summaryrefslogtreecommitdiff
path: root/platform/darwin/src/MGLFeature.mm
diff options
context:
space:
mode:
Diffstat (limited to 'platform/darwin/src/MGLFeature.mm')
-rw-r--r--platform/darwin/src/MGLFeature.mm244
1 files changed, 244 insertions, 0 deletions
diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm
new file mode 100644
index 0000000000..68c57a193a
--- /dev/null
+++ b/platform/darwin/src/MGLFeature.mm
@@ -0,0 +1,244 @@
+#import "MGLFeature_Private.h"
+
+#import "MGLPointAnnotation.h"
+#import "MGLPolyline.h"
+#import "MGLPolygon.h"
+
+#import "MGLMultiPoint_Private.h"
+
+class PropertyValueEvaluator {
+public:
+ PropertyValueEvaluator() {}
+
+ id operator()(const std::nullptr_t &) const {
+ return [NSNull null];
+ }
+
+ id operator()(const bool &value) const {
+ return value ? @YES : @NO;
+ }
+
+ id operator()(const uint64_t &value) const {
+ return @(value);
+ }
+
+ id operator()(const int64_t &value) const {
+ return @(value);
+ }
+
+ id operator()(const double &value) const {
+ return @(value);
+ }
+
+ id operator()(const std::string &value) const {
+ return @(value.c_str());
+ }
+
+ id operator()(const std::vector<mbgl::Value> &values) const {
+ std::vector<id> objects;
+ objects.reserve(values.size());
+ std::transform(values.begin(), values.end(), std::back_inserter(objects), ^id (const mbgl::Value &value) {
+ PropertyValueEvaluator evaluator;
+ return mbgl::Value::visit(value, evaluator);
+ });
+ return [NSArray arrayWithObjects:&objects[0] count:objects.size()];
+ }
+
+ id operator()(const std::unordered_map<std::string, mbgl::Value> &items) const {
+ std::vector<NSString *> keys;
+ keys.reserve(items.size());
+ std::vector<id> objects;
+ objects.reserve(items.size());
+ for (auto &item : items) {
+ keys.push_back(@(item.first.c_str()));
+ PropertyValueEvaluator evaluator;
+ objects.push_back(mbgl::Value::visit(item.second, evaluator));
+ }
+ return [NSDictionary dictionaryWithObjects:&objects[0] forKeys:&keys[0] count:keys.size()];
+ }
+};
+
+template <typename T>
+class GeometryEvaluator {
+public:
+ GeometryEvaluator()
+ : attributes([NSMutableDictionary dictionary]) {}
+
+ GeometryEvaluator(const mbgl::Feature &feature)
+ : tag(feature.id ? @(*feature.id) : nullptr),
+ attributes([NSMutableDictionary dictionaryWithCapacity:feature.properties.size()]) {
+ for (auto &pair : feature.properties) {
+ auto &value = pair.second;
+ PropertyValueEvaluator evaluator;
+ attributes[@(pair.first.c_str())] = mbgl::Value::visit(value, evaluator);
+ }
+ }
+
+ MGLShape <MGLFeature> * operator()(const mapbox::geometry::point<T> &geometry) const {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ feature.coordinate = coordinateFromPoint(geometry);
+ feature.identifier = tag;
+ feature.attributes = attributes;
+ return feature;
+ }
+
+ MGLShape <MGLFeature> * operator()(const mapbox::geometry::line_string<T> &geometry) const {
+ std::vector<CLLocationCoordinate2D> coordinates;
+ coordinates.reserve(geometry.size());
+ std::transform(geometry.begin(), geometry.end(), std::back_inserter(coordinates), coordinateFromPoint);
+
+ MGLPolylineFeature *feature = [[MGLPolylineFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()];
+ feature.identifier = tag;
+ feature.attributes = attributes;
+ return feature;
+ }
+
+ MGLShape <MGLFeature> * operator()(const mapbox::geometry::polygon<T> &geometry) const {
+ // TODO: MGLPolygon doesn’t support holes, so what to do?
+ auto &linearRing = geometry.front();
+
+ std::vector<CLLocationCoordinate2D> coordinates;
+ coordinates.reserve(linearRing.size());
+ std::transform(linearRing.begin(), linearRing.end(), std::back_inserter(coordinates), coordinateFromPoint);
+
+ MGLPolygonFeature *feature = [[MGLPolygonFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()];
+ feature.identifier = tag;
+ feature.attributes = attributes;
+ return feature;
+ }
+
+ MGLShape <MGLFeature> * operator()(const mapbox::geometry::multi_point<T> &geometry) const {
+ std::vector<CLLocationCoordinate2D> coordinates;
+ coordinates.reserve(geometry.size());
+ std::transform(geometry.begin(), geometry.end(), std::back_inserter(coordinates), coordinateFromPoint);
+
+ MGLMultiPointFeature *feature = [[MGLMultiPointFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()];
+ feature.identifier = tag;
+ feature.attributes = attributes;
+ return feature;
+ }
+
+ MGLShape <MGLFeature> * operator()(const mapbox::geometry::multi_line_string<T> &geometry) const {
+ NSMutableArray *polylines = [NSMutableArray arrayWithCapacity:geometry.size()];
+ for (auto &lineString : geometry) {
+ std::vector<CLLocationCoordinate2D> coordinates;
+ coordinates.reserve(lineString.size());
+ std::transform(lineString.begin(), lineString.end(), std::back_inserter(coordinates), coordinateFromPoint);
+
+ MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:&coordinates[0] count:coordinates.size()];
+ [polylines addObject:polyline];
+ }
+
+ MGLMultiPolylineFeature *feature = [MGLMultiPolylineFeature multiPolylineWithPolylines:polylines];
+ feature.identifier = tag;
+ feature.attributes = attributes;
+ return feature;
+ }
+
+ MGLShape <MGLFeature> * operator()(const mapbox::geometry::multi_polygon<T> &geometry) const {
+ NSMutableArray *polygons = [NSMutableArray arrayWithCapacity:geometry.size()];
+ for (auto &polygon : geometry) {
+ // TODO: MGLPolygon doesn’t support holes, so what to do?
+ auto &linearRing = polygon.front();
+
+ std::vector<CLLocationCoordinate2D> coordinates;
+ coordinates.reserve(linearRing.size());
+ std::transform(linearRing.begin(), linearRing.end(), std::back_inserter(coordinates), coordinateFromPoint);
+
+ MGLPolygon *polygonObject = [MGLPolygon polygonWithCoordinates:&coordinates[0] count:coordinates.size()];
+ [polygons addObject:polygonObject];
+ }
+
+ MGLMultiPolygonFeature *feature = [MGLMultiPolygonFeature multiPolygonWithPolygons:polygons];
+ feature.identifier = tag;
+ feature.attributes = attributes;
+ return feature;
+ }
+
+ MGLShape <MGLFeature> * operator()(const mapbox::geometry::geometry_collection<T> &collection) const {
+ NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:collection.size()];
+ for (auto &geometry : collection) {
+ GeometryEvaluator<T> evaluator;
+ id <MGLFeature> feature = mapbox::geometry::geometry<T>::visit(geometry, evaluator);
+ [shapes addObject:feature];
+ }
+ MGLShapeCollectionFeature *feature = [MGLShapeCollectionFeature shapeCollectionWithShapes:shapes];
+ feature.identifier = tag;
+ feature.attributes = attributes;
+ return feature;
+ }
+
+private:
+ NSNumber *tag = nullptr;
+ NS_MUTABLE_DICTIONARY_OF(NSString *, id) *attributes;
+
+ static CLLocationCoordinate2D coordinateFromPoint(const mapbox::geometry::point<T> &point) {
+ return CLLocationCoordinate2DMake(point.y, point.x);
+ }
+};
+
+NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features) {
+ std::vector<MGLShape <MGLFeature> *> shapes;
+ shapes.reserve(features.size());
+ std::transform(features.begin(), features.end(), std::back_inserter(shapes), ^MGLShape <MGLFeature> * (const mbgl::Feature &feature) {
+ GeometryEvaluator<double> evaluator(feature);
+ return mapbox::geometry::geometry<double>::visit(feature.geometry, evaluator);
+ });
+ return [NSArray arrayWithObjects:&shapes[0] count:shapes.size()];
+}
+
+@implementation MGLPointFeature
+
+- (id)attributeForKey:(NSString *)key {
+ return self.attributes[key];
+}
+
+@end
+
+@implementation MGLPolylineFeature
+
+- (id)attributeForKey:(NSString *)key {
+ return self.attributes[key];
+}
+
+@end
+
+@implementation MGLPolygonFeature
+
+- (id)attributeForKey:(NSString *)key {
+ return self.attributes[key];
+}
+
+@end
+
+@implementation MGLMultiPointFeature
+
+- (id)attributeForKey:(NSString *)key {
+ return self.attributes[key];
+}
+
+@end
+
+@implementation MGLMultiPolylineFeature
+
+- (id)attributeForKey:(NSString *)key {
+ return self.attributes[key];
+}
+
+@end
+
+@implementation MGLMultiPolygonFeature
+
+- (id)attributeForKey:(NSString *)key {
+ return self.attributes[key];
+}
+
+@end
+
+@implementation MGLShapeCollectionFeature
+
+- (id)attributeForKey:(NSString *)key {
+ return self.attributes[key];
+}
+
+@end