Add support for parsing MLT-format vector tile sources (#3246)

Co-authored-by: Bart Louwers <bart@emeel.net>
Co-authored-by: Bart Louwers <bart.louwers@gmail.com>
This commit is contained in:
Tim Sylvester
2025-10-31 17:24:12 -07:00
committed by GitHub
parent 4c31a52a3c
commit 29428dce42
92 changed files with 1134 additions and 286 deletions

4
.gitmodules vendored
View File

@@ -100,6 +100,10 @@
[submodule "vendor/filesystem"]
path = vendor/filesystem
url = https://github.com/gulrak/filesystem.git
[submodule "vendor/maplibre-tile-spec"]
path = vendor/maplibre-tile-spec
url = https://github.com/maplibre/maplibre-tile-spec.git
branch = cpp
[submodule "vendor/kdbush.hpp"]
path = vendor/kdbush.hpp
url = https://github.com/mourner/kdbush.hpp.git

View File

@@ -144,6 +144,7 @@ cc_library(
"//vendor:eternal",
"//vendor:expected-lite",
"//vendor:maplibre-native-base",
"//vendor/maplibre-tile-spec/cpp:mlt_cpp",
"//vendor:parsedate",
"//vendor:pmtiles",
"//vendor:polylabel",

View File

@@ -302,9 +302,9 @@ list(APPEND INCLUDE_FILES
${PROJECT_SOURCE_DIR}/include/mbgl/style/conversion/light.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/style/conversion/position.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/style/conversion/property_value.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/style/conversion/raster_dem_options.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/style/conversion/rotation.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/style/conversion/source.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/style/conversion/source_options.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/style/conversion/tileset.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/style/conversion/transition_options.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/style/expression/assertion.hpp
@@ -676,9 +676,9 @@ list(APPEND SRC_FILES
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/light.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/position.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/property_value.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/raster_dem_options.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/rotation.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/source.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/source_options.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/stringify.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/tileset.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/transition_options.cpp
@@ -879,10 +879,15 @@ list(APPEND SRC_FILES
${PROJECT_SOURCE_DIR}/src/mbgl/tile/tile_operation.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/tile/vector_tile.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/tile/vector_tile.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/tile/vector_tile_data.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/tile/vector_tile_data.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/tile/vector_mlt_tile.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/tile/vector_mlt_tile.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/tile/vector_mlt_tile_data.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/tile/vector_mlt_tile_data.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/tile/vector_mvt_tile.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/tile/vector_mvt_tile.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/tile/vector_mvt_tile_data.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/tile/vector_mvt_tile_data.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/util/action_journal.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/util/action_journal_impl.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/util/action_journal_impl.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/util/camera.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/util/bounding_volumes.hpp
@@ -1553,6 +1558,7 @@ include(${PROJECT_SOURCE_DIR}/vendor/unordered_dense.cmake)
include(${PROJECT_SOURCE_DIR}/vendor/vector-tile.cmake)
include(${PROJECT_SOURCE_DIR}/vendor/wagyu.cmake)
include(${PROJECT_SOURCE_DIR}/vendor/metal-cpp.cmake)
include(${PROJECT_SOURCE_DIR}/vendor/maplibre-tile-spec.cmake)
include(${PROJECT_SOURCE_DIR}/vendor/supercluster.cmake)
include(${PROJECT_SOURCE_DIR}/vendor/expected-lite.cmake)
include(${PROJECT_SOURCE_DIR}/vendor/kdbush.cmake)
@@ -1581,6 +1587,7 @@ target_link_libraries(
mbgl-vendor-unique_resource
mbgl-vendor-vector-tile
mbgl-vendor-wagyu
mlt-cpp
$<$<BOOL:${MLN_WITH_METAL}>:mbgl-vendor-metal-cpp>
$<IF:$<BOOL:${MLN_USE_RUST}>,mbgl-rustutils,mbgl-vendor-csscolorparser>
$<$<BOOL:${MLN_TEXT_SHAPING_HARFBUZZ}>:mbgl-freetype>
@@ -1614,6 +1621,8 @@ set(EXPORT_TARGETS
mbgl-vendor-boost
mbgl-vendor-earcut.hpp
mbgl-vendor-eternal
mbgl-vendor-filesystem
mbgl-vendor-metal-cpp
mbgl-vendor-rapidjson
mbgl-vendor-parsedate
mbgl-vendor-pmtiles
@@ -1622,8 +1631,7 @@ set(EXPORT_TARGETS
mbgl-vendor-unique_resource
mbgl-vendor-vector-tile
mbgl-vendor-wagyu
mbgl-vendor-metal-cpp
mbgl-vendor-filesystem
mlt-cpp
unordered_dense
)

View File

@@ -336,9 +336,9 @@ MLN_CORE_SOURCE = [
"src/mbgl/style/conversion/light.cpp",
"src/mbgl/style/conversion/position.cpp",
"src/mbgl/style/conversion/property_value.cpp",
"src/mbgl/style/conversion/raster_dem_options.cpp",
"src/mbgl/style/conversion/rotation.cpp",
"src/mbgl/style/conversion/source.cpp",
"src/mbgl/style/conversion/source_options.cpp",
"src/mbgl/style/conversion/stringify.hpp",
"src/mbgl/style/conversion/tileset.cpp",
"src/mbgl/style/conversion/transition_options.cpp",
@@ -514,8 +514,14 @@ MLN_CORE_SOURCE = [
"src/mbgl/tile/tile_operation.cpp",
"src/mbgl/tile/vector_tile.cpp",
"src/mbgl/tile/vector_tile.hpp",
"src/mbgl/tile/vector_tile_data.cpp",
"src/mbgl/tile/vector_tile_data.hpp",
"src/mbgl/tile/vector_mlt_tile.cpp",
"src/mbgl/tile/vector_mlt_tile.hpp",
"src/mbgl/tile/vector_mlt_tile_data.cpp",
"src/mbgl/tile/vector_mlt_tile_data.hpp",
"src/mbgl/tile/vector_mvt_tile.cpp",
"src/mbgl/tile/vector_mvt_tile.hpp",
"src/mbgl/tile/vector_mvt_tile_data.cpp",
"src/mbgl/tile/vector_mvt_tile_data.hpp",
"src/mbgl/util/action_journal.cpp",
"src/mbgl/util/action_journal_impl.hpp",
"src/mbgl/util/action_journal_impl.cpp",
@@ -696,9 +702,9 @@ MLN_CORE_HEADERS = [
"include/mbgl/style/conversion/light.hpp",
"include/mbgl/style/conversion/position.hpp",
"include/mbgl/style/conversion/property_value.hpp",
"include/mbgl/style/conversion/raster_dem_options.hpp",
"include/mbgl/style/conversion/rotation.hpp",
"include/mbgl/style/conversion/source.hpp",
"include/mbgl/style/conversion/source_options.hpp",
"include/mbgl/style/conversion/tileset.hpp",
"include/mbgl/style/conversion/transition_options.hpp",
"include/mbgl/style/conversion_impl.hpp",

View File

@@ -1,6 +1,6 @@
#include <benchmark/benchmark.h>
#include <mbgl/tile/vector_tile_data.hpp>
#include <mbgl/tile/vector_mvt_tile_data.hpp>
#include <mbgl/util/io.hpp>
using namespace mbgl;
@@ -11,7 +11,7 @@ static void Parse_VectorTile(benchmark::State& state) {
while (state.KeepRunning()) {
std::size_t length = 0;
VectorTileData tile(data);
VectorMVTTileData tile(data);
for (const auto& name : tile.layerNames()) {
if (auto layer = tile.getLayer(name)) {
const std::size_t count = layer->featureCount();

View File

@@ -7,14 +7,13 @@
#include <args.hxx>
#include <mapbox/io/io.hpp>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
int main(int argc, char* argv[]) {
args::ArgumentParser p("Mapbox GL cache tool", "");
args::ArgumentParser p("MapLibre cache tool", "");
args::HelpFlag helpFlag(p, "help", "Display this help menu", {'h'});
args::ValueFlag<std::string> urlValue(p, "URL", "Resource URL (required)", {'u'}, args::Options::Required);
@@ -35,7 +34,7 @@ int main(int argc, char* argv[]) {
{"tile", mbgl::Resource::Tile}};
std::string typeHelp("One of the following (required):");
for (auto key : typeMap) {
for (const auto& key : typeMap) {
typeHelp += " " + key.first;
}
@@ -53,18 +52,18 @@ int main(int argc, char* argv[]) {
std::cout << p;
exit(0);
} catch (const args::ParseError& e) {
std::cerr << e.what() << std::endl;
std::cerr << e.what() << '\n';
std::cerr << p;
exit(1);
} catch (const args::ValidationError& e) {
std::cerr << e.what() << std::endl;
std::cerr << e.what() << '\n';
std::cerr << p;
exit(2);
}
auto file = mapbox::base::io::readFile(args::get(dataValue));
if (!file) {
std::cerr << file.error() << std::endl;
std::cerr << file.error() << '\n';
exit(3);
}
@@ -78,15 +77,15 @@ int main(int argc, char* argv[]) {
if (args::get(typeFlag) == mbgl::Resource::Tile) {
if (!xValueFlag || !yValueFlag || !zValueFlag) {
std::cerr << "Error: -x, -y and -z must be provided for tiles" << std::endl;
std::cerr << "Error: -x, -y and -z must be provided for tiles" << '\n';
exit(1);
}
resource.tileData = {{args::get(urlValue),
1,
args::get(xValueFlag),
args::get(yValueFlag),
static_cast<int8_t>(args::get(zValueFlag))}};
resource.tileData = {{.urlTemplate = args::get(urlValue),
.pixelRatio = 1,
.x = args::get(xValueFlag),
.y = args::get(yValueFlag),
.z = static_cast<int8_t>(args::get(zValueFlag))}};
}
mbgl::util::RunLoop loop;

View File

@@ -8,8 +8,8 @@ namespace style {
namespace conversion {
template <>
struct Converter<RasterDEMOptions> {
std::optional<RasterDEMOptions> operator()(const Convertible& value, Error& error) const;
struct Converter<SourceOptions> {
std::optional<SourceOptions> operator()(const Convertible& value, Error& error) const;
};
} // namespace conversion

View File

@@ -7,8 +7,9 @@
namespace mbgl {
namespace style {
struct RasterDEMOptions {
std::optional<Tileset::DEMEncoding> encoding = std::nullopt;
struct SourceOptions {
std::optional<Tileset::RasterEncoding> rasterEncoding = std::nullopt;
std::optional<Tileset::VectorEncoding> vectorEncoding = std::nullopt;
};
// NOTE: Any derived class must invalidate `weakFactory` in the destructor
@@ -17,7 +18,7 @@ public:
RasterDEMSource(std::string id,
variant<std::string, Tileset> urlOrTileset,
uint16_t tileSize,
std::optional<RasterDEMOptions> options = std::nullopt);
std::optional<SourceOptions> options = std::nullopt);
~RasterDEMSource() override;
bool supportsLayerType(const mbgl::style::LayerTypeInfo*) const override;
@@ -25,7 +26,7 @@ protected:
void setTilesetOverrides(Tileset& tileset) override;
private:
std::optional<RasterDEMOptions> options;
std::optional<SourceOptions> options;
};
template <>

View File

@@ -16,7 +16,8 @@ public:
VectorSource(std::string id,
variant<std::string, Tileset> urlOrTileset,
std::optional<float> maxZoom = std::nullopt,
std::optional<float> minZoom = std::nullopt);
std::optional<float> minZoom = std::nullopt,
Tileset::VectorEncoding encoding = Tileset::VectorEncoding::Mapbox);
void setTilesetOverrides(Tileset& tileset) override;
@@ -30,11 +31,14 @@ public:
bool supportsLayerType(const mbgl::style::LayerTypeInfo*) const override;
Tileset::VectorEncoding getEncoding() const noexcept { return encoding; }
mapbox::base::WeakPtr<Source> makeWeakPtr() override { return weakFactory.makeWeakPtr(); }
private:
std::optional<float> maxZoom;
std::optional<float> minZoom;
Tileset::VectorEncoding encoding;
mapbox::base::WeakPtrFactory<Source> weakFactory{this}; // Must remain last
};

View File

@@ -18,38 +18,40 @@ public:
XYZ,
TMS
};
enum class DEMEncoding : bool {
Mapbox,
Terrarium
enum class RasterEncoding : std::uint8_t {
Mapbox, // Mapbox DEM
Terrarium, // Terrarium DEM
};
enum class VectorEncoding : std::uint8_t {
Mapbox, // Mapbox Vector Tiles (MVT)
MLT, // MapLibre Tiles
};
std::vector<std::string> tiles;
Range<uint8_t> zoomRange;
std::string attribution;
Scheme scheme;
// DEMEncoding is not supported by the TileJSON spec
DEMEncoding encoding;
std::optional<RasterEncoding> rasterEncoding;
std::optional<VectorEncoding> vectorEncoding;
std::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,
DEMEncoding encoding_ = DEMEncoding::Mapbox)
std::optional<RasterEncoding> rasterEncoding_ = std::nullopt,
std::optional<VectorEncoding> encoding_ = std::nullopt)
: tiles(std::move(tiles_)),
zoomRange(zoomRange_),
attribution(std::move(attribution_)),
scheme(scheme_),
encoding(encoding_) {};
rasterEncoding(rasterEncoding_),
vectorEncoding(encoding_) {}
// TileJSON also includes center and zoom but they are not used by mbgl.
friend bool operator==(const Tileset& lhs, const Tileset& rhs) noexcept {
return std::tie(lhs.tiles, lhs.zoomRange, lhs.attribution, lhs.scheme, lhs.bounds) ==
std::tie(rhs.tiles, rhs.zoomRange, rhs.attribution, rhs.scheme, rhs.bounds);
}
friend bool operator!=(const Tileset& lhs, const Tileset& rhs) noexcept { return !(lhs == rhs); }
bool operator==(const Tileset&) const = default;
bool operator!=(const Tileset&) const = default;
};
} // namespace mbgl

Binary file not shown.

View File

@@ -2,7 +2,13 @@
"version": 8,
"metadata": {
"test": {
"allowed": 0.003
"allowed": 0.003,
"source-replace": [
{
"replace": "maplibre",
"with": "mlt"
}
]
}
},
"center": [
@@ -19,6 +25,14 @@
"tiles": [
"local://tiles/extent1024-14-8802-5374.mvt"
]
},
"mlt": {
"type": "vector",
"maxzoom": 14,
"tiles": [
"local://tiles/extent1024-14-8802-5374.mlt"
],
"encoding": "mlt"
}
},
"layers": [

View File

@@ -1,7 +1,14 @@
{
"version": 8,
"metadata": {
"test": {}
"test": {
"source-replace": [
{
"replace": "maplibre",
"with": "mlt"
}
]
}
},
"zoom": 0.99,
"center": [
@@ -15,6 +22,14 @@
"tiles": [
"local://tiles/{z}-{x}-{y}.mvt"
]
},
"mlt": {
"type": "vector",
"maxzoom": 14,
"tiles": [
"local://tiles/{z}-{x}-{y}.mlt"
],
"encoding": "mlt"
}
},
"sprite": "local://sprites/solid-black",

View File

@@ -2,7 +2,11 @@
"version": 8,
"metadata": {
"test": {
"height": 256
"height": 256,
"source-replace": [{
"replace": "maplibre",
"with": "mlt"
}]
}
},
"center": [
@@ -17,6 +21,14 @@
"tiles": [
"local://tiles/{z}-{x}-{y}.mvt"
]
},
"mlt": {
"type": "vector",
"maxzoom": 14,
"tiles": [
"local://tiles/{z}-{x}-{y}.mlt"
],
"encoding": "mlt"
}
},
"sprite": "local://sprites/sprite",

View File

@@ -1,5 +1,15 @@
{
"version": 8,
"metadata": {
"test": {
"source-replace": [
{
"replace": "maplibre",
"with": "mlt"
}
]
}
},
"center": [
-118.28162,
33.86852
@@ -14,6 +24,14 @@
"tiles": [
"local://tiles/mapbox.mapbox-streets-v7/16-11235-26208.mvt"
]
},
"mlt": {
"type": "vector",
"maxzoom": 16,
"tiles": [
"local://tiles/mapbox.mapbox-streets-v7/16-11235-26208.mlt"
],
"encoding": "mlt"
}
},
"glyphs": "local://glyphs/{fontstack}/{range}.pbf",

View File

@@ -1,7 +1,14 @@
{
"version": 8,
"metadata": {
"test": {}
"test": {
"source-replace": [
{
"replace": "maplibre",
"with": "mlt"
}
]
}
},
"zoom": 2,
"sources": {
@@ -12,6 +19,15 @@
"tiles": [
"local://tiles/{z}-{x}-{y}.tms.mvt"
]
},
"mlt": {
"type": "vector",
"maxzoom": 14,
"scheme": "tms",
"tiles": [
"local://tiles/{z}-{x}-{y}.tms.mlt"
],
"encoding": "mlt"
}
},
"layers": [

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -10,11 +10,30 @@
The default value for this option is ``MLNDEMEncoding/MLNDEMEncodingMapbox``.
This option cannot be represented in a TileJSON or style JSON file. It is used
with the ``MLNRasterDEMSource`` class and is ignored when creating an
with the ``MLNRasterDEMSource`` class and is ignored when creating a
``MLNRasterTileSource`` or ``MLNRasterTileSource`` object.
*/
FOUNDATION_EXTERN MLN_EXPORT const MLNTileSourceOption MLNTileSourceOptionDEMEncoding;
/**
The encoding formula used to generate the raster tileset
*/
typedef NS_ENUM(NSUInteger, MLNDEMEncoding) {
/**
Raster tiles generated with the [Mapbox encoding
formula](https://docs.mapbox.com/help/troubleshooting/access-elevation-data/#mapbox-terrain-rgb)
*/
MLNDEMEncodingMapbox = 0,
/**
Raster tiles generated with the [Mapzen Terrarium encoding
formula](https://aws.amazon.com/public-datasets/terrain/).
*/
MLNDEMEncodingTerrarium = 1,
};
/**
``MLNRasterDEMSource`` is a map content source that supplies rasterized
<a href="https://en.wikipedia.org/wiki/Digital_elevation_model">digital elevation model</a>

View File

@@ -5,6 +5,8 @@
#import <mbgl/style/sources/raster_dem_source.hpp>
const MLNTileSourceOption MLNTileSourceOptionDEMEncoding = @"MLNTileSourceOptionDEMEncoding";
@implementation MLNRasterDEMSource
- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier urlOrTileset:(mbgl::variant<std::string, mbgl::Tileset>)urlOrTileset tileSize:(uint16_t)tileSize {

View File

@@ -142,25 +142,6 @@ typedef NS_ENUM(NSUInteger, MLNTileCoordinateSystem) {
MLNTileCoordinateSystemTMS
};
/**
The encoding formula used to generate the raster-dem tileset
*/
typedef NS_ENUM(NSUInteger, MLNDEMEncoding) {
/**
Raster tiles generated with the [Mapbox encoding
formula](https://docs.mapbox.com/help/troubleshooting/access-elevation-data/#mapbox-terrain-rgb).
*/
MLNDEMEncodingMapbox = 0,
/**
Raster tiles generated with the [Mapzen Terrarium encoding
formula](https://aws.amazon.com/public-datasets/terrain/).
*/
MLNDEMEncodingTerrarium
};
/**
``MLNTileSource`` is a map content source that supplies map tiles to be shown on
the map. The location of and metadata about the tiles are defined either by an

View File

@@ -3,6 +3,7 @@
#import "MLNAttributionInfo_Private.h"
#import "MLNGeometry_Private.h"
#import "MLNRasterDEMSource.h"
#import "MLNVectorTileSource.h"
#import "NSString+MLNAdditions.h"
#import "NSValue+MLNAdditions.h"
@@ -20,7 +21,6 @@ const MLNTileSourceOption MLNTileSourceOptionCoordinateBounds = @"MLNTileSourceO
const MLNTileSourceOption MLNTileSourceOptionAttributionHTMLString = @"MLNTileSourceOptionAttributionHTMLString";
const MLNTileSourceOption MLNTileSourceOptionAttributionInfos = @"MLNTileSourceOptionAttributionInfos";
const MLNTileSourceOption MLNTileSourceOptionTileCoordinateSystem = @"MLNTileSourceOptionTileCoordinateSystem";
const MLNTileSourceOption MLNTileSourceOptionDEMEncoding = @"MLNTileSourceOptionDEMEncoding";
@implementation MLNTileSource
@@ -131,19 +131,38 @@ mbgl::Tileset MLNTileSetFromTileURLTemplates(NSArray<NSString *> *tileURLTemplat
}
}
if (NSNumber *demEncodingNumber = options[MLNTileSourceOptionDEMEncoding]) {
if (![demEncodingNumber isKindOfClass:[NSValue class]]) {
NSNumber *encodingNumber = options[MLNTileSourceOptionDEMEncoding];
if (encodingNumber) {
if (![encodingNumber isKindOfClass:[NSValue class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MLNTileSourceOptionDEMEncoding must be set to an NSValue or NSNumber."];
}
MLNDEMEncoding demEncoding;
[demEncodingNumber getValue:&demEncoding];
switch (demEncoding) {
MLNDEMEncoding encoding;
[encodingNumber getValue:&encoding];
switch (encoding) {
case MLNDEMEncodingMapbox:
tileSet.encoding = mbgl::Tileset::DEMEncoding::Mapbox;
tileSet.rasterEncoding = mbgl::Tileset::RasterEncoding::Mapbox;
break;
case MLNDEMEncodingTerrarium:
tileSet.encoding = mbgl::Tileset::DEMEncoding::Terrarium;
tileSet.rasterEncoding = mbgl::Tileset::RasterEncoding::Terrarium;
break;
}
}
encodingNumber = options[MLNVectorTileSourceOptionEncoding];
if (encodingNumber) {
if (![encodingNumber isKindOfClass:[NSValue class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MLNTileSourceOptionVectorEncoding must be set to an NSValue or NSNumber."];
}
MLNVectorTileSourceEncoding encoding;
[encodingNumber getValue:&encoding];
switch (encoding) {
case MLNVectorTileSourceEncodingMapbox:
tileSet.vectorEncoding = mbgl::Tileset::VectorEncoding::Mapbox;
break;
case MLNVectorTileSourceEncodingMLT:
tileSet.vectorEncoding = mbgl::Tileset::VectorEncoding::MLT;
break;
}
}

View File

@@ -4,6 +4,33 @@
NS_ASSUME_NONNULL_BEGIN
/**
An `NSNumber` object containing an unsigned integer that specifies the encoding
formula for vector tilesets. The integer corresponds to one of the constants in
``MLNVectorTileSourceEncoding``.
The default value for this option is
``MLNVectorTileSourceEncoding/MLNVectorTileSourceEncodingMapbox``.
*/
FOUNDATION_EXTERN MLN_EXPORT const MLNTileSourceOption MLNVectorTileSourceOptionEncoding;
/**
The encoding formula used to generate the raster-dem tileset
*/
typedef NS_ENUM(NSUInteger, MLNVectorTileSourceEncoding) {
/**
Vector tiles in [MVT format](https://github.com/mapbox/vector-tile-spec).
*/
MLNVectorTileSourceEncodingMapbox = 0,
/**
Vector tiles in [MLT format](https://github.com/maplibre/maplibre-tile-spec).
*/
MLNVectorTileSourceEncodingMLT = 1,
};
/**
``MLNVectorTileSource`` is a map content source that supplies tiled vector data
in <a href="https://www.mapbox.com/vector-tiles/">Mapbox Vector Tile</a> format

View File

@@ -14,6 +14,8 @@
#include <mbgl/style/sources/vector_source.hpp>
#include <mbgl/renderer/renderer.hpp>
const MLNTileSourceOption MLNVectorTileSourceOptionEncoding = @"MLNVectorTileSourceOptionEncoding";
@interface MLNVectorTileSource ()
@property (nonatomic, readonly) mbgl::style::VectorSource *rawSource;

View File

@@ -1,6 +1,7 @@
#import <XCTest/XCTest.h>
#import <Mapbox.h>
#import "MLNVectorTileSource.h"
#import "MLNTileSource_Private.h"
#import "MLNGeometry_Private.h"
@@ -12,9 +13,13 @@
@implementation MLNTileSetTests
- (void)testTileSetFromTileURLTemplates {
namespace {
// a tile set that provides an mbgl tile set
NSArray *tileURLTemplates = @[@"tile.1", @"tile.2", @"tile.3"];
}
- (void)testTileSetFromTileURLTemplates {
mbgl::Tileset tileSet = MLNTileSetFromTileURLTemplates(tileURLTemplates, nil);
// has the correct URL templates
@@ -120,23 +125,61 @@
// the scheme is reflected by the mbgl tileset
XCTAssertEqual(tileSet.scheme, mbgl::Tileset::Scheme::TMS);
}
// when the dem encoding is changed using an NSNumber
- (void)testTileSetFromTileURLTemplatesRasterEncodings {
mbgl::Tileset tileSet;
// when the DEM encoding is changed using an NSNumber
tileSet = MLNTileSetFromTileURLTemplates(tileURLTemplates, @{
MLNTileSourceOptionDEMEncoding: @(MLNDEMEncodingTerrarium),
});
// the encoding is reflected by the mbgl tileset
XCTAssertEqual(tileSet.encoding, mbgl::Tileset::DEMEncoding::Terrarium);
XCTAssertEqual(tileSet.rasterEncoding, mbgl::Tileset::RasterEncoding::Terrarium);
XCTAssertFalse(tileSet.vectorEncoding);
// when the dem encoding is changed using an NSValue
// when the raster encoding is changed using an NSValue
MLNDEMEncoding terrarium = MLNDEMEncodingTerrarium;
tileSet = MLNTileSetFromTileURLTemplates(tileURLTemplates, @{
MLNTileSourceOptionDEMEncoding: [NSValue value:&terrarium withObjCType:@encode(MLNDEMEncoding)],
});
// the encoding is reflected by the mbgl tileset
XCTAssertEqual(tileSet.encoding, mbgl::Tileset::DEMEncoding::Terrarium);
XCTAssertEqual(tileSet.rasterEncoding, mbgl::Tileset::RasterEncoding::Terrarium);
XCTAssertFalse(tileSet.vectorEncoding);
}
- (void)testTileSetFromTileURLTemplatesVectorEncodings {
mbgl::Tileset tileSet;
// when the raster encoding is changed using an NSNumber
tileSet = MLNTileSetFromTileURLTemplates(tileURLTemplates, @{
MLNVectorTileSourceOptionEncoding: @(MLNVectorTileSourceEncodingMapbox),
});
// the encoding is reflected by the mbgl tileset
XCTAssertEqual(tileSet.vectorEncoding, mbgl::Tileset::VectorEncoding::Mapbox);
XCTAssertFalse(tileSet.rasterEncoding);
// when the raster encoding is changed using an NSNumber
tileSet = MLNTileSetFromTileURLTemplates(tileURLTemplates, @{
MLNVectorTileSourceOptionEncoding: @(MLNVectorTileSourceEncodingMLT),
});
// the encoding is reflected by the mbgl tileset
XCTAssertEqual(tileSet.vectorEncoding, mbgl::Tileset::VectorEncoding::MLT);
XCTAssertFalse(tileSet.rasterEncoding);
// when the raster encoding is changed using an NSValue
MLNVectorTileSourceEncoding mlt = MLNVectorTileSourceEncodingMLT;
tileSet = MLNTileSetFromTileURLTemplates(tileURLTemplates, @{
MLNVectorTileSourceOptionEncoding: [NSValue value:&mlt withObjCType:@encode(MLNVectorTileSourceEncoding)],
});
// the encoding is reflected by the mbgl tileset
XCTAssertEqual(tileSet.vectorEncoding, mbgl::Tileset::VectorEncoding::MLT);
XCTAssertFalse(tileSet.rasterEncoding);
}
- (void)testInvalidTileSet {

View File

@@ -105,6 +105,11 @@ public:
const auto format_ptr = values.find("format");
const std::string format = (format_ptr == values.end()) ? "png" : format_ptr->second;
// Translate MIME type field to source encoding.
if (format == "mlt" || format == "application/vnd.maplibre-vector-tile") {
doc.AddMember("encoding", "mlt", allocator);
}
if (format != "pbf" && !values.contains("scale")) {
values["scale"] = "1";
}

View File

@@ -47,6 +47,11 @@ std::string extract_url(const std::string& url) {
}
} // namespace
// temporary, remove this when it's available in `pmtiles.hpp`
namespace pmtiles {
const uint8_t TILETYPE_MLT = 0x6;
} // namespace pmtiles
namespace mbgl {
using namespace rapidjson;
@@ -305,6 +310,11 @@ private:
rapidjson::Value().SetString(std::string(util::PMTILES_PROTOCOL + url), allocator), allocator);
}
// Translate tile type field to source encoding.
if (header.tile_type == pmtiles::TILETYPE_MLT) {
doc.AddMember("encoding", "mlt", allocator);
}
if (!doc.HasMember("bounds")) {
doc.AddMember("bounds", rapidjson::Value(), allocator);
}

View File

@@ -131,6 +131,57 @@ ArgumentsTuple parseArguments(int argc, char** argv) {
updateResults,
std::move(testFilter)};
}
void runWithAlternateSources(TestRunner& runner, TestMetadata& metadata, bool& errored, bool& passed) {
constexpr auto replacementsKey = "source-replace";
constexpr auto targetKey = "replace";
constexpr auto sourceKey = "with";
constexpr auto sourcesKey = "sources";
if (!metadata.document.HasMember("metadata") || !metadata.document["metadata"].HasMember("test")) {
return;
}
auto& testElement = metadata.document["metadata"]["test"];
if (!testElement.HasMember(replacementsKey) || !testElement[replacementsKey].IsArray()) {
return;
}
const auto& replacesElement = testElement[replacementsKey];
if (!replacesElement.IsArray() || replacesElement.Empty()) {
return;
}
auto& sources = metadata.document[sourcesKey];
// Each item in the source replacements array...
for (auto i = replacesElement.Begin(); i != replacesElement.End(); ++i) {
const auto& entry = *i;
if (entry.IsObject() && entry.HasMember(targetKey) && entry.HasMember(sourceKey) &&
entry[targetKey].IsString() && entry[sourceKey].IsString()) {
const auto* targetName = entry[targetKey].GetString();
const auto* sourceName = entry[sourceKey].GetString();
if (sources.HasMember(targetName) && sources[targetName].IsObject() && sources.HasMember(sourceName) &&
sources[sourceName].IsObject()) {
// Swap the named sources
sources[targetName].Swap(sources[sourceName]);
// run the test again with the new source
runner.run(metadata);
// Restore the original source
sources[targetName].Swap(sources[sourceName]);
// stop if the test fails
errored = metadata.metricsErrored || metadata.renderErrored || metadata.labelCutOffFound;
passed = !errored && !metadata.metricsFailed && !metadata.renderFailed;
if (!passed) {
break;
}
}
}
}
}
} // namespace
namespace mbgl {
@@ -200,7 +251,7 @@ int runRenderTests(int argc, char** argv, std::function<void()> testStatus) {
if (it != ignores.end()) {
metadata.ignoredTest = shouldIgnore = true;
ignoreReason = it->second;
if (ignoreReason.rfind("skip", 0) == 0) {
if (ignoreReason.starts_with("skip")) {
printf(ANSI_COLOR_GRAY "* skipped %s (%s)" ANSI_COLOR_RESET "\n", id.c_str(), ignoreReason.c_str());
mbgl::Log::Info(mbgl::Event::General, "* skipped " + id + "(" + ignoreReason + ")");
continue;
@@ -217,6 +268,10 @@ int runRenderTests(int argc, char** argv, std::function<void()> testStatus) {
bool errored = metadata.metricsErrored || metadata.renderErrored || metadata.labelCutOffFound;
bool passed = !errored && !metadata.metricsFailed && !metadata.renderFailed;
if (passed) {
runWithAlternateSources(runner, metadata, errored, passed);
}
if (shouldIgnore) {
if (passed) {
status = "ignored passed";

View File

@@ -3,7 +3,7 @@
namespace mbgl {
DEMData::DEMData(const PremultipliedImage& _image, Tileset::DEMEncoding _encoding)
DEMData::DEMData(const PremultipliedImage& _image, Tileset::RasterEncoding _encoding)
: dim(_image.size.height),
// extra two pixels per row for border backfilling on either edge
stride(dim + 2),
@@ -99,7 +99,7 @@ const std::array<float, 4>& DEMData::getUnpackVector() const {
// https://aws.amazon.com/public-datasets/terrain/
static const std::array<float, 4> unpackTerrarium = {{256.0f, 1.0f, 1.0f / 256.0f, 32768.0f}};
return encoding == Tileset::DEMEncoding::Terrarium ? unpackTerrarium : unpackMapbox;
return encoding == Tileset::RasterEncoding::Terrarium ? unpackTerrarium : unpackMapbox;
}
} // namespace mbgl

View File

@@ -13,7 +13,7 @@ namespace mbgl {
class DEMData {
public:
DEMData(const PremultipliedImage& image, Tileset::DEMEncoding encoding);
DEMData(const PremultipliedImage& image, Tileset::RasterEncoding encoding);
void backfillBorder(const DEMData& borderTileData, int8_t dx, int8_t dy);
int32_t get(int32_t x, int32_t y) const;
@@ -24,7 +24,7 @@ public:
const int32_t dim;
const int32_t stride;
const Tileset::DEMEncoding encoding;
const Tileset::RasterEncoding encoding;
private:
std::shared_ptr<PremultipliedImage> image;

View File

@@ -54,10 +54,10 @@ std::size_t totalVerticesCheck(const GeometryCollection& polygon) {
void addFillIndices(SegmentVector& fillSegments,
gfx::IndexVector<gfx::Triangles>& fillIndexes,
std::vector<uint32_t>& indices,
std::size_t startVertices,
std::size_t totalVertices) {
std::size_t nIndices = indices.size();
const std::span<const uint32_t>& indices,
const std::size_t startVertices,
const std::size_t totalVertices) {
const std::size_t nIndices = indices.size();
assert(nIndices % 3 == 0);
if (fillSegments.empty() ||
@@ -66,10 +66,13 @@ void addFillIndices(SegmentVector& fillSegments,
}
auto& triangleSegment = fillSegments.back();
assert(triangleSegment.vertexLength <= std::numeric_limits<uint16_t>::max());
assert(triangleSegment.vertexLength + totalVertices <= std::numeric_limits<uint16_t>::max());
const auto triangleIndex = static_cast<uint16_t>(triangleSegment.vertexLength);
for (std::size_t i = 0; i < nIndices; i += 3) {
assert(
std::max({triangleIndex + indices[i + 0], triangleIndex + indices[i + 1], triangleIndex + indices[i + 2]}) <
triangleIndex + totalVertices);
fillIndexes.emplace_back(
triangleIndex + indices[i], triangleIndex + indices[i + 1], triangleIndex + indices[i + 2]);
}
@@ -78,8 +81,8 @@ void addFillIndices(SegmentVector& fillSegments,
triangleSegment.indexLength += nIndices;
}
void addOutlineIndices(std::size_t base,
std::size_t nVertices,
void addOutlineIndices(const std::size_t base,
const std::size_t nVertices,
SegmentVector& lineSegments,
gfx::IndexVector<gfx::Lines>& lineIndexes) {
if (nVertices == 0) return;
@@ -206,21 +209,36 @@ void generateFillAndOutineBuffers(const GeometryCollection& geometry,
gfx::PolylineGeneratorOptions lineOptions;
lineOptions.type = FeatureType::Polygon;
// If we have pre-tessellated geometry, multi-polygons are tessellated
// together, so we need to add them to the fill segment all at once.
if (!geometry.getTriangles().empty()) {
const std::size_t startVertices = fillVertices.elements();
std::size_t totalVertices = 0;
for (const auto& polygon : geometry) {
totalVertices += polygon.size();
addRingVertices(fillVertices, polygon);
}
addFillIndices(fillSegments, fillIndexes, geometry.getTriangles(), startVertices, totalVertices);
return;
}
for (auto& polygon : classifyRings(geometry)) {
// Optimize polygons with many interior rings for earcut tesselation.
limitHoles(polygon, 500);
std::size_t totalVertices = totalVerticesCheck(polygon);
std::size_t startVertices = fillVertices.elements();
const std::size_t totalVertices = totalVerticesCheck(polygon);
const std::size_t startVertices = fillVertices.elements();
for (const auto& ring : polygon) {
std::size_t base = fillVertices.elements();
std::size_t nVertices = addRingVertices(fillVertices, ring);
const std::size_t base = fillVertices.elements();
const std::size_t nVertices = addRingVertices(fillVertices, ring);
addOutlineIndices(base, nVertices, basicLineSegments, basicLineIndexes);
lineGenerator.generate(ring, lineOptions);
}
// tessellate, if no triangles are provided
std::vector<uint32_t> indices = mapbox::earcut(polygon);
addFillIndices(fillSegments, fillIndexes, indices, startVertices, totalVertices);
}
}

View File

@@ -11,13 +11,13 @@ namespace gfx {
class HillshadePrepareDrawableData : public DrawableData {
public:
HillshadePrepareDrawableData(int32_t stride_, Tileset::DEMEncoding encoding_, uint8_t maxzoom_)
HillshadePrepareDrawableData(int32_t stride_, Tileset::RasterEncoding encoding_, uint8_t maxzoom_)
: stride(stride_),
encoding(encoding_),
maxzoom(maxzoom_) {}
int32_t stride;
Tileset::DEMEncoding encoding;
Tileset::RasterEncoding encoding;
uint8_t maxzoom;
};

View File

@@ -0,0 +1,78 @@
#include <mbgl/programs/programs.hpp>
#include <mbgl/programs/background_program.hpp>
#include <mbgl/programs/circle_program.hpp>
#include <mbgl/programs/heatmap_program.hpp>
#include <mbgl/programs/hillshade_program.hpp>
#include <mbgl/programs/fill_extrusion_program.hpp>
#include <mbgl/programs/fill_program.hpp>
#include <mbgl/programs/line_program.hpp>
#include <mbgl/programs/raster_program.hpp>
#include <mbgl/programs/symbol_program.hpp>
#include <mbgl/util/logging.hpp>
namespace mbgl {
Programs::Programs(const ProgramParameters& programParameters_)
: programParameters(programParameters_) {}
Programs::~Programs() = default;
namespace {
/// @brief Register a list of types with a shader registry instance
/// @tparam ...T Type list parameter pack
/// @param registry A shader registry instance
/// programParameters_ ProgramParameters used to initialize each instance
template <typename... T>
void registerTypes(gfx::ShaderRegistry& registry, const ProgramParameters& programParameters_) {
/// The following fold expression will create a shared_ptr for every type
/// in the parameter pack and register it with the shader registry.
/// Registration calls are wrapped in a lambda that throws on registration
/// failure, we shouldn't expect registration to faill unless the shader
/// registry instance provided already has conflicting programs present.
(
[](bool expr) {
if (!expr) {
throw std::runtime_error("Failed to register " + std::string(T::Name) + " with shader registry!");
}
}(registry.getLegacyGroup().registerShader(std::make_shared<T>(programParameters_))),
...);
}
} // namespace
void Programs::registerWith(gfx::ShaderRegistry& registry) {
#if MLN_LEGACY_RENDERER
/// The following types will be registered
registerTypes<BackgroundProgram,
BackgroundPatternProgram,
RasterProgram,
HeatmapProgram,
HeatmapTextureProgram,
HillshadeProgram,
HillshadePrepareProgram,
FillProgram,
FillPatternProgram,
FillOutlineProgram,
FillOutlinePatternProgram,
FillExtrusionProgram,
FillExtrusionPatternProgram,
CircleProgram,
LineProgram,
LineGradientProgram,
LineSDFProgram,
LinePatternProgram,
SymbolIconProgram,
SymbolSDFIconProgram,
SymbolSDFTextProgram,
SymbolTextAndIconProgram,
CollisionBoxProgram,
CollisionCircleProgram,
DebugProgram,
ClippingMaskProgram>(registry, programParameters);
#else
/// The following types will be registered
registerTypes<DebugProgram, ClippingMaskProgram>(registry, programParameters);
#endif
}
} // namespace mbgl

View File

@@ -6,7 +6,7 @@ namespace mbgl {
using namespace style;
HillshadeBucket::HillshadeBucket(PremultipliedImage&& image_, Tileset::DEMEncoding encoding)
HillshadeBucket::HillshadeBucket(PremultipliedImage&& image_, Tileset::RasterEncoding encoding)
: demdata(image_, encoding) {}
HillshadeBucket::HillshadeBucket(DEMData&& demdata_)

View File

@@ -19,8 +19,8 @@ using HillshadeLayoutVertex = gfx::Vertex<TypeList<attributes::pos, attributes::
class HillshadeBucket final : public Bucket {
public:
HillshadeBucket(PremultipliedImage&&, Tileset::DEMEncoding encoding);
HillshadeBucket(std::shared_ptr<PremultipliedImage>, Tileset::DEMEncoding encoding);
HillshadeBucket(PremultipliedImage&&, Tileset::RasterEncoding encoding);
HillshadeBucket(std::shared_ptr<PremultipliedImage>, Tileset::RasterEncoding encoding);
HillshadeBucket(DEMData&&);
~HillshadeBucket() override;

View File

@@ -79,7 +79,7 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates,
const std::size_t first = [&coordinates, &len] {
std::size_t i = 0;
// If the line has duplicate vertices at the start, adjust index to remove them.
while (i < len - 1 && coordinates[i] == coordinates[i + 1]) {
while (i + 1 < len && coordinates[i] == coordinates[i + 1]) {
i++;
}
return i;
@@ -102,17 +102,16 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates,
return;
}
const auto& props = feature.getProperties();
auto clip_start_it = props.find("mapbox_clip_start");
auto clip_end_it = props.find("mapbox_clip_end");
if (clip_start_it != props.end() && clip_end_it != props.end()) {
const auto clip_start = feature.getValue("mapbox_clip_start");
const auto clip_end = feature.getValue("mapbox_clip_end");
if (clip_start && clip_end) {
double total_length = 0.0;
for (std::size_t i = first; i < len - 1; ++i) {
total_length += util::dist<double>(coordinates[i], coordinates[i + 1]);
}
options.clipDistances = gfx::PolylineGeneratorDistances{
*numericValue<double>(clip_start_it->second), *numericValue<double>(clip_end_it->second), total_length};
*numericValue<double>(*clip_start), *numericValue<double>(*clip_end), total_length};
}
options.joinType = layout.evaluate<LineJoin>(zoom, feature, canonical);

View File

@@ -22,8 +22,8 @@ constexpr std::array<float, 4> unpackMapbox = {{6553.6f, 25.6f, 0.1f, 10000.0f}}
// https://aws.amazon.com/public-datasets/terrain/
constexpr std::array<float, 4> unpackTerrarium = {{256.0f, 1.0f, 1.0f / 256.0f, 32768.0f}};
constexpr const std::array<float, 4>& getUnpackVector(const Tileset::DEMEncoding encoding) {
return (encoding == Tileset::DEMEncoding::Terrarium) ? unpackTerrarium : unpackMapbox;
constexpr const std::array<float, 4>& getUnpackVector(const Tileset::RasterEncoding encoding) {
return (encoding == Tileset::RasterEncoding::Terrarium) ? unpackTerrarium : unpackMapbox;
}
} // namespace

View File

@@ -24,6 +24,7 @@ std::unique_ptr<RenderSource> RenderSource::create(const Immutable<Source::Impl>
const TaggedScheduler& threadPool_) {
switch (impl->type) {
case SourceType::Vector:
// the TileSet isn't available yet, so we can't make different sources by format
return std::make_unique<RenderVectorSource>(staticImmutableCast<TileSource::Impl>(impl),
std::move(threadPool_));
case SourceType::Raster:

View File

@@ -1,8 +1,10 @@
#include <mbgl/renderer/sources/render_vector_source.hpp>
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/tile/vector_tile.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
#include <mbgl/tile/vector_mlt_tile.hpp>
#include <mbgl/tile/vector_mvt_tile.hpp>
namespace mbgl {
@@ -20,17 +22,29 @@ void RenderVectorSource::updateInternal(const Tileset& tileset,
const bool needsRendering,
const bool needsRelayout,
const TileParameters& parameters) {
tilePyramid.update(layers,
needsRendering,
needsRelayout,
parameters,
*baseImpl,
util::tileSize_I,
tileset.zoomRange,
tileset.bounds,
[&](const OverscaledTileID& tileID, TileObserver* observer_) {
return std::make_unique<VectorTile>(tileID, baseImpl->id, parameters, tileset, observer_);
});
tilePyramid.update(
layers,
needsRendering,
needsRelayout,
parameters,
*baseImpl,
util::tileSize_I,
tileset.zoomRange,
tileset.bounds,
[&](const OverscaledTileID& tileID, TileObserver* observer_) -> std::unique_ptr<VectorTile> {
if (!isMLT.has_value()) {
auto impl = staticImmutableCast<style::TileSource::Impl>(baseImpl);
assert(impl->tileset); // we should have one by now
if (impl->tileset) {
isMLT = (impl->tileset->vectorEncoding == Tileset::VectorEncoding::MLT);
}
}
if (isMLT && *isMLT) {
return std::make_unique<VectorMLTTile>(tileID, baseImpl->id, parameters, tileset, observer_);
} else {
return std::make_unique<VectorMVTTile>(tileID, baseImpl->id, parameters, tileset, observer_);
}
});
}
} // namespace mbgl

View File

@@ -17,6 +17,9 @@ private:
bool needsRelayout,
const TileParameters&) override;
const std::optional<Tileset>& getTileset() const override;
private:
std::optional<bool> isMLT;
};
} // namespace mbgl

View File

@@ -1,34 +0,0 @@
#include <mbgl/style/conversion/raster_dem_options.hpp>
#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/style/expression/dsl.hpp>
#include <sstream>
namespace mbgl {
namespace style {
namespace conversion {
std::optional<RasterDEMOptions> Converter<RasterDEMOptions>::operator()(const Convertible& value, Error& error) const {
RasterDEMOptions options;
auto encodingValue = objectMember(value, "encoding");
if (encodingValue) {
std::optional<std::string> encoding = toString(*encodingValue);
if (encoding && *encoding == "terrarium") {
options.encoding = {Tileset::DEMEncoding::Terrarium};
} else if (encoding && *encoding == "mapbox") {
options.encoding = {Tileset::DEMEncoding::Mapbox};
} else {
error.message =
"invalid raster-dem encoding type - valid types are 'mapbox' "
"and 'terrarium'";
return std::nullopt;
}
}
return {std::move(options)};
}
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -2,7 +2,7 @@
#include <mbgl/style/conversion/coordinate.hpp>
#include <mbgl/style/conversion/geojson.hpp>
#include <mbgl/style/conversion/geojson_options.hpp>
#include <mbgl/style/conversion/raster_dem_options.hpp>
#include <mbgl/style/conversion/source_options.hpp>
#include <mbgl/style/conversion/tileset.hpp>
#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
@@ -16,8 +16,8 @@ namespace mbgl {
namespace style {
namespace conversion {
// A tile source can either specify a URL to TileJSON, or inline TileJSON.
namespace {
// A tile source can either specify a URL to TileJSON, or inline TileJSON.
std::optional<variant<std::string, Tileset>> convertURLOrTileset(const Convertible& value, Error& error) {
auto urlVal = objectMember(value, "url");
if (!urlVal) {
@@ -25,7 +25,7 @@ std::optional<variant<std::string, Tileset>> convertURLOrTileset(const Convertib
if (!tileset) {
return std::nullopt;
}
return {*tileset};
return {std::move(*tileset)};
}
std::optional<std::string> url = toString(*urlVal);
@@ -34,7 +34,7 @@ std::optional<variant<std::string, Tileset>> convertURLOrTileset(const Convertib
return std::nullopt;
}
return {*url};
return {std::move(*url)};
}
std::optional<std::unique_ptr<Source>> convertRasterSource(const std::string& id,
@@ -83,7 +83,7 @@ std::optional<std::unique_ptr<Source>> convertRasterDEMSource(const std::string&
parameters. Since style.json can contain TileJSON parameter overrides or non-TileJSON spec parameters, a
separate mechanism is needed. Ideally these two pathways share parsing logic.
*/
std::optional<RasterDEMOptions> options = convert<RasterDEMOptions>(value, error);
auto options = convert<SourceOptions>(value, error);
return {std::make_unique<RasterDEMSource>(id, std::move(*urlOrTileset), tileSize, options)};
}
@@ -91,11 +91,11 @@ std::optional<std::unique_ptr<Source>> convertRasterDEMSource(const std::string&
std::optional<std::unique_ptr<Source>> convertVectorSource(const std::string& id,
const Convertible& value,
Error& error) {
std::optional<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value, error);
auto urlOrTileset = convertURLOrTileset(value, error);
if (!urlOrTileset) {
return std::nullopt;
}
auto maxzoomValue = objectMember(value, "maxzoom");
const auto maxzoomValue = objectMember(value, "maxzoom");
std::optional<float> maxzoom;
if (maxzoomValue) {
maxzoom = toNumber(*maxzoomValue);
@@ -104,7 +104,7 @@ std::optional<std::unique_ptr<Source>> convertVectorSource(const std::string& id
return std::nullopt;
}
}
auto minzoomValue = objectMember(value, "minzoom");
const auto minzoomValue = objectMember(value, "minzoom");
std::optional<float> minzoom;
if (minzoomValue) {
minzoom = toNumber(*minzoomValue);
@@ -113,7 +113,20 @@ std::optional<std::unique_ptr<Source>> convertVectorSource(const std::string& id
return std::nullopt;
}
}
return {std::make_unique<VectorSource>(id, std::move(*urlOrTileset), std::move(maxzoom), std::move(minzoom))};
const auto encodingValue = objectMember(value, "encoding");
auto encoding = Tileset::VectorEncoding::Mapbox;
if (encodingValue) {
const auto encodingStr = toString(*encodingValue);
if (encodingStr && encodingStr == "mvt") {
encoding = Tileset::VectorEncoding::Mapbox;
} else if (encodingStr && encodingStr == "mlt") {
encoding = Tileset::VectorEncoding::MLT;
} else {
error.message = "invalid encoding";
return std::nullopt;
}
}
return {std::make_unique<VectorSource>(id, std::move(*urlOrTileset), maxzoom, minzoom, encoding)};
}
std::optional<std::unique_ptr<Source>> convertGeoJSONSource(const std::string& id,

View File

@@ -0,0 +1,33 @@
#include <mbgl/style/conversion/source_options.hpp>
#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/style/expression/dsl.hpp>
namespace mbgl {
namespace style {
namespace conversion {
std::optional<SourceOptions> Converter<SourceOptions>::operator()(const Convertible& value, Error& error) const {
const auto encodingValue = objectMember(value, "encoding");
if (encodingValue) {
const auto encoding = toString(*encodingValue);
if (encoding && *encoding == "terrarium") {
return {{.rasterEncoding = Tileset::RasterEncoding::Terrarium}};
} else if (encoding && *encoding == "mapbox") {
return {{.rasterEncoding = Tileset::RasterEncoding::Mapbox}};
} else if (encoding && *encoding == "mvt") {
return {{.vectorEncoding = Tileset::VectorEncoding::Mapbox}};
} else if (encoding && *encoding == "mlt") {
return {{.vectorEncoding = Tileset::VectorEncoding::MLT}};
} else {
error.message =
"invalid encoding - valid types are 'mapbox' and 'terrarium' for raster sources, 'mvt' and 'mlt' for "
"vector sources";
return std::nullopt;
}
}
return {};
}
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -1,5 +1,5 @@
#include <mbgl/style/conversion/tileset.hpp>
#include <mbgl/style/conversion/raster_dem_options.hpp>
#include <mbgl/style/conversion/source_options.hpp>
#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/math/clamp.hpp>
@@ -39,10 +39,13 @@ std::optional<Tileset> Converter<Tileset>::operator()(const Convertible& value,
}
}
auto rasterDEMOptions = convert<RasterDEMOptions>(value, error);
if (rasterDEMOptions) {
if (std::optional<Tileset::DEMEncoding> encoding = rasterDEMOptions.value().encoding) {
result.encoding = encoding.value();
auto options = convert<SourceOptions>(value, error);
if (options) {
if (const auto encoding = options->rasterEncoding) {
result.rasterEncoding = encoding;
}
if (const auto encoding = options->vectorEncoding) {
result.vectorEncoding = encoding;
}
}

View File

@@ -15,7 +15,7 @@ namespace style {
RasterDEMSource::RasterDEMSource(std::string id,
variant<std::string, Tileset> urlOrTileset_,
uint16_t tileSize,
std::optional<RasterDEMOptions> options_)
std::optional<SourceOptions> options_)
: RasterSource(std::move(id), std::move(urlOrTileset_), tileSize, SourceType::RasterDEM),
options(std::move(options_)) {}
@@ -30,8 +30,8 @@ bool RasterDEMSource::supportsLayerType(const mbgl::style::LayerTypeInfo* info)
void RasterDEMSource::setTilesetOverrides(Tileset& tileset) {
if (options) {
if (std::optional<Tileset::DEMEncoding> encoding = options.value().encoding) {
tileset.encoding = encoding.value();
if (const auto encoding = options->rasterEncoding) {
tileset.rasterEncoding = encoding;
}
}
}

View File

@@ -10,6 +10,7 @@
#include <mbgl/util/constants.hpp>
#include <mbgl/util/exception.hpp>
#include <mbgl/util/mapbox.hpp>
#include <string>
namespace mbgl {
namespace style {
@@ -17,10 +18,12 @@ namespace style {
VectorSource::VectorSource(std::string id,
variant<std::string, Tileset> urlOrTileset_,
std::optional<float> maxZoom_,
std::optional<float> minZoom_)
std::optional<float> minZoom_,
Tileset::VectorEncoding encoding_)
: TileSource(id, urlOrTileset_, util::tileSize_I, SourceType::Vector),
maxZoom(std::move(maxZoom_)),
minZoom(std::move(minZoom_)) {}
minZoom(std::move(minZoom_)),
encoding(encoding_) {}
void VectorSource::setTilesetOverrides(Tileset& tileset) {
if (maxZoom) {

View File

@@ -4,11 +4,14 @@
#include <mbgl/util/feature.hpp>
#include <cstdint>
#include <memory>
#include <span>
#include <string>
#include <vector>
#include <memory>
#include <optional>
namespace mlt {
class MapLibreTile;
}
namespace mbgl {
class CanonicalTileID;
@@ -44,8 +47,17 @@ public:
GeometryCollection clone() const { return GeometryCollection(*this); }
const auto& getTriangles() const { return triangles; }
void setTriangles(std::shared_ptr<const mlt::MapLibreTile> owner, std::span<const std::uint32_t> triangles_) {
triangleOwner = std::move(owner);
triangles = triangles_;
}
private:
GeometryCollection(const GeometryCollection&) = default;
std::shared_ptr<const mlt::MapLibreTile> triangleOwner;
std::span<const std::uint32_t> triangles = {};
};
class GeometryTileFeature {

View File

@@ -24,7 +24,7 @@ RasterDEMTile::RasterDEMTile(const OverscaledTileID& id_,
threadPool(parameters.threadPool),
mailbox(std::make_shared<Mailbox>(*Scheduler::GetCurrent())),
worker(parameters.threadPool, ActorRef<RasterDEMTile>(*this, mailbox)) {
encoding = tileset.encoding;
encoding = tileset.rasterEncoding.value_or(Tileset::RasterEncoding::Mapbox);
if (id.canonical.y == 0) {
// this tile doesn't have upper neighboring tiles so marked those as backfilled
neighboringTiles = neighboringTiles | DEMTileNeighbors::NoUpper;

View File

@@ -99,7 +99,7 @@ private:
Actor<RasterDEMTileWorker> worker;
uint64_t correlationID = 0;
Tileset::DEMEncoding encoding;
Tileset::RasterEncoding encoding;
// Contains the Bucket object for the tile. Buckets are render
// objects and they get added by tile parsing operations.

View File

@@ -11,7 +11,7 @@ RasterDEMTileWorker::RasterDEMTileWorker(const ActorRef<RasterDEMTileWorker>&, A
void RasterDEMTileWorker::parse(const std::shared_ptr<const std::string>& data,
uint64_t correlationID,
Tileset::DEMEncoding encoding) {
Tileset::RasterEncoding encoding) {
if (!data) {
parent.invoke(&RasterDEMTile::onParsed, nullptr,
correlationID); // No data; empty tile.

View File

@@ -14,7 +14,9 @@ class RasterDEMTileWorker {
public:
RasterDEMTileWorker(const ActorRef<RasterDEMTileWorker>&, ActorRef<RasterDEMTile>);
void parse(const std::shared_ptr<const std::string>& data, uint64_t correlationID, Tileset::DEMEncoding encoding);
void parse(const std::shared_ptr<const std::string>& data,
uint64_t correlationID,
Tileset::RasterEncoding encoding);
private:
ActorRef<RasterDEMTile> parent;

View File

@@ -0,0 +1,24 @@
#include <mbgl/tile/vector_mlt_tile.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
#include <mbgl/tile/tile_loader_impl.hpp>
#include <mbgl/tile/vector_mlt_tile_data.hpp>
#include <utility>
namespace mbgl {
VectorMLTTile::VectorMLTTile(const OverscaledTileID& id_,
std::string sourceID_,
const TileParameters& parameters_,
const Tileset& tileset_,
TileObserver* observer_)
: VectorTile(id_, std::move(sourceID_), parameters_, tileset_, observer_) {}
void VectorMLTTile::setData(const std::shared_ptr<const std::string>& data_) {
if (!obsolete) {
GeometryTile::setData(data_ ? std::make_unique<VectorMLTTileData>(data_) : nullptr);
}
}
} // namespace mbgl

View File

@@ -0,0 +1,23 @@
#pragma once
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/tile_loader.hpp>
#include <mbgl/tile/vector_tile.hpp>
namespace mbgl {
class Tileset;
class TileParameters;
class VectorMLTTile : public VectorTile {
public:
VectorMLTTile(const OverscaledTileID&,
std::string sourceID,
const TileParameters&,
const Tileset&,
TileObserver* observer = nullptr);
void setData(const std::shared_ptr<const std::string>& data) override;
};
} // namespace mbgl

View File

@@ -0,0 +1,220 @@
#include <mapbox/feature.hpp>
#include <mbgl/tile/vector_mlt_tile_data.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/instrumentation.hpp>
#include <mbgl/util/logging.hpp>
#include <mlt/decoder.hpp>
#include <mlt/layer.hpp>
namespace mbgl {
using GeometryType = mlt::metadata::tileset::GeometryType;
VectorMLTTileFeature::VectorMLTTileFeature(std::shared_ptr<const MapLibreTile> tile_,
const mlt::Layer& layer_,
const mlt::Feature& feature_,
std::uint32_t extent_)
: tile(std::move(tile_)),
layer(layer_),
feature(feature_),
extent(extent_) {}
FeatureType VectorMLTTileFeature::getType() const {
switch (feature.getGeometry().type) {
case GeometryType::POINT:
return FeatureType::Point;
case GeometryType::MULTIPOINT:
case GeometryType::MULTILINESTRING:
case GeometryType::LINESTRING:
return FeatureType::LineString;
case GeometryType::POLYGON:
case GeometryType::MULTIPOLYGON:
return FeatureType::Polygon;
default:
return FeatureType::Unknown;
}
}
namespace {
struct PropertyVisitor {
Value operator()(std::nullptr_t) const { return mapbox::feature::null_value; }
Value operator()(bool value) const { return value; }
Value operator()(std::uint32_t value) const { return value; }
Value operator()(std::uint64_t value) const { return value; }
Value operator()(float value) const { return value; }
Value operator()(double value) const { return value; }
Value operator()(std::string_view value) const { return std::string(value); }
template <typename T>
Value operator()(std::optional<T> value) const {
return value ? operator()(*value) : NullValue();
}
};
} // namespace
std::optional<Value> VectorMLTTileFeature::getValue(const std::string& key) const {
if (auto prop = feature.getProperty(key, layer)) {
return std::visit(PropertyVisitor(), *prop);
}
return std::nullopt;
}
const PropertyMap& VectorMLTTileFeature::getProperties() const {
if (!properties) {
const PropertyVisitor visitor;
properties.emplace();
properties->reserve(layer.getProperties().size());
for (const auto& [key, props] : layer.getProperties()) {
auto value = props.getProperty(feature.getIndex());
auto prop = value ? std::visit(visitor, std::move(*value)) : mapbox::feature::null_value;
properties->emplace(key, std::move(prop));
}
}
return *properties;
}
FeatureIdentifier VectorMLTTileFeature::getID() const {
return feature.getID();
}
namespace {
struct PointConverter {
double scale;
inline constexpr static GeometryCoordinate convert(double scale, const mlt::Coordinate& coord) {
return {static_cast<std::int16_t>(std::round(coord.x * scale)),
static_cast<std::int16_t>(std::round(coord.y * scale))};
}
GeometryCoordinate operator()(const mlt::Coordinate& coord) const { return convert(scale, coord); }
GeometryCoordinates operator()(const mlt::CoordVec& coords) const {
GeometryCoordinates result(coords.size());
std::ranges::transform(coords, result.begin(), *this);
return result;
}
};
} // namespace
const GeometryCollection& VectorMLTTileFeature::getGeometries() const {
MLN_TRACE_FUNC();
if (!lines) {
const auto scale = static_cast<double>(util::EXTENT) / extent;
const auto& geometry = feature.getGeometry();
const PointConverter convert{scale};
switch (geometry.type) {
case GeometryType::POINT: {
const auto& geom = static_cast<const mlt::geometry::Point&>(geometry);
lines = GeometryCollection{{convert(geom.getCoordinate())}};
break;
}
case GeometryType::MULTIPOINT:
case GeometryType::LINESTRING: {
const auto& geom = static_cast<const mlt::geometry::MultiPoint&>(geometry);
lines = GeometryCollection{convert(geom.getCoordinates())};
break;
}
case GeometryType::POLYGON: {
const auto& geom = static_cast<const mlt::geometry::Polygon&>(geometry);
lines.emplace(geom.getRings().size());
std::ranges::transform(geom.getRings(), lines->begin(), convert);
if (!geometry.getTriangles().empty()) {
lines->setTriangles(tile, geometry.getTriangles());
}
break;
}
case GeometryType::MULTILINESTRING: {
const auto& geom = static_cast<const mlt::geometry::MultiLineString&>(geometry);
lines.emplace(geom.getLineStrings().size());
std::ranges::transform(geom.getLineStrings(), lines->begin(), convert);
break;
}
case GeometryType::MULTIPOLYGON: {
const auto& geom = static_cast<const mlt::geometry::MultiPolygon&>(geometry);
const auto& polygons = geom.getPolygons();
using RingVec = mlt::geometry::MultiPolygon::RingVec;
lines.emplace(std::accumulate(
polygons.begin(), polygons.end(), static_cast<std::size_t>(0), [](std::size_t a, const RingVec& b) {
return a + b.size();
}));
for (const auto& poly : polygons) {
std::ranges::transform(poly, std::back_inserter(*lines), convert);
}
if (!geometry.getTriangles().empty()) {
lines->setTriangles(tile, geometry.getTriangles());
}
break;
}
default:
lines.emplace();
break;
}
}
return *lines;
}
VectorMLTTileLayer::VectorMLTTileLayer(std::shared_ptr<const MapLibreTile> tile_, const mlt::Layer& layer_)
: tile(std::move(tile_)),
layer(layer_) {}
std::size_t VectorMLTTileLayer::featureCount() const {
return layer.getFeatures().size();
}
std::unique_ptr<GeometryTileFeature> VectorMLTTileLayer::getFeature(std::size_t index) const {
const auto& features = layer.getFeatures();
const mlt::Feature* targetFeature = nullptr;
targetFeature = &features[index];
return std::make_unique<VectorMLTTileFeature>(tile, layer, *targetFeature, layer.getExtent());
}
std::string VectorMLTTileLayer::getName() const {
return layer.getName();
}
VectorMLTTileData::VectorMLTTileData(std::shared_ptr<const std::string> data_)
: data(std::move(data_)) {}
VectorMLTTileData::VectorMLTTileData(const VectorMLTTileData& other)
: data(other.data),
tile(other.tile) {}
std::unique_ptr<GeometryTileData> VectorMLTTileData::clone() const {
return std::make_unique<VectorMLTTileData>(*this);
}
std::unique_ptr<GeometryTileLayer> VectorMLTTileData::getLayer(const std::string& name) const {
MLN_TRACE_FUNC();
if (data && !tile) {
try {
mlt::DataView tileData{data->data(), data->size()};
tile = std::make_shared<MapLibreTile>(mlt::Decoder().decode(tileData));
} catch (const std::exception& ex) {
Log::Warning(Event::ParseTile, "MLT parse failed: " + std::string(ex.what()));
}
// We don't need the raw data anymore
data.reset();
}
if (tile) {
if (const auto* layer = tile->getLayer(name)) {
return std::make_unique<VectorMLTTileLayer>(tile, *layer);
}
}
return nullptr;
}
std::vector<std::string> VectorMLTTileData::layerNames() const {
if (data && !data->empty() && !tile) {
getLayer({});
}
if (tile) {
std::vector<std::string> result(tile->getLayers().size());
std::ranges::transform(tile->getLayers(), result.begin(), [](const auto& layer) { return layer.getName(); });
return result;
}
return {};
}
} // namespace mbgl

View File

@@ -0,0 +1,85 @@
#pragma once
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/util/containers.hpp>
#include <unordered_map>
#include <functional>
#include <utility>
namespace mlt {
class MapLibreTile;
class Feature;
class Layer;
} // namespace mlt
namespace mbgl {
using MapLibreTile = mlt::MapLibreTile;
class VectorMLTTileFeature : public GeometryTileFeature {
public:
VectorMLTTileFeature(std::shared_ptr<const MapLibreTile>,
const mlt::Layer& layer_,
const mlt::Feature&,
std::uint32_t extent);
VectorMLTTileFeature(const VectorMLTTileFeature&) = delete;
VectorMLTTileFeature(VectorMLTTileFeature&& other)
: tile(std::move(other.tile)),
layer(other.layer),
feature(other.feature),
extent(other.extent),
version(other.version),
lines(std::move(other.lines)),
properties(std::move(other.properties)) {}
VectorMLTTileFeature& operator=(VectorMLTTileFeature&&) = delete;
VectorMLTTileFeature& operator=(const VectorMLTTileFeature&) = delete;
FeatureType getType() const override;
std::optional<Value> getValue(const std::string& key) const override;
const PropertyMap& getProperties() const override;
FeatureIdentifier getID() const override;
const GeometryCollection& getGeometries() const override;
private:
std::shared_ptr<const MapLibreTile> tile;
const mlt::Layer& layer;
mlt::Feature const& feature;
std::uint32_t extent;
int version;
// lazy init
mutable std::optional<GeometryCollection> lines;
mutable std::optional<PropertyMap> properties;
};
class VectorMLTTileLayer : public GeometryTileLayer {
public:
VectorMLTTileLayer(std::shared_ptr<const MapLibreTile>, const mlt::Layer&);
std::size_t featureCount() const override;
std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override;
std::string getName() const override;
private:
const std::shared_ptr<const MapLibreTile> tile;
const mlt::Layer& layer;
};
class VectorMLTTileData : public GeometryTileData {
public:
VectorMLTTileData(std::shared_ptr<const std::string> data);
VectorMLTTileData(const VectorMLTTileData&);
VectorMLTTileData(VectorMLTTileData&&) = default;
std::unique_ptr<GeometryTileData> clone() const override;
std::unique_ptr<GeometryTileLayer> getLayer(const std::string& name) const override;
std::vector<std::string> layerNames() const;
private:
mutable std::shared_ptr<const std::string> data;
mutable std::shared_ptr<const MapLibreTile> tile;
};
} // namespace mbgl

View File

@@ -0,0 +1,24 @@
#include <mbgl/tile/vector_mvt_tile.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
#include <mbgl/tile/tile_loader_impl.hpp>
#include <mbgl/tile/vector_mvt_tile_data.hpp>
#include <utility>
namespace mbgl {
VectorMVTTile::VectorMVTTile(const OverscaledTileID& id_,
std::string sourceID_,
const TileParameters& parameters_,
const Tileset& tileset_,
TileObserver* observer_)
: VectorTile(id_, std::move(sourceID_), parameters_, tileset_, observer_) {}
void VectorMVTTile::setData(const std::shared_ptr<const std::string>& data_) {
if (!obsolete) {
GeometryTile::setData(data_ ? std::make_unique<VectorMVTTileData>(data_) : nullptr);
}
}
} // namespace mbgl

View File

@@ -0,0 +1,23 @@
#pragma once
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/tile_loader.hpp>
#include <mbgl/tile/vector_tile.hpp>
namespace mbgl {
class Tileset;
class TileParameters;
class VectorMVTTile : public VectorTile {
public:
VectorMVTTile(const OverscaledTileID&,
std::string sourceID,
const TileParameters&,
const Tileset&,
TileObserver* observer = nullptr);
void setData(const std::shared_ptr<const std::string>& data) override;
};
} // namespace mbgl

View File

@@ -1,14 +1,19 @@
#include <mbgl/tile/vector_tile_data.hpp>
#include <mbgl/tile/vector_mvt_tile_data.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/instrumentation.hpp>
#include <mbgl/util/logging.hpp>
#if ANDROID
#include <mlt/decoder.hpp>
#endif
namespace mbgl {
VectorTileFeature::VectorTileFeature(const mapbox::vector_tile::layer& layer, const protozero::data_view& view)
VectorMVTTileFeature::VectorMVTTileFeature(const mapbox::vector_tile::layer& layer, const protozero::data_view& view)
: feature(view, layer) {}
FeatureType VectorTileFeature::getType() const {
FeatureType VectorMVTTileFeature::getType() const {
switch (feature.getType()) {
case mapbox::vector_tile::GeomType::POINT:
return FeatureType::Point;
@@ -21,23 +26,23 @@ FeatureType VectorTileFeature::getType() const {
}
}
std::optional<Value> VectorTileFeature::getValue(const std::string& key) const {
const std::optional<Value> value(feature.getValue(key));
return value->is<NullValue>() ? std::nullopt : value;
std::optional<Value> VectorMVTTileFeature::getValue(const std::string& key) const {
const auto value = feature.getValue(key);
return value.is<NullValue>() ? std::nullopt : std::optional<Value>{std::move(value)};
}
const PropertyMap& VectorTileFeature::getProperties() const {
const PropertyMap& VectorMVTTileFeature::getProperties() const {
if (!properties) {
properties = feature.getProperties();
}
return *properties;
}
FeatureIdentifier VectorTileFeature::getID() const {
FeatureIdentifier VectorMVTTileFeature::getID() const {
return feature.getID();
}
const GeometryCollection& VectorTileFeature::getGeometries() const {
const GeometryCollection& VectorMVTTileFeature::getGeometries() const {
MLN_TRACE_FUNC();
if (!lines) {
@@ -57,30 +62,30 @@ const GeometryCollection& VectorTileFeature::getGeometries() const {
return *lines;
}
VectorTileLayer::VectorTileLayer(std::shared_ptr<const std::string> data_, const protozero::data_view& view)
VectorMVTTileLayer::VectorMVTTileLayer(std::shared_ptr<const std::string> data_, const protozero::data_view& view)
: data(std::move(data_)),
layer(view) {}
std::size_t VectorTileLayer::featureCount() const {
std::size_t VectorMVTTileLayer::featureCount() const {
return layer.featureCount();
}
std::unique_ptr<GeometryTileFeature> VectorTileLayer::getFeature(std::size_t i) const {
return std::make_unique<VectorTileFeature>(layer, layer.getFeature(i));
std::unique_ptr<GeometryTileFeature> VectorMVTTileLayer::getFeature(std::size_t i) const {
return std::make_unique<VectorMVTTileFeature>(layer, layer.getFeature(i));
}
std::string VectorTileLayer::getName() const {
std::string VectorMVTTileLayer::getName() const {
return layer.getName();
}
VectorTileData::VectorTileData(std::shared_ptr<const std::string> data_)
VectorMVTTileData::VectorMVTTileData(std::shared_ptr<const std::string> data_)
: data(std::move(data_)) {}
std::unique_ptr<GeometryTileData> VectorTileData::clone() const {
return std::make_unique<VectorTileData>(data);
std::unique_ptr<GeometryTileData> VectorMVTTileData::clone() const {
return std::make_unique<VectorMVTTileData>(data);
}
std::unique_ptr<GeometryTileLayer> VectorTileData::getLayer(const std::string& name) const {
std::unique_ptr<GeometryTileLayer> VectorMVTTileData::getLayer(const std::string& name) const {
MLN_TRACE_FUNC();
if (!parsed) {
@@ -93,12 +98,12 @@ std::unique_ptr<GeometryTileLayer> VectorTileData::getLayer(const std::string& n
auto it = layers.find(name);
if (it != layers.end()) {
return std::make_unique<VectorTileLayer>(data, it->second);
return std::make_unique<VectorMVTTileLayer>(data, it->second);
}
return nullptr;
}
std::vector<std::string> VectorTileData::layerNames() const {
std::vector<std::string> VectorMVTTileData::layerNames() const {
return mapbox::vector_tile::buffer(*data).layerNames();
}

View File

@@ -20,9 +20,9 @@
namespace mbgl {
class VectorTileFeature : public GeometryTileFeature {
class VectorMVTTileFeature : public GeometryTileFeature {
public:
VectorTileFeature(const mapbox::vector_tile::layer&, const protozero::data_view&);
VectorMVTTileFeature(const mapbox::vector_tile::layer&, const protozero::data_view&);
FeatureType getType() const override;
std::optional<Value> getValue(const std::string& key) const override;
@@ -36,9 +36,9 @@ private:
mutable std::optional<PropertyMap> properties;
};
class VectorTileLayer : public GeometryTileLayer {
class VectorMVTTileLayer : public GeometryTileLayer {
public:
VectorTileLayer(std::shared_ptr<const std::string> data, const protozero::data_view&);
VectorMVTTileLayer(std::shared_ptr<const std::string> data, const protozero::data_view&);
std::size_t featureCount() const override;
std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override;
@@ -49,9 +49,9 @@ private:
mapbox::vector_tile::layer layer;
};
class VectorTileData : public GeometryTileData {
class VectorMVTTileData : public GeometryTileData {
public:
VectorTileData(std::shared_ptr<const std::string> data);
VectorMVTTileData(std::shared_ptr<const std::string> data);
std::unique_ptr<GeometryTileData> clone() const override;
std::unique_ptr<GeometryTileLayer> getLayer(const std::string& name) const override;

View File

@@ -1,18 +1,19 @@
#include <mbgl/tile/vector_mvt_tile.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
#include <mbgl/tile/tile_loader_impl.hpp>
#include <mbgl/tile/vector_tile.hpp>
#include <mbgl/tile/vector_tile_data.hpp>
#include <utility>
namespace mbgl {
VectorTile::VectorTile(const OverscaledTileID& id_,
std::string sourceID_,
const TileParameters& parameters,
const TileParameters& parameters_,
const Tileset& tileset,
TileObserver* observer_)
: GeometryTile(id_, std::move(sourceID_), parameters, observer_),
loader(*this, id_, parameters, tileset) {}
: GeometryTile(id_, std::move(sourceID_), parameters_, observer_),
loader(*this, id_, parameters_, tileset) {}
VectorTile::~VectorTile() {
// Don't rely on `~TileLoader` to close, it's not safe to call there.
@@ -33,12 +34,4 @@ void VectorTile::setMetadata(std::optional<Timestamp> modified_, std::optional<T
expires = std::move(expires_);
}
void VectorTile::setData(const std::shared_ptr<const std::string>& data_) {
if (obsolete) {
return;
}
GeometryTile::setData(data_ ? std::make_unique<VectorTileData>(data_) : nullptr);
}
} // namespace mbgl

View File

@@ -20,7 +20,8 @@ public:
void setNecessity(TileNecessity) final;
void setUpdateParameters(const TileUpdateParameters&) final;
void setMetadata(std::optional<Timestamp> modified, std::optional<Timestamp> expires);
void setData(const std::shared_ptr<const std::string>& data);
virtual void setData(const std::shared_ptr<const std::string>&) = 0;
private:
TileLoader<VectorTile> loader;

View File

@@ -52,7 +52,7 @@ add_library(
${PROJECT_SOURCE_DIR}/test/style/conversion/light.test.cpp
${PROJECT_SOURCE_DIR}/test/style/conversion/padding.test.cpp
${PROJECT_SOURCE_DIR}/test/style/conversion/property_value.test.cpp
${PROJECT_SOURCE_DIR}/test/style/conversion/raster_dem_options.test.cpp
${PROJECT_SOURCE_DIR}/test/style/conversion/source_options.test.cpp
${PROJECT_SOURCE_DIR}/test/style/conversion/stringify.test.cpp
${PROJECT_SOURCE_DIR}/test/style/conversion/tileset.test.cpp
${PROJECT_SOURCE_DIR}/test/style/expression/dependency.test.cpp

View File

@@ -17,7 +17,7 @@ auto fakeImage = [](Size s) {
TEST(DEMData, ConstructorMapbox) {
PremultipliedImage image = fakeImage({16, 16});
DEMData demdata(image, Tileset::DEMEncoding::Mapbox);
DEMData demdata(image, Tileset::RasterEncoding::Mapbox);
EXPECT_EQ(demdata.dim, 16);
EXPECT_EQ(demdata.stride, 18);
@@ -26,7 +26,7 @@ TEST(DEMData, ConstructorMapbox) {
TEST(DEMData, ConstructorTerrarium) {
PremultipliedImage image = fakeImage({16, 16});
DEMData demdata(image, Tileset::DEMEncoding::Terrarium);
DEMData demdata(image, Tileset::RasterEncoding::Terrarium);
EXPECT_EQ(demdata.dim, 16);
EXPECT_EQ(demdata.stride, 18);
@@ -35,7 +35,7 @@ TEST(DEMData, ConstructorTerrarium) {
TEST(DEMData, InitialBackfill) {
PremultipliedImage image1 = fakeImage({4, 4});
DEMData dem1(image1, Tileset::DEMEncoding::Mapbox);
DEMData dem1(image1, Tileset::RasterEncoding::Mapbox);
bool nonempty = true;
// checking that a 1 px border around the fake image has been populated
@@ -89,10 +89,10 @@ TEST(DEMData, InitialBackfill) {
TEST(DEMData, BackfillNeighbor) {
PremultipliedImage image1 = fakeImage({4, 4});
DEMData dem0(image1, Tileset::DEMEncoding::Mapbox);
DEMData dem0(image1, Tileset::RasterEncoding::Mapbox);
PremultipliedImage image2 = fakeImage({4, 4});
DEMData dem1(image2, Tileset::DEMEncoding::Mapbox);
DEMData dem1(image2, Tileset::RasterEncoding::Mapbox);
dem0.backfillBorder(dem1, -1, 0);
for (int y = 0; y < 4; y++) {

View File

@@ -1,48 +0,0 @@
#include <mbgl/test/util.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion/raster_dem_options.hpp>
#include <mbgl/util/tileset.hpp>
#include <mbgl/util/logging.hpp>
using namespace mbgl;
using namespace mbgl::style;
using namespace mbgl::style::conversion;
TEST(RasterDEMOptions, Basic) {
Error error;
std::optional<RasterDEMOptions> converted = convertJSON<RasterDEMOptions>("{}", error);
ASSERT_TRUE((bool)converted);
}
TEST(RasterDEMOptions, ErrorHandling) {
Error error;
std::optional<RasterDEMOptions> converted = convertJSON<RasterDEMOptions>(
R"JSON({
"encoding": "this isn't a valid encoding"
})JSON",
error);
ASSERT_FALSE(converted);
ASSERT_EQ(error.message, "invalid raster-dem encoding type - valid types are 'mapbox' and 'terrarium'");
}
TEST(RasterDEMOptions, TerrariumEncodingParsed) {
Error error;
std::optional<RasterDEMOptions> converted = convertJSON<RasterDEMOptions>(
R"JSON({
"encoding": "terrarium"
})JSON",
error);
ASSERT_EQ(converted.value().encoding, Tileset::DEMEncoding::Terrarium);
}
TEST(RasterDEMOptions, MapboxEncodingParsed) {
Error error;
std::optional<RasterDEMOptions> converted = convertJSON<RasterDEMOptions>(
R"JSON({
"encoding": "mapbox"
})JSON",
error);
ASSERT_EQ(converted.value().encoding, Tileset::DEMEncoding::Mapbox);
}

View File

@@ -0,0 +1,72 @@
#include <mbgl/test/util.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion/source_options.hpp>
#include <mbgl/util/tileset.hpp>
#include <mbgl/util/logging.hpp>
using namespace mbgl;
using namespace mbgl::style;
using namespace mbgl::style::conversion;
TEST(SourceOptions, Basic) {
Error error;
auto converted = convertJSON<SourceOptions>("{}", error);
ASSERT_FALSE(converted);
}
TEST(SourceOptions, ErrorHandling) {
Error error;
auto converted = convertJSON<SourceOptions>(
R"JSON({
"encoding": "this isn't a valid encoding"
})JSON",
error);
ASSERT_FALSE(converted);
ASSERT_EQ(0, error.message.find("invalid encoding"));
}
TEST(SourceOptions, TerrariumEncodingParsed) {
Error error;
auto converted = convertJSON<SourceOptions>(
R"JSON({
"encoding": "terrarium"
})JSON",
error);
ASSERT_EQ(converted.value().rasterEncoding, Tileset::RasterEncoding::Terrarium);
ASSERT_FALSE(converted.value().vectorEncoding);
}
TEST(SourceOptions, MapboxEncodingParsed) {
Error error;
auto converted = convertJSON<SourceOptions>(
R"JSON({
"encoding": "mapbox"
})JSON",
error);
ASSERT_EQ(converted.value().rasterEncoding, Tileset::RasterEncoding::Mapbox);
ASSERT_FALSE(converted.value().vectorEncoding);
}
TEST(SourceOptions, MVTEncodingParsed) {
Error error;
auto converted = convertJSON<SourceOptions>(
R"JSON({
"encoding": "mvt"
})JSON",
error);
ASSERT_EQ(converted.value().vectorEncoding, Tileset::VectorEncoding::Mapbox);
ASSERT_FALSE(converted.value().rasterEncoding);
}
TEST(SourceOptions, MLTEncodingParsed) {
Error error;
auto converted = convertJSON<SourceOptions>(
R"JSON({
"encoding": "mlt"
})JSON",
error);
ASSERT_EQ(converted.value().vectorEncoding, Tileset::VectorEncoding::MLT);
ASSERT_FALSE(converted.value().rasterEncoding);
}

View File

@@ -66,7 +66,7 @@ TEST(RasterDEMTile, onError) {
TEST(RasterDEMTile, onParsed) {
RasterDEMTileTest test;
RasterDEMTile tile(OverscaledTileID(0, 0, 0), "testSource", test.tileParameters, test.tileset);
tile.onParsed(std::make_unique<HillshadeBucket>(PremultipliedImage({16, 16}), Tileset::DEMEncoding::Mapbox), 0);
tile.onParsed(std::make_unique<HillshadeBucket>(PremultipliedImage({16, 16}), Tileset::RasterEncoding::Mapbox), 0);
EXPECT_TRUE(tile.isRenderable());
EXPECT_TRUE(tile.isLoaded());
EXPECT_TRUE(tile.isComplete());

View File

@@ -5,7 +5,7 @@
#include <mbgl/test/fake_file_source.hpp>
#include <mbgl/tile/tile_loader_impl.hpp>
#include <mbgl/tile/vector_tile.hpp>
#include <mbgl/tile/vector_tile_data.hpp>
#include <mbgl/tile/vector_mvt_tile_data.hpp>
#include <mbgl/actor/scheduler.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
@@ -38,6 +38,8 @@ public:
renderable = true;
}
void setData(const std::shared_ptr<const std::string>&) override {}
util::SimpleIdentity uniqueId;
};

View File

@@ -1,7 +1,7 @@
#include <mbgl/test/util.hpp>
#include <mbgl/test/fake_file_source.hpp>
#include <mbgl/tile/vector_tile.hpp>
#include <mbgl/tile/vector_tile_data.hpp>
#include <mbgl/tile/vector_mvt_tile.hpp>
#include <mbgl/tile/vector_mvt_tile_data.hpp>
#include <mbgl/tile/tile_loader_impl.hpp>
#include <mbgl/storage/resource_options.hpp>
@@ -25,7 +25,7 @@ using namespace mbgl;
TEST(VectorTile, setError) {
VectorTileTest test;
VectorTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, test.tileset);
VectorMVTTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, test.tileset);
tile.setError(std::make_exception_ptr(std::runtime_error("test")));
EXPECT_FALSE(tile.isRenderable());
EXPECT_TRUE(tile.isLoaded());
@@ -34,7 +34,7 @@ TEST(VectorTile, setError) {
TEST(VectorTile, onError) {
VectorTileTest test;
VectorTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, test.tileset);
VectorMVTTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, test.tileset);
tile.onError(std::make_exception_ptr(std::runtime_error("test")), 0);
EXPECT_FALSE(tile.isRenderable());
@@ -44,7 +44,7 @@ TEST(VectorTile, onError) {
TEST(VectorTile, Issue8542) {
VectorTileTest test;
VectorTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, test.tileset);
VectorMVTTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, test.tileset);
// Query before data is set
std::vector<Feature> result;
@@ -52,7 +52,7 @@ TEST(VectorTile, Issue8542) {
}
TEST(VectorTileData, ParseResults) {
VectorTileData data(std::make_shared<std::string>(util::read_file("test/fixtures/map/issue12432/0-0-0.mvt")));
VectorMVTTileData data(std::make_shared<std::string>(util::read_file("test/fixtures/map/issue12432/0-0-0.mvt")));
std::vector<std::string> layerNames = data.layerNames();
ASSERT_EQ(layerNames.size(), 2u);

2
vendor/PMTiles vendored

2
vendor/glslang vendored

1
vendor/maplibre-tile-spec vendored Submodule

15
vendor/maplibre-tile-spec.cmake vendored Normal file
View File

@@ -0,0 +1,15 @@
set(MLT_WITH_JSON OFF CACHE BOOL "No JSON support" FORCE)
set(MLT_WITH_PROTOZERO OFF CACHE BOOL "No protozero" FORCE)
set(MLT_WITH_FASTPFOR OFF CACHE BOOL "disabled for lack of support for ARMv7 in SIMDE and requirement for SSE on x86" FORCE)
set(MLT_WITH_TESTS OFF CACHE BOOL "Google Test conflicts with Dawn")
set(MLT_WITH_TOOLS OFF CACHE BOOL "Not used")
# This is set by the platform CMakeLists.txt after vendor libraries. If it was set earlier, we could just use it.
set(CMAKE_OSX_DEPLOYMENT_TARGET 14.3)
set(MLT_OSX_DEPLOYMENT_TARGET ${CMAKE_OSX_DEPLOYMENT_TARGET} CACHE STRING "Inherited MacOS/iOS target" FORCE)
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.25")
add_subdirectory(${PROJECT_SOURCE_DIR}/vendor/maplibre-tile-spec/cpp SYSTEM)
else()
add_subdirectory(${PROJECT_SOURCE_DIR}/vendor/maplibre-tile-spec/cpp)
endif()