Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
add support for mapzen terrarium
Browse files Browse the repository at this point in the history
  • Loading branch information
Molly Lloyd committed Feb 8, 2018
1 parent 4498917 commit 0bbd54c
Show file tree
Hide file tree
Showing 14 changed files with 57 additions and 29 deletions.
9 changes: 7 additions & 2 deletions include/mbgl/util/tileset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,27 @@ namespace mbgl {
class Tileset {
public:
enum class Scheme : bool { XYZ, TMS };
enum class Encoding : bool { Mapbox, Terrarium };

std::vector<std::string> tiles;
Range<uint8_t> zoomRange;
std::string attribution;
Scheme scheme;
Encoding encoding;
optional<LatLngBounds> bounds;


Tileset(std::vector<std::string> tiles_ = std::vector<std::string>(),
Range<uint8_t> zoomRange_ = { 0, util::DEFAULT_MAX_ZOOM },
std::string attribution_ = {},
Scheme scheme_ = Scheme::XYZ)
Scheme scheme_ = Scheme::XYZ,
Encoding encoding_ = Encoding::Mapbox)
: tiles(std::move(tiles_)),
zoomRange(std::move(zoomRange_)),
attribution(std::move(attribution_)),
scheme(scheme_),
bounds() {}
encoding(encoding_),
bounds() {};

// TileJSON also includes center and zoom but they are not used by mbgl.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import com.mapbox.mapboxsdk.style.layers.TransitionOptions;

/**
* Client-side hillshading visualization based on DEM data. Currently, the implementation only supports Mapbox Terrain RGB tiles
* Client-side hillshading visualization based on DEM data. Currently, the implementation only supports Mapbox Terrain RGB and Mapzen Terrarium tiles.
*
* @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layers-hillshade">The online documentation</a>
*/
Expand Down
13 changes: 11 additions & 2 deletions src/mbgl/geometry/dem_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace mbgl {

DEMData::DEMData(const PremultipliedImage& _image):
DEMData::DEMData(const PremultipliedImage& _image, Tileset::Encoding encoding):
dim(_image.size.height),
border(std::max<int32_t>(std::ceil(_image.size.height / 2), 1)),
stride(dim + 2 * border),
Expand All @@ -13,13 +13,22 @@ DEMData::DEMData(const PremultipliedImage& _image):
throw std::runtime_error("raster-dem tiles must be square.");
}

auto decodeRGB = [&] (const uint8_t r, const uint8_t g, const uint8_t b) {
if (encoding == Tileset::Encoding::Mapbox) {
return (r * 256 * 256 + g * 256 + b)/10 - 10000;
} else {
// encoding == Tileset::Encoding::Terrarium;
return ((r * 256 + g + b / 256) - 32768);
}
};

std::memset(image.data.get(), 0, image.bytes());

for (int32_t y = 0; y < dim; y++) {
for (int32_t x = 0; x < dim; x++) {
const int32_t i = y * dim + x;
const int32_t j = i * 4;
set(x, y, (_image.data[j] * 256 * 256 + _image.data[j+1] * 256 + _image.data[j+2])/10 - 10000);
set(x, y, decodeRGB(_image.data[j], _image.data[j+1], _image.data[j+2]));
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/mbgl/geometry/dem_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <mbgl/math/clamp.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/tileset.hpp>

#include <memory>
#include <array>
Expand All @@ -12,7 +13,7 @@ namespace mbgl {

class DEMData {
public:
DEMData(const PremultipliedImage& image);
DEMData(const PremultipliedImage& image, Tileset::Encoding encoding);
void backfillBorder(const DEMData& borderTileData, int8_t dx, int8_t dy);

void set(const int32_t x, const int32_t y, const int32_t value) {
Expand Down
2 changes: 1 addition & 1 deletion src/mbgl/renderer/buckets/hillshade_bucket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace mbgl {

using namespace style;

HillshadeBucket::HillshadeBucket(PremultipliedImage&& image_): demdata(image_) {
HillshadeBucket::HillshadeBucket(PremultipliedImage&& image_, Tileset::Encoding encoding): demdata(image_, encoding) {
}

HillshadeBucket::HillshadeBucket(DEMData&& demdata_) : demdata(std::move(demdata_)) {
Expand Down
5 changes: 3 additions & 2 deletions src/mbgl/renderer/buckets/hillshade_bucket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/renderer/tile_mask.hpp>
#include <mbgl/geometry/dem_data.hpp>
#include <mbgl/util/tileset.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/mat4.hpp>
#include <mbgl/util/optional.hpp>
Expand All @@ -16,8 +17,8 @@ namespace mbgl {

class HillshadeBucket : public Bucket {
public:
HillshadeBucket(PremultipliedImage&&);
HillshadeBucket(std::shared_ptr<PremultipliedImage>);
HillshadeBucket(PremultipliedImage&&, Tileset::Encoding encoding);
HillshadeBucket(std::shared_ptr<PremultipliedImage>, Tileset::Encoding encoding);
HillshadeBucket(DEMData&&);


Expand Down
8 changes: 8 additions & 0 deletions src/mbgl/style/conversion/tileset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ optional<Tileset> Converter<Tileset>::operator()(const Convertible& value, Error
}
}

auto encodingValue = objectMember(value, "encoding");
if (encodingValue) {
optional<std::string> encoding = toString(*encodingValue);
if (encoding && *encoding == "terrarium") {
result.encoding = Tileset::Encoding::Terrarium;
}
}

auto minzoomValue = objectMember(value, "minzoom");
if (minzoomValue) {
optional<float> minzoom = toNumber(*minzoomValue);
Expand Down
3 changes: 2 additions & 1 deletion src/mbgl/tile/raster_dem_tile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ RasterDEMTile::RasterDEMTile(const OverscaledTileID& id_,
worker(parameters.workerScheduler,
ActorRef<RasterDEMTile>(*this, mailbox)) {

encoding = tileset.encoding;
if ( id.canonical.y == 0 ){
// this tile doesn't have upper neighboring tiles so marked those as backfilled
neighboringTiles = neighboringTiles | DEMTileNeighbors::NoUpper;
Expand All @@ -47,7 +48,7 @@ void RasterDEMTile::setMetadata(optional<Timestamp> modified_, optional<Timestam
void RasterDEMTile::setData(std::shared_ptr<const std::string> data) {
pending = true;
++correlationID;
worker.invoke(&RasterDEMTileWorker::parse, data, correlationID);
worker.invoke(&RasterDEMTileWorker::parse, data, correlationID, encoding);
}

void RasterDEMTile::onParsed(std::unique_ptr<HillshadeBucket> result, const uint64_t resultCorrelationID) {
Expand Down
1 change: 1 addition & 0 deletions src/mbgl/tile/raster_dem_tile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class RasterDEMTile : public Tile {
Actor<RasterDEMTileWorker> worker;

uint64_t correlationID = 0;
Tileset::Encoding encoding;

// Contains the Bucket object for the tile. Buckets are render
// objects and they get added by tile parsing operations.
Expand Down
4 changes: 2 additions & 2 deletions src/mbgl/tile/raster_dem_tile_worker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ RasterDEMTileWorker::RasterDEMTileWorker(ActorRef<RasterDEMTileWorker>, ActorRef
: parent(std::move(parent_)) {
}

void RasterDEMTileWorker::parse(std::shared_ptr<const std::string> data, uint64_t correlationID) {
void RasterDEMTileWorker::parse(std::shared_ptr<const std::string> data, uint64_t correlationID, Tileset::Encoding encoding) {
if (!data) {
parent.invoke(&RasterDEMTile::onParsed, nullptr, correlationID); // No data; empty tile.
return;
}

try {
auto bucket = std::make_unique<HillshadeBucket>(decodeImage(*data));
auto bucket = std::make_unique<HillshadeBucket>(decodeImage(*data), encoding);
parent.invoke(&RasterDEMTile::onParsed, std::move(bucket), correlationID);
} catch (...) {
parent.invoke(&RasterDEMTile::onError, std::current_exception(), correlationID);
Expand Down
3 changes: 2 additions & 1 deletion src/mbgl/tile/raster_dem_tile_worker.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <mbgl/actor/actor_ref.hpp>
#include <mbgl/util/tileset.hpp>

#include <memory>
#include <string>
Expand All @@ -13,7 +14,7 @@ class RasterDEMTileWorker {
public:
RasterDEMTileWorker(ActorRef<RasterDEMTileWorker>, ActorRef<RasterDEMTile>);

void parse(std::shared_ptr<const std::string> data, uint64_t correlationID);
void parse(std::shared_ptr<const std::string> data, uint64_t correlationID, Tileset::Encoding encoding);

private:
ActorRef<RasterDEMTile> parent;
Expand Down
29 changes: 15 additions & 14 deletions test/geometry/dem_data.test.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <mbgl/test/util.hpp>

#include <mbgl/util/image.hpp>
#include <mbgl/util/tileset.hpp>
#include <mbgl/geometry/dem_data.hpp>

using namespace mbgl;
Expand All @@ -16,28 +17,28 @@ auto fakeImage = [](Size s) {

TEST(DEMData, Constructor) {
PremultipliedImage image = fakeImage({16, 16});
DEMData pyramid(image);

EXPECT_EQ(pyramid.dim, 16);
EXPECT_EQ(pyramid.border, 8);
EXPECT_EQ(pyramid.stride, 32);
EXPECT_EQ(pyramid.getImage()->bytes(), size_t(32*32*4));
EXPECT_EQ(pyramid.dim, 16);
EXPECT_EQ(pyramid.border, 8);
DEMData demdata(image, Tileset::Encoding::Mapbox);

EXPECT_EQ(demdata.dim, 16);
EXPECT_EQ(demdata.border, 8);
EXPECT_EQ(demdata.stride, 32);
EXPECT_EQ(demdata.getImage()->bytes(), size_t(32*32*4));
EXPECT_EQ(demdata.dim, 16);
EXPECT_EQ(demdata.border, 8);
};

TEST(DEMData, RoundTrip) {
PremultipliedImage image = fakeImage({16, 16});
DEMData pyramid(image);
DEMData demdata(image, Tileset::Encoding::Mapbox);

pyramid.set(4, 6, 255);
EXPECT_EQ(pyramid.get(4, 6), 255);
demdata.set(4, 6, 255);
EXPECT_EQ(demdata.get(4, 6), 255);
}

TEST(DEMData, InitialBackfill) {

PremultipliedImage image1 = fakeImage({4, 4});
DEMData dem1(image1);
DEMData dem1(image1, Tileset::Encoding::Mapbox);

bool nonempty = true;
// checking that a 1 px border around the fake image has been populated
Expand Down Expand Up @@ -91,10 +92,10 @@ TEST(DEMData, InitialBackfill) {

TEST(DEMData, BackfillNeighbor) {
PremultipliedImage image1 = fakeImage({4, 4});
DEMData dem0(image1);
DEMData dem0(image1, Tileset::Encoding::Mapbox);

PremultipliedImage image2 = fakeImage({4, 4});
DEMData dem1(image2);
DEMData dem1(image2, Tileset::Encoding::Mapbox);

dem0.backfillBorder(dem1, -1, 0);
for (int y = 0; y < 4; y++) {
Expand Down
2 changes: 1 addition & 1 deletion test/tile/raster_dem_tile.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ TEST(RasterDEMTile, onError) {
TEST(RasterDEMTile, onParsed) {
RasterDEMTileTest test;
RasterDEMTile tile(OverscaledTileID(0, 0, 0), test.tileParameters, test.tileset);
tile.onParsed(std::make_unique<HillshadeBucket>(PremultipliedImage({16, 16})), 0);
tile.onParsed(std::make_unique<HillshadeBucket>(PremultipliedImage({16, 16}), Tileset::Encoding::Mapbox), 0);
EXPECT_TRUE(tile.isRenderable());
EXPECT_TRUE(tile.isLoaded());
EXPECT_TRUE(tile.isComplete());
Expand Down

0 comments on commit 0bbd54c

Please sign in to comment.