diff --git a/.mason b/.mason index 3017f674227..c3be66082b8 160000 --- a/.mason +++ b/.mason @@ -1 +1 @@ -Subproject commit 3017f674227ff7a7d915911157cdff62079c3089 +Subproject commit c3be66082b836fe9dc852ee72837e8156661523f diff --git a/benchmark/parse/filter.cpp b/benchmark/parse/filter.cpp index 24314e85840..6b430a9b112 100644 --- a/benchmark/parse/filter.cpp +++ b/benchmark/parse/filter.cpp @@ -9,12 +9,8 @@ #include -#include - using namespace mbgl; -typedef std::multimap Properties; - style::Filter parse(const char* expression) { rapidjson::GenericDocument, rapidjson::CrtAllocator> doc; doc.Parse<0>(expression); @@ -29,7 +25,7 @@ static void Parse_Filter(benchmark::State& state) { static void Parse_EvaluateFilter(benchmark::State& state) { const style::Filter filter = parse(R"FILTER(["==", "foo", "bar"])FILTER"); - const Properties properties = { { "foo", std::string("bar") } }; + const PropertyMap properties = { { "foo", std::string("bar") } }; while (state.KeepRunning()) { filter(FeatureType::Unknown, [&] (const std::string& key) -> optional { diff --git a/configure b/configure index 3c90c5ebbe3..4a62cd1be54 100755 --- a/configure +++ b/configure @@ -118,6 +118,7 @@ print_flags zlib static_libs cflags ldflags print_flags nunicode static_libs cflags ldflags print_flags libzip static_libs cflags ldflags print_flags geometry cflags +print_flags geojson static_libs cflags ldflags print_flags geojsonvt static_libs cflags ldflags print_flags variant cflags print_flags rapidjson static_libs cflags ldflags diff --git a/include/mbgl/style/filter_evaluator.hpp b/include/mbgl/style/filter_evaluator.hpp index e7b6e0f5a0a..cf91fdab1f7 100644 --- a/include/mbgl/style/filter_evaluator.hpp +++ b/include/mbgl/style/filter_evaluator.hpp @@ -151,13 +151,24 @@ class FilterEvaluator { return false; } + bool operator()(const NullValue&, + const NullValue&) const { + // Should be unreachable; null is not currently allowed by the style specification. + assert(false); + return false; + } + bool operator()(const std::vector&, const std::vector&) const { + // Should be unreachable; nested values are not currently allowed by the style specification. + assert(false); return false; } bool operator()(const std::unordered_map&, const std::unordered_map&) const { + // Should be unreachable; nested values are not currently allowed by the style specification. + assert(false); return false; } }; diff --git a/include/mbgl/util/feature.hpp b/include/mbgl/util/feature.hpp index 7747d34ee94..7c5c8d7625c 100644 --- a/include/mbgl/util/feature.hpp +++ b/include/mbgl/util/feature.hpp @@ -7,13 +7,13 @@ namespace mbgl { using Value = mapbox::geometry::value; - +using NullValue = mapbox::geometry::null_value_t; +using PropertyMap = mapbox::geometry::property_map; +using FeatureIdentifier = mapbox::geometry::identifier; class Feature : public mapbox::geometry::feature { public: Feature(geometry_type&& geometry_) : mapbox::geometry::feature { std::move(geometry_) } {} - - optional id; }; } // namespace mbgl diff --git a/include/mbgl/util/geometry.hpp b/include/mbgl/util/geometry.hpp index 7fc2668c2c7..6dc16bc5140 100644 --- a/include/mbgl/util/geometry.hpp +++ b/include/mbgl/util/geometry.hpp @@ -41,4 +41,21 @@ Point convertPoint(const Point& p) { return Point(p.x, p.y); } +struct ToFeatureType { + template + FeatureType operator()(const Point &) const { return FeatureType::Point; } + template + FeatureType operator()(const MultiPoint &) const { return FeatureType::Point; } + template + FeatureType operator()(const LineString &) const { return FeatureType::LineString; } + template + FeatureType operator()(const MultiLineString &) const { return FeatureType::LineString; } + template + FeatureType operator()(const Polygon &) const { return FeatureType::Polygon; } + template + FeatureType operator()(const MultiPolygon &) const { return FeatureType::Polygon; } + template + FeatureType operator()(const mapbox::geometry::geometry_collection &) const { return FeatureType::Unknown; } +}; + } // namespace mbgl diff --git a/mbgl.gypi b/mbgl.gypi index 2507bade781..5eea61fd5ac 100644 --- a/mbgl.gypi +++ b/mbgl.gypi @@ -192,6 +192,7 @@ '<@(protozero_cflags)', '<@(boost_cflags)', '<@(geometry_cflags)', + '<@(geojson_cflags)', '<@(geojsonvt_cflags)', '<@(rapidjson_cflags)', '<@(variant_cflags)', @@ -207,7 +208,7 @@ '<@(opengl_ldflags)', ], 'libraries': [ - '<@(geojsonvt_static_libs)', + '<@(geojson_static_libs)', ], }, diff --git a/platform/android/scripts/configure.sh b/platform/android/scripts/configure.sh index b2bdce556d4..a9a5b25ff7f 100644 --- a/platform/android/scripts/configure.sh +++ b/platform/android/scripts/configure.sh @@ -9,8 +9,9 @@ SQLITE_VERSION=3.9.1 ZLIB_VERSION=system NUNICODE_VERSION=1.6 LIBZIP_VERSION=0.11.2 -GEOMETRY_VERSION=0.5.0 -GEOJSONVT_VERSION=4.1.2-cxx11abi +GEOMETRY_VERSION=0.8.0 +GEOJSON_VERSION=0.1.4 +GEOJSONVT_VERSION=6.1.0 VARIANT_VERSION=1.1.0 RAPIDJSON_VERSION=1.0.2 JNI_HPP_VERSION=2.0.0 diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm index 777b296303e..3bf1e61153d 100644 --- a/platform/darwin/src/MGLFeature.mm +++ b/platform/darwin/src/MGLFeature.mm @@ -118,7 +118,7 @@ - (id)attributeForKey:(NSString *)key { */ class PropertyValueEvaluator { public: - id operator()(const std::nullptr_t &) const { + id operator()(const mbgl::NullValue &) const { return [NSNull null]; } @@ -260,7 +260,7 @@ static CLLocationCoordinate2D toLocationCoordinate2D(const mbgl::Point &point GeometryEvaluator evaluator; MGLShape *shape = mapbox::geometry::geometry::visit(feature.geometry, evaluator); if (feature.id) { - shape.identifier = @(*feature.id); + shape.identifier = mbgl::FeatureIdentifier::visit(*feature.id, PropertyValueEvaluator()); } shape.attributes = attributes; [shapes addObject:shape]; diff --git a/platform/darwin/test/MGLFeatureTests.mm b/platform/darwin/test/MGLFeatureTests.mm index 6cf038d4fb0..13ad8759b0c 100644 --- a/platform/darwin/test/MGLFeatureTests.mm +++ b/platform/darwin/test/MGLFeatureTests.mm @@ -89,7 +89,7 @@ - (void)testPropertyConversion { mapbox::geometry::point point = { -90.066667, 29.95 }; mbgl::Feature pointFeature(point); - pointFeature.id = UINT64_MAX; + pointFeature.id = { UINT64_MAX }; pointFeature.properties["null"] = nullptr; pointFeature.properties["bool"] = true; pointFeature.properties["unsigned int"] = UINT64_MAX; diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index ec0957a4f5e..590a1196009 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -1739,7 +1739,7 @@ "$(sqlite_ldflags)", "$(zlib_ldflags)", "$(opengl_ldflags)", - "$(geojsonvt_static_libs)", + "$(geojson_static_libs)", ); PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.sdk.ios; PRODUCT_NAME = Mapbox; @@ -1779,7 +1779,7 @@ "$(sqlite_ldflags)", "$(zlib_ldflags)", "$(opengl_ldflags)", - "$(geojsonvt_static_libs)", + "$(geojson_static_libs)", ); PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.sdk.ios; PRODUCT_NAME = Mapbox; @@ -1833,7 +1833,7 @@ "$(sqlite_ldflags)", "$(zlib_ldflags)", "$(opengl_ldflags)", - "$(geojsonvt_static_libs)", + "$(geojson_static_libs)", ); PRODUCT_NAME = Mapbox; PUBLIC_HEADERS_FOLDER_PATH = Headers; @@ -1863,7 +1863,7 @@ "$(sqlite_ldflags)", "$(zlib_ldflags)", "$(opengl_ldflags)", - "$(geojsonvt_static_libs)", + "$(geojson_static_libs)", ); PRODUCT_NAME = Mapbox; PUBLIC_HEADERS_FOLDER_PATH = Headers; diff --git a/platform/ios/scripts/configure.sh b/platform/ios/scripts/configure.sh index 408180881ce..a0791e31089 100644 --- a/platform/ios/scripts/configure.sh +++ b/platform/ios/scripts/configure.sh @@ -5,8 +5,9 @@ PROTOZERO_VERSION=1.3.0 BOOST_VERSION=1.60.0 SQLITE_VERSION=system ZLIB_VERSION=system -GEOMETRY_VERSION=0.5.0 -GEOJSONVT_VERSION=4.1.2 +GEOMETRY_VERSION=0.8.0 +GEOJSON_VERSION=0.1.4 +GEOJSONVT_VERSION=6.1.0 VARIANT_VERSION=1.1.0 RAPIDJSON_VERSION=1.0.2 GTEST_VERSION=1.7.0 diff --git a/platform/ios/scripts/package.sh b/platform/ios/scripts/package.sh index f0ca6833897..8bc2a3fd63e 100755 --- a/platform/ios/scripts/package.sh +++ b/platform/ios/scripts/package.sh @@ -119,7 +119,7 @@ if [[ "${BUILD_FOR_DEVICE}" == true ]]; then -o ${OUTPUT}/static/${NAME}.framework/${NAME} \ ${LIBS[@]/#/${PRODUCTS}/${BUILDTYPE}-iphoneos/lib} \ ${LIBS[@]/#/${PRODUCTS}/${BUILDTYPE}-iphonesimulator/lib} \ - `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libgeojsonvt.a` + `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libgeojson.a` cp -rv ${PRODUCTS}/${BUILDTYPE}-iphoneos/${NAME}.bundle ${STATIC_BUNDLE_DIR} fi @@ -149,7 +149,7 @@ else libtool -static -no_warning_for_no_symbols \ -o ${OUTPUT}/static/${NAME}.framework/${NAME} \ ${LIBS[@]/#/${PRODUCTS}/${BUILDTYPE}-iphonesimulator/lib} \ - `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libgeojsonvt.a` + `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libgeojson.a` cp -rv ${PRODUCTS}/${BUILDTYPE}-iphonesimulator/${NAME}.bundle ${STATIC_BUNDLE_DIR} fi diff --git a/platform/linux/scripts/configure.sh b/platform/linux/scripts/configure.sh index 6521fc8ccd4..c4f6dc606d9 100644 --- a/platform/linux/scripts/configure.sh +++ b/platform/linux/scripts/configure.sh @@ -14,8 +14,9 @@ SQLITE_VERSION=3.9.1 LIBUV_VERSION=1.7.5 ZLIB_VERSION=system NUNICODE_VERSION=1.6 -GEOMETRY_VERSION=0.5.0 -GEOJSONVT_VERSION=4.1.2${CXX11ABI:-} +GEOMETRY_VERSION=0.8.0 +GEOJSON_VERSION=0.1.4${CXX11ABI:-} +GEOJSONVT_VERSION=6.1.0 VARIANT_VERSION=1.1.0 RAPIDJSON_VERSION=1.0.2 GTEST_VERSION=1.7.0${CXX11ABI:-} diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj index 7271356f2a8..10f57a369a4 100644 --- a/platform/macos/macos.xcodeproj/project.pbxproj +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -1039,7 +1039,7 @@ OTHER_LDFLAGS = ( "$(zlib_ldflags)", "$(opengl_ldflags)", - "$(geojsonvt_static_libs)", + "$(geojson_static_libs)", ); PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL; PRODUCT_NAME = Mapbox; @@ -1078,7 +1078,7 @@ OTHER_LDFLAGS = ( "$(zlib_ldflags)", "$(opengl_ldflags)", - "$(geojsonvt_static_libs)", + "$(geojson_static_libs)", ); PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL; PRODUCT_NAME = Mapbox; diff --git a/platform/macos/scripts/configure.sh b/platform/macos/scripts/configure.sh index 2952ec25358..47d9b381baa 100644 --- a/platform/macos/scripts/configure.sh +++ b/platform/macos/scripts/configure.sh @@ -8,8 +8,9 @@ GLFW_VERSION=3.1.2 SQLITE_VERSION=3.9.1 ZLIB_VERSION=system NUNICODE_VERSION=1.6 -GEOMETRY_VERSION=0.5.0 -GEOJSONVT_VERSION=4.1.2 +GEOMETRY_VERSION=0.8.0 +GEOJSON_VERSION=0.1.4 +GEOJSONVT_VERSION=6.1.0 VARIANT_VERSION=1.1.0 RAPIDJSON_VERSION=1.0.2 GTEST_VERSION=1.7.0 diff --git a/platform/node/src/node_feature.cpp b/platform/node/src/node_feature.cpp index 1a5e31fe971..6620cf18523 100644 --- a/platform/node/src/node_feature.cpp +++ b/platform/node/src/node_feature.cpp @@ -6,9 +6,10 @@ using namespace mapbox::geometry; using Value = mbgl::Value; using Feature = mbgl::Feature; +using FeatureIdentifier = mbgl::FeatureIdentifier; using Geometry = mbgl::Feature::geometry_type; using GeometryCollection = mapbox::geometry::geometry_collection; -using Properties = mbgl::Feature::property_map; +using Properties = mbgl::PropertyMap; template struct ToType { @@ -76,7 +77,7 @@ struct ToCoordinatesOrGeometries { }; struct ToValue { - v8::Local operator()(std::nullptr_t) { + v8::Local operator()(mbgl::NullValue) { Nan::EscapableHandleScope scope; return scope.Escape(Nan::Null()); } @@ -159,7 +160,7 @@ v8::Local toJS(const Feature& feature) { Nan::Set(result, Nan::New("properties").ToLocalChecked(), toJS(feature.properties)); if (feature.id) { - Nan::Set(result, Nan::New("id").ToLocalChecked(), Nan::New(double(*feature.id))); + Nan::Set(result, Nan::New("id").ToLocalChecked(), FeatureIdentifier::visit(*feature.id, ToValue())); } return scope.Escape(result); diff --git a/platform/node/src/node_feature.hpp b/platform/node/src/node_feature.hpp index 7973ee19d4f..8d1eceba38f 100644 --- a/platform/node/src/node_feature.hpp +++ b/platform/node/src/node_feature.hpp @@ -13,6 +13,6 @@ namespace node_mbgl { v8::Local toJS(const mbgl::Value&); v8::Local toJS(const mbgl::Feature&); v8::Local toJS(const mbgl::Feature::geometry_type&); -v8::Local toJS(const mbgl::Feature::property_map&); +v8::Local toJS(const mbgl::PropertyMap&); } diff --git a/platform/qt/scripts/configure.sh b/platform/qt/scripts/configure.sh index 461c1cc1b3e..6b501d271cd 100644 --- a/platform/qt/scripts/configure.sh +++ b/platform/qt/scripts/configure.sh @@ -5,8 +5,9 @@ CXX11ABI=${CXX11ABI:-$(scripts/check-cxx11abi.sh)} UNIQUE_RESOURCE_VERSION=dev PROTOZERO_VERSION=1.3.0 BOOST_VERSION=1.60.0 -GEOMETRY_VERSION=0.5.0 -GEOJSONVT_VERSION=4.1.2${CXX11ABI:-} +GEOMETRY_VERSION=0.8.0 +GEOJSON_VERSION=0.1.4${CXX11ABI:-} +GEOJSONVT_VERSION=6.1.0 GTEST_VERSION=1.7.0${CXX11ABI:-} LIBJPEG_TURBO_VERSION=1.4.2 NUNICODE_VERSION=1.6 diff --git a/src/mbgl/annotation/fill_annotation_impl.cpp b/src/mbgl/annotation/fill_annotation_impl.cpp index 8146c68a533..fe520451f7e 100644 --- a/src/mbgl/annotation/fill_annotation_impl.cpp +++ b/src/mbgl/annotation/fill_annotation_impl.cpp @@ -9,7 +9,7 @@ using namespace style; FillAnnotationImpl::FillAnnotationImpl(AnnotationID id_, FillAnnotation annotation_, uint8_t maxZoom_) : ShapeAnnotationImpl(id_, maxZoom_), - annotation(std::move(annotation_)) { + annotation({ ShapeAnnotationGeometry::visit(annotation_.geometry, CloseShapeAnnotation{}), annotation_.opacity, annotation_.color, annotation_.outlineColor }) { } void FillAnnotationImpl::updateStyle(Style& style) const { diff --git a/src/mbgl/annotation/line_annotation_impl.cpp b/src/mbgl/annotation/line_annotation_impl.cpp index bc7b8df50e0..f18ca9fadca 100644 --- a/src/mbgl/annotation/line_annotation_impl.cpp +++ b/src/mbgl/annotation/line_annotation_impl.cpp @@ -9,7 +9,7 @@ using namespace style; LineAnnotationImpl::LineAnnotationImpl(AnnotationID id_, LineAnnotation annotation_, uint8_t maxZoom_) : ShapeAnnotationImpl(id_, maxZoom_), - annotation(std::move(annotation_)) { + annotation({ ShapeAnnotationGeometry::visit(annotation_.geometry, CloseShapeAnnotation{}), annotation_.opacity, annotation_.width, annotation_.color }) { } void LineAnnotationImpl::updateStyle(Style& style) const { diff --git a/src/mbgl/annotation/shape_annotation_impl.cpp b/src/mbgl/annotation/shape_annotation_impl.cpp index f22debdd812..620b1acc768 100644 --- a/src/mbgl/annotation/shape_annotation_impl.cpp +++ b/src/mbgl/annotation/shape_annotation_impl.cpp @@ -1,5 +1,3 @@ -#include - #include #include #include @@ -7,6 +5,7 @@ #include #include #include +#include namespace mbgl { @@ -19,86 +18,16 @@ ShapeAnnotationImpl::ShapeAnnotationImpl(const AnnotationID id_, const uint8_t m layerID("com.mapbox.annotations.shape." + util::toString(id)) { } -struct ToGeoJSONVT { - const double tolerance; - - ToGeoJSONVT(const double tolerance_) - : tolerance(tolerance_) { - } - - geojsonvt::ProjectedFeature operator()(const LineString& line) const { - geojsonvt::ProjectedRings converted; - converted.push_back(convertPoints(geojsonvt::ProjectedFeatureType::LineString, line)); - return convertFeature(geojsonvt::ProjectedFeatureType::LineString, converted); - } - - geojsonvt::ProjectedFeature operator()(const Polygon& polygon) const { - geojsonvt::ProjectedRings converted; - for (const auto& ring : polygon) { - converted.push_back(convertPoints(geojsonvt::ProjectedFeatureType::Polygon, ring)); - } - return convertFeature(geojsonvt::ProjectedFeatureType::Polygon, converted); - } - - geojsonvt::ProjectedFeature operator()(const MultiLineString& lines) const { - geojsonvt::ProjectedRings converted; - for (const auto& line : lines) { - converted.push_back(convertPoints(geojsonvt::ProjectedFeatureType::LineString, line)); - } - return convertFeature(geojsonvt::ProjectedFeatureType::LineString, converted); - } - - geojsonvt::ProjectedFeature operator()(const MultiPolygon& polygons) const { - geojsonvt::ProjectedRings converted; - for (const auto& polygon : polygons) { - for (const auto& ring : polygon) { - converted.push_back(convertPoints(geojsonvt::ProjectedFeatureType::Polygon, ring)); - } - } - return convertFeature(geojsonvt::ProjectedFeatureType::Polygon, converted); - } - -private: - geojsonvt::LonLat convertPoint(const Point& p) const { - return { - util::wrap(p.x, -util::LONGITUDE_MAX, util::LONGITUDE_MAX), - util::clamp(p.y, -util::LATITUDE_MAX, util::LATITUDE_MAX) - }; - } - - geojsonvt::ProjectedRing convertPoints(geojsonvt::ProjectedFeatureType type, const std::vector>& points) const { - std::vector converted; - - for (const auto& p : points) { - converted.push_back(convertPoint(p)); - } - - assert(points.size() > 0); - if (type == geojsonvt::ProjectedFeatureType::Polygon && points.size() > 0 && points.front() != points.back()) { - converted.push_back(converted.front()); - } - - return geojsonvt::Convert::projectRing(converted, tolerance); - } - - geojsonvt::ProjectedFeature convertFeature(geojsonvt::ProjectedFeatureType type, const geojsonvt::ProjectedRings& rings) const { - return geojsonvt::Convert::create(geojsonvt::Tags(), type, rings); - } -}; - void ShapeAnnotationImpl::updateTileData(const CanonicalTileID& tileID, AnnotationTileData& data) { static const double baseTolerance = 4; if (!shapeTiler) { - const uint64_t maxAmountOfTileFeatures = (1ull << maxZoom) * util::EXTENT; - const double tolerance = baseTolerance / maxAmountOfTileFeatures; - - std::vector features = { - ShapeAnnotationGeometry::visit(geometry(), ToGeoJSONVT(tolerance)) - }; - + mapbox::geometry::feature_collection features; + features.emplace_back(ShapeAnnotationGeometry::visit(geometry(), [] (auto&& geom) { + return Feature(std::move(geom)); + })); mapbox::geojsonvt::Options options; - options.maxZoom = maxZoom; + options.maxZoom = util::clamp(maxZoom, 0, 18); options.buffer = 255u; options.extent = util::EXTENT; options.tolerance = baseTolerance; @@ -106,34 +35,20 @@ void ShapeAnnotationImpl::updateTileData(const CanonicalTileID& tileID, Annotati } const auto& shapeTile = shapeTiler->getTile(tileID.z, tileID.x, tileID.y); - if (!shapeTile) + if (shapeTile.features.empty()) return; AnnotationTileLayer& layer = *data.layers.emplace(layerID, std::make_unique(layerID)).first->second; - for (auto& shapeFeature : shapeTile.features) { - FeatureType featureType = FeatureType::Unknown; - - if (shapeFeature.type == geojsonvt::TileFeatureType::LineString) { - featureType = FeatureType::LineString; - } else if (shapeFeature.type == geojsonvt::TileFeatureType::Polygon) { - featureType = FeatureType::Polygon; - } + ToGeometryCollection toGeometryCollection; + ToFeatureType toFeatureType; + for (const auto& shapeFeature : shapeTile.features) { + FeatureType featureType = apply_visitor(toFeatureType, shapeFeature.geometry); + GeometryCollection renderGeometry = apply_visitor(toGeometryCollection, shapeFeature.geometry); assert(featureType != FeatureType::Unknown); - GeometryCollection renderGeometry; - for (auto& shapeRing : shapeFeature.tileGeometry.get()) { - GeometryCoordinates renderLine; - - for (auto& shapePoint : shapeRing) { - renderLine.emplace_back(shapePoint.x, shapePoint.y); - } - - renderGeometry.push_back(renderLine); - } - // https://github.com/mapbox/geojson-vt-cpp/issues/44 if (featureType == FeatureType::Polygon) { renderGeometry = fixupPolygons(renderGeometry); diff --git a/src/mbgl/annotation/shape_annotation_impl.hpp b/src/mbgl/annotation/shape_annotation_impl.hpp index 1b8fcd57772..800b4ec3134 100644 --- a/src/mbgl/annotation/shape_annotation_impl.hpp +++ b/src/mbgl/annotation/shape_annotation_impl.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -32,4 +33,33 @@ class ShapeAnnotationImpl { std::unique_ptr shapeTiler; }; +struct CloseShapeAnnotation { + ShapeAnnotationGeometry operator()(const mbgl::LineString &geom) const { + return geom; + } + ShapeAnnotationGeometry operator()(const mbgl::MultiLineString &geom) const { + return geom; + } + ShapeAnnotationGeometry operator()(const mbgl::Polygon &geom) const { + mbgl::Polygon closed = geom; + for (auto &ring : closed) { + if (!ring.empty() && ring.front() != ring.back()) { + ring.emplace_back(ring.front()); + } + } + return closed; + } + ShapeAnnotationGeometry operator()(const mbgl::MultiPolygon &geom) const { + mbgl::MultiPolygon closed = geom; + for (auto &polygon : closed) { + for (auto &ring : polygon) { + if (!ring.empty() && ring.front() != ring.back()) { + ring.emplace_back(ring.front()); + } + } + } + return closed; + } +}; + } // namespace mbgl diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp index b9744d193aa..d71df283787 100644 --- a/src/mbgl/style/sources/geojson_source_impl.cpp +++ b/src/mbgl/style/sources/geojson_source_impl.cpp @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include @@ -18,6 +20,7 @@ using namespace mapbox::geojsonvt; namespace mbgl { namespace style { namespace conversion { + template <> Result convertGeoJSON(const JSValue& value) { Options options; @@ -25,7 +28,8 @@ Result convertGeoJSON(const JSValue& value) { options.extent = util::EXTENT; try { - return GeoJSON { std::make_unique(Convert::convert(value, 0), options) }; + const auto geojson = mapbox::geojson::convert(value); + return GeoJSON { std::make_unique(geojson, options) }; } catch (const std::exception& ex) { return Error { ex.what() }; } @@ -82,7 +86,8 @@ void GeoJSONSource::Impl::load(FileSource& fileSource) { Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s", geoJSON.error().message); // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for // tiles to load. - urlOrGeoJSON = GeoJSON { std::make_unique(std::vector()) }; + mapbox::geojson::feature_collection features; + urlOrGeoJSON = GeoJSON { std::make_unique(features) }; } else { urlOrGeoJSON = std::move(*geoJSON); } diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp index e2f8b69e4d4..0dc4ac91072 100644 --- a/src/mbgl/tile/geojson_tile.cpp +++ b/src/mbgl/tile/geojson_tile.cpp @@ -11,16 +11,16 @@ namespace mbgl { class GeoJSONTileFeature : public GeometryTileFeature { public: - GeoJSONTileFeature(FeatureType, GeometryCollection&&, Feature::property_map&&); + GeoJSONTileFeature(FeatureType, GeometryCollection&&, PropertyMap&&); FeatureType getType() const override; optional getValue(const std::string&) const override; - Feature::property_map getProperties() const override { return properties; } + PropertyMap getProperties() const override { return properties; } GeometryCollection getGeometries() const override; private: const FeatureType type; const GeometryCollection geometries; - const Feature::property_map properties; + const PropertyMap properties; }; class GeoJSONTileLayer : public GeometryTileLayer { @@ -49,52 +49,28 @@ class GeoJSONTileData : public GeometryTileData { std::unique_ptr convertTile(const mapbox::geojsonvt::Tile& tile) { std::shared_ptr layer; - if (tile) { + if (!tile.features.empty()) { std::vector> features; GeometryCoordinates line; + ToFeatureType toFeatureType; + ToGeometryCollection toGeometryCollection; + for (auto& feature : tile.features) { - const FeatureType featureType = - (feature.type == mapbox::geojsonvt::TileFeatureType::Point - ? FeatureType::Point - : (feature.type == mapbox::geojsonvt::TileFeatureType::LineString - ? FeatureType::LineString - : (feature.type == mapbox::geojsonvt::TileFeatureType::Polygon - ? FeatureType::Polygon - : FeatureType::Unknown))); + const FeatureType featureType = apply_visitor(toFeatureType, feature.geometry); + if (featureType == FeatureType::Unknown) { continue; } - GeometryCollection geometry; - - // Flatten the geometry; GeoJSONVT distinguishes between a Points array and Rings array - // (Points = GeoJSON types Point, MultiPoint, LineString) - // (Rings = GeoJSON types MultiLineString, Polygon, MultiPolygon) - // However, in Mapbox GL, we use one structure for both types, and just have one outer - // element for Points. - if (feature.tileGeometry.is()) { - line.clear(); - for (auto& point : feature.tileGeometry.get()) { - line.emplace_back(point.x, point.y); - } - geometry.emplace_back(std::move(line)); - } else if (feature.tileGeometry.is()) { - for (auto& ring : feature.tileGeometry.get()) { - line.clear(); - for (auto& point : ring) { - line.emplace_back(point.x, point.y); - } - geometry.emplace_back(std::move(line)); - } - } + GeometryCollection geometry = apply_visitor(toGeometryCollection, feature.geometry); // https://github.com/mapbox/geojson-vt-cpp/issues/44 if (featureType == FeatureType::Polygon) { geometry = fixupPolygons(geometry); } - Feature::property_map properties{ feature.tags.begin(), feature.tags.end() }; + PropertyMap properties = feature.properties; features.emplace_back(std::make_shared( featureType, std::move(geometry), std::move(properties))); @@ -118,7 +94,7 @@ void GeoJSONTile::setNecessity(Necessity) {} GeoJSONTileFeature::GeoJSONTileFeature(FeatureType type_, GeometryCollection&& geometries_, - Feature::property_map&& properties_) + PropertyMap&& properties_) : type(type_), geometries(std::move(geometries_)), properties(std::move(properties_)) { } diff --git a/src/mbgl/tile/geometry_tile_data.hpp b/src/mbgl/tile/geometry_tile_data.hpp index 1dc22e0c55a..4055a80ecf3 100644 --- a/src/mbgl/tile/geometry_tile_data.hpp +++ b/src/mbgl/tile/geometry_tile_data.hpp @@ -14,6 +14,7 @@ #include #include #include +#include namespace mbgl { @@ -41,8 +42,8 @@ class GeometryTileFeature : private util::noncopyable { virtual ~GeometryTileFeature() = default; virtual FeatureType getType() const = 0; virtual optional getValue(const std::string& key) const = 0; - virtual Feature::property_map getProperties() const { return Feature::property_map(); } - virtual optional getID() const { return {}; } + virtual PropertyMap getProperties() const { return PropertyMap(); } + virtual optional getID() const { return {}; } virtual GeometryCollection getGeometries() const = 0; }; @@ -73,4 +74,70 @@ Feature convertFeature(const GeometryTileFeature&, const CanonicalTileID&); // The result is guaranteed to have correctly wound, strictly simple rings. GeometryCollection fixupPolygons(const GeometryCollection&); +struct ToGeometryCollection { + GeometryCollection operator()(const mapbox::geometry::point& geom) const { + return { { geom } }; + } + GeometryCollection operator()(const mapbox::geometry::multi_point& geom) const { + GeometryCoordinates coordinates; + coordinates.reserve(geom.size()); + for (const auto& point : geom) { + coordinates.emplace_back(point); + } + return { coordinates }; + } + GeometryCollection operator()(const mapbox::geometry::line_string& geom) const { + GeometryCoordinates coordinates; + coordinates.reserve(geom.size()); + for (const auto& point : geom) { + coordinates.emplace_back(point); + } + return { coordinates }; + } + GeometryCollection operator()(const mapbox::geometry::multi_line_string& geom) const { + GeometryCollection collection; + collection.reserve(geom.size()); + for (const auto& ring : geom) { + GeometryCoordinates coordinates; + coordinates.reserve(ring.size()); + for (const auto& point : ring) { + coordinates.emplace_back(point); + } + collection.push_back(std::move(coordinates)); + } + return collection; + } + GeometryCollection operator()(const mapbox::geometry::polygon& geom) const { + GeometryCollection collection; + collection.reserve(geom.size()); + for (const auto& ring : geom) { + GeometryCoordinates coordinates; + coordinates.reserve(ring.size()); + for (const auto& point : ring) { + coordinates.emplace_back(point); + } + collection.push_back(std::move(coordinates)); + } + return collection; + } + GeometryCollection operator()(const mapbox::geometry::multi_polygon& geom) const { + GeometryCollection collection; + for (auto& polygon : geom) { + for (auto& ring : polygon) { + GeometryCoordinates coordinates; + coordinates.reserve(ring.size()); + for (auto& point : ring) { + coordinates.emplace_back(point); + } + collection.push_back(std::move(coordinates)); + } + } + return collection; + } + GeometryCollection operator()(const mapbox::geometry::geometry_collection&) const { + GeometryCollection collection; + return collection; + } +}; + } // namespace mbgl diff --git a/src/mbgl/tile/vector_tile.cpp b/src/mbgl/tile/vector_tile.cpp index 1f924a45e14..6a3c51c05dc 100644 --- a/src/mbgl/tile/vector_tile.cpp +++ b/src/mbgl/tile/vector_tile.cpp @@ -24,12 +24,12 @@ class VectorTileFeature : public GeometryTileFeature { FeatureType getType() const override { return type; } optional getValue(const std::string&) const override; std::unordered_map getProperties() const override; - optional getID() const override; + optional getID() const override; GeometryCollection getGeometries() const override; private: const VectorTileLayer& layer; - optional id; + optional id; FeatureType type = FeatureType::Unknown; packed_iter_type tags_iter; packed_iter_type geometry_iter; @@ -120,7 +120,7 @@ VectorTileFeature::VectorTileFeature(protozero::pbf_reader feature_pbf, const Ve while (feature_pbf.next()) { switch (feature_pbf.tag()) { case 1: // id - id = feature_pbf.get_uint64(); + id = { feature_pbf.get_uint64() }; break; case 2: // tags tags_iter = feature_pbf.get_packed_uint32(); @@ -185,7 +185,7 @@ std::unordered_map VectorTileFeature::getProperties() const { return properties; } -optional VectorTileFeature::getID() const { +optional VectorTileFeature::getID() const { return id; } diff --git a/test/fixtures/style_parser/geojson-data-inline.style.json b/test/fixtures/style_parser/geojson-data-inline.style.json index fc4fe97c784..a5d19eea600 100644 --- a/test/fixtures/style_parser/geojson-data-inline.style.json +++ b/test/fixtures/style_parser/geojson-data-inline.style.json @@ -3,7 +3,7 @@ "sources": { "mapbox": { "type": "geojson", - "data": { "type": "Feature", "geometry": { "type": "Point", "coordinates": [100.0, 0.0] } } + "data": { "type": "Feature", "geometry": { "type": "Point", "coordinates": [100.0, 0.0] }, "properties": {} } } } } diff --git a/test/style/filter.cpp b/test/style/filter.cpp index 2d26a8eb610..53504d84aee 100644 --- a/test/style/filter.cpp +++ b/test/style/filter.cpp @@ -8,20 +8,16 @@ #include -#include - using namespace mbgl; using namespace mbgl::style; -typedef std::multimap Properties; - Filter parse(const char * expression) { rapidjson::GenericDocument, rapidjson::CrtAllocator> doc; doc.Parse<0>(expression); return *conversion::convert(doc); } -bool evaluate(const Filter& filter, const Properties& properties, FeatureType type = FeatureType::Unknown) { +bool evaluate(const Filter& filter, const PropertyMap& properties, FeatureType type = FeatureType::Unknown) { return filter(type, [&] (const std::string& key) -> optional { auto it = properties.find(key); if (it == properties.end()) @@ -47,6 +43,7 @@ TEST(Filter, EqualsNumber) { ASSERT_FALSE(evaluate(f, {{ "foo", std::string("0") }})); ASSERT_FALSE(evaluate(f, {{ "foo", false }})); ASSERT_FALSE(evaluate(f, {{ "foo", true }})); + ASSERT_FALSE(evaluate(f, {{ "foo", nullptr }})); ASSERT_FALSE(evaluate(f, {{}})); }