[core] geometry@0.8.0 / geojsonvt@6.0.0 (#5514)

* [core] geometry.hpp 0.8.0

* geojsonvt @ 6.0.0

* Update platform deps, build scripts

* Perf optimizations/cleanup

* Rebase in geometry@080

* D.R.Y. etc

* Ensure fill annotation geometries have closed rings.

* Optimizations

* Update to geojsonvt @ 6.1.0 for clean handoff between geojson parsing and geojsonvt

* Apply close multi/poly geoms for line annotations as well
This commit is contained in:
Young Hahn
2016-07-06 17:29:34 -04:00
committed by GitHub
parent 903d609b40
commit 71a3b1d0db
29 changed files with 206 additions and 184 deletions

2
.mason

Submodule .mason updated: 3017f67422...c3be66082b

View File

@@ -9,12 +9,8 @@
#include <rapidjson/document.h>
#include <map>
using namespace mbgl;
typedef std::multimap<std::string, Value> Properties;
style::Filter parse(const char* expression) {
rapidjson::GenericDocument<rapidjson::UTF8<>, 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<Value> {

1
configure vendored
View File

@@ -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

View File

@@ -151,13 +151,24 @@ private:
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<Value>&,
const std::vector<Value>&) const {
// Should be unreachable; nested values are not currently allowed by the style specification.
assert(false);
return false;
}
bool operator()(const std::unordered_map<std::string, Value>&,
const std::unordered_map<std::string, Value>&) const {
// Should be unreachable; nested values are not currently allowed by the style specification.
assert(false);
return false;
}
};

View File

@@ -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<double> {
public:
Feature(geometry_type&& geometry_)
: mapbox::geometry::feature<double> { std::move(geometry_) } {}
optional<uint64_t> id;
};
} // namespace mbgl

View File

@@ -41,4 +41,21 @@ Point<S> convertPoint(const Point<T>& p) {
return Point<S>(p.x, p.y);
}
struct ToFeatureType {
template <class T>
FeatureType operator()(const Point<T> &) const { return FeatureType::Point; }
template <class T>
FeatureType operator()(const MultiPoint<T> &) const { return FeatureType::Point; }
template <class T>
FeatureType operator()(const LineString<T> &) const { return FeatureType::LineString; }
template <class T>
FeatureType operator()(const MultiLineString<T> &) const { return FeatureType::LineString; }
template <class T>
FeatureType operator()(const Polygon<T> &) const { return FeatureType::Polygon; }
template <class T>
FeatureType operator()(const MultiPolygon<T> &) const { return FeatureType::Polygon; }
template <class T>
FeatureType operator()(const mapbox::geometry::geometry_collection<T> &) const { return FeatureType::Unknown; }
};
} // namespace mbgl

View File

@@ -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)',
],
},

View File

@@ -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

View File

@@ -118,7 +118,7 @@
*/
class PropertyValueEvaluator {
public:
id operator()(const std::nullptr_t &) const {
id operator()(const mbgl::NullValue &) const {
return [NSNull null];
}
@@ -260,7 +260,7 @@ NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vec
GeometryEvaluator<double> evaluator;
MGLShape <MGLFeaturePrivate> *shape = mapbox::geometry::geometry<double>::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];

View File

@@ -89,7 +89,7 @@
mapbox::geometry::point<double> 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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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:-}

View File

@@ -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;

View File

@@ -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

View File

@@ -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<double>;
using Properties = mbgl::Feature::property_map;
using Properties = mbgl::PropertyMap;
template <class T>
struct ToType {
@@ -76,7 +77,7 @@ public:
};
struct ToValue {
v8::Local<v8::Value> operator()(std::nullptr_t) {
v8::Local<v8::Value> operator()(mbgl::NullValue) {
Nan::EscapableHandleScope scope;
return scope.Escape(Nan::Null());
}
@@ -159,7 +160,7 @@ v8::Local<v8::Object> 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);

View File

@@ -13,6 +13,6 @@ namespace node_mbgl {
v8::Local<v8::Value> toJS(const mbgl::Value&);
v8::Local<v8::Object> toJS(const mbgl::Feature&);
v8::Local<v8::Object> toJS(const mbgl::Feature::geometry_type&);
v8::Local<v8::Object> toJS(const mbgl::Feature::property_map&);
v8::Local<v8::Object> toJS(const mbgl::PropertyMap&);
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -1,5 +1,3 @@
#include <mapbox/geojsonvt/convert.hpp>
#include <mbgl/annotation/shape_annotation_impl.hpp>
#include <mbgl/annotation/annotation_tile.hpp>
#include <mbgl/tile/tile_id.hpp>
@@ -7,6 +5,7 @@
#include <mbgl/math/clamp.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/geometry.hpp>
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<double>& line) const {
geojsonvt::ProjectedRings converted;
converted.push_back(convertPoints(geojsonvt::ProjectedFeatureType::LineString, line));
return convertFeature(geojsonvt::ProjectedFeatureType::LineString, converted);
}
geojsonvt::ProjectedFeature operator()(const Polygon<double>& 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<double>& 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<double>& 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<double>& 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<Point<double>>& points) const {
std::vector<geojsonvt::LonLat> 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<geojsonvt::ProjectedFeature> features = {
ShapeAnnotationGeometry::visit(geometry(), ToGeoJSONVT(tolerance))
};
mapbox::geometry::feature_collection<double> 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<uint8_t>(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<AnnotationTileLayer>(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<geojsonvt::TileRings>()) {
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);

View File

@@ -3,6 +3,7 @@
#include <mapbox/geojsonvt.hpp>
#include <mbgl/annotation/annotation.hpp>
#include <mbgl/util/geometry.hpp>
#include <string>
#include <memory>
@@ -32,4 +33,33 @@ public:
std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> shapeTiler;
};
struct CloseShapeAnnotation {
ShapeAnnotationGeometry operator()(const mbgl::LineString<double> &geom) const {
return geom;
}
ShapeAnnotationGeometry operator()(const mbgl::MultiLineString<double> &geom) const {
return geom;
}
ShapeAnnotationGeometry operator()(const mbgl::Polygon<double> &geom) const {
mbgl::Polygon<double> 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<double> &geom) const {
mbgl::MultiPolygon<double> 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

View File

@@ -6,6 +6,8 @@
#include <mbgl/platform/log.hpp>
#include <mbgl/util/rapidjson.hpp>
#include <mapbox/geojson.hpp>
#include <mapbox/geojson/rapidjson.hpp>
#include <mapbox/geojsonvt.hpp>
#include <mapbox/geojsonvt/convert.hpp>
@@ -18,6 +20,7 @@ using namespace mapbox::geojsonvt;
namespace mbgl {
namespace style {
namespace conversion {
template <>
Result<GeoJSON> convertGeoJSON(const JSValue& value) {
Options options;
@@ -25,7 +28,8 @@ Result<GeoJSON> convertGeoJSON(const JSValue& value) {
options.extent = util::EXTENT;
try {
return GeoJSON { std::make_unique<GeoJSONVT>(Convert::convert(value, 0), options) };
const auto geojson = mapbox::geojson::convert(value);
return GeoJSON { std::make_unique<GeoJSONVT>(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<GeoJSONVT>(std::vector<ProjectedFeature>()) };
mapbox::geojson::feature_collection features;
urlOrGeoJSON = GeoJSON { std::make_unique<GeoJSONVT>(features) };
} else {
urlOrGeoJSON = std::move(*geoJSON);
}

View File

@@ -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<Value> 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 @@ private:
std::unique_ptr<GeoJSONTileData> convertTile(const mapbox::geojsonvt::Tile& tile) {
std::shared_ptr<GeoJSONTileLayer> layer;
if (tile) {
if (!tile.features.empty()) {
std::vector<std::shared_ptr<const GeoJSONTileFeature>> 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<mapbox::geojsonvt::TilePoints>()) {
line.clear();
for (auto& point : feature.tileGeometry.get<mapbox::geojsonvt::TilePoints>()) {
line.emplace_back(point.x, point.y);
}
geometry.emplace_back(std::move(line));
} else if (feature.tileGeometry.is<mapbox::geojsonvt::TileRings>()) {
for (auto& ring : feature.tileGeometry.get<mapbox::geojsonvt::TileRings>()) {
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<GeoJSONTileFeature>(
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_)) {
}

View File

@@ -14,6 +14,7 @@
#include <vector>
#include <unordered_map>
#include <functional>
#include <iostream>
namespace mbgl {
@@ -41,8 +42,8 @@ public:
virtual ~GeometryTileFeature() = default;
virtual FeatureType getType() const = 0;
virtual optional<Value> getValue(const std::string& key) const = 0;
virtual Feature::property_map getProperties() const { return Feature::property_map(); }
virtual optional<uint64_t> getID() const { return {}; }
virtual PropertyMap getProperties() const { return PropertyMap(); }
virtual optional<FeatureIdentifier> 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<int16_t>& geom) const {
return { { geom } };
}
GeometryCollection operator()(const mapbox::geometry::multi_point<int16_t>& 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<int16_t>& 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<int16_t>& 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<int16_t>& 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<int16_t>& 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<int16_t>&) const {
GeometryCollection collection;
return collection;
}
};
} // namespace mbgl

View File

@@ -24,12 +24,12 @@ public:
FeatureType getType() const override { return type; }
optional<Value> getValue(const std::string&) const override;
std::unordered_map<std::string,Value> getProperties() const override;
optional<uint64_t> getID() const override;
optional<FeatureIdentifier> getID() const override;
GeometryCollection getGeometries() const override;
private:
const VectorTileLayer& layer;
optional<uint64_t> id;
optional<FeatureIdentifier> 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<std::string,Value> VectorTileFeature::getProperties() const {
return properties;
}
optional<uint64_t> VectorTileFeature::getID() const {
optional<FeatureIdentifier> VectorTileFeature::getID() const {
return id;
}

View File

@@ -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": {} }
}
}
}

View File

@@ -8,20 +8,16 @@
#include <rapidjson/document.h>
#include <map>
using namespace mbgl;
using namespace mbgl::style;
typedef std::multimap<std::string, mbgl::Value> Properties;
Filter parse(const char * expression) {
rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> doc;
doc.Parse<0>(expression);
return *conversion::convert<Filter>(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<Value> {
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, {{}}));
}