diff options
Diffstat (limited to 'platform/darwin')
24 files changed, 548 insertions, 171 deletions
diff --git a/platform/darwin/src/MGLFeature.h b/platform/darwin/src/MGLFeature.h index d187e9cf06..239a338f67 100644 --- a/platform/darwin/src/MGLFeature.h +++ b/platform/darwin/src/MGLFeature.h @@ -83,10 +83,6 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, copy, readonly) NS_DICTIONARY_OF(NSString *, id) *attributes; - - -- (NS_DICTIONARY_OF(NSString *, id) *)featureDictionary; - /** Returns the feature attribute for the given attribute name. @@ -95,6 +91,17 @@ NS_ASSUME_NONNULL_BEGIN */ - (nullable id)attributeForKey:(NSString *)key; +/** + Returns a dictionary that can be serialized as a GeoJSON Feature representation + of an instance of an `MGLFeature` subclass. + + The dictionary includes a `geometry` key corresponding to the receiver’s + underlying geometry data, a `properties` key corresponding to the receiver’s + `attributes` property, and an `id` key corresponding to the receiver’s + `identifier` property. + */ +- (NS_DICTIONARY_OF(NSString *, id) *)geoJSONDictionary; + @end /** diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm index 142a5e7ae6..84dcc4f0bb 100644 --- a/platform/darwin/src/MGLFeature.mm +++ b/platform/darwin/src/MGLFeature.mm @@ -5,17 +5,16 @@ #import "MGLPolygon.h" #import "MGLValueEvaluator.h" +#import "MGLShape_Private.h" #import "MGLMultiPoint_Private.h" #import "MGLPolyline+MGLAdditions.h" #import "MGLPolygon+MGLAdditions.h" -#import <mbgl/util/geometry.hpp> - -@protocol MGLFeaturePrivate <MGLFeature> +#import "NSDictionary+MGLAdditions.h" -@property (nonatomic, copy, nullable, readwrite) id identifier; -@property (nonatomic, copy, readwrite) NS_DICTIONARY_OF(NSString *, id) *attributes; +#import "NSExpression+MGLAdditions.h" -@end +#import <mbgl/util/geometry.hpp> +#import <mapbox/geometry/feature.hpp> @interface MGLPointFeature () <MGLFeaturePrivate> @end @@ -29,15 +28,12 @@ return self.attributes[key]; } -- (NS_DICTIONARY_OF(NSString *, id) *)featureDictionary { - - return @{@"type":@"Feature", - @"properties":(self.attributes) ? self.attributes : @{}, - @"geometry":@{ - @"type":@"Point", - @"coordinates":@[@(self.coordinate.longitude), @(self.coordinate.latitude)] - } - }; +- (NSDictionary *)geoJSONDictionary { + return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier); +} + +- (mbgl::Feature)mbglFeature { + return mbglFeature([self featureObject], identifier, self.attributes); } @end @@ -49,20 +45,17 @@ @synthesize identifier; @synthesize attributes; -// - (id)attributeForKey:(NSString *)key { return self.attributes[key]; } -- (NS_DICTIONARY_OF(NSString *, id) *)featureDictionary { - return @{@"type":@"Feature", - @"properties":(self.attributes) ? self.attributes : @{}, - @"geometry":@{ - @"type":@"LineString", - @"coordinates":self.mgl_coordinates - } - };; +- (NSDictionary *)geoJSONDictionary { + return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier); +} + +- (mbgl::Feature)mbglFeature { + return mbglFeature([self featureObject], identifier, self.attributes); } @end @@ -79,14 +72,12 @@ return self.attributes[key]; } -- (NS_DICTIONARY_OF(NSString *, id) *)featureDictionary { - return @{@"type":@"Feature", - @"properties":(self.attributes) ? self.attributes : @{}, - @"geometry":@{ - @"type":@"Polygon", - @"coordinates":self.mgl_coordinates - } - }; +- (NSDictionary *)geoJSONDictionary { + return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier); +} + +- (mbgl::Feature)mbglFeature { + return mbglFeature([self featureObject], identifier, self.attributes); } @end @@ -103,21 +94,12 @@ return self.attributes[key]; } -- (NS_DICTIONARY_OF(NSString *, id) *)featureDictionary { - NSMutableArray *coordinates = [NSMutableArray array]; - - for (NSUInteger index = 0; index < self.pointCount; index++) { - CLLocationCoordinate2D coordinate = self.coordinates[index]; - [coordinates addObject:@[@(coordinate.longitude), @(coordinate.latitude)]]; - } - - return @{@"type":@"Feature", - @"properties":(self.attributes) ? self.attributes : @{}, - @"geometry":@{ - @"type":@"Multipoint", - @"coordinates":coordinates - } - }; +- (NSDictionary *)geoJSONDictionary { + return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier); +} + +- (mbgl::Feature)mbglFeature { + return mbglFeature([self featureObject], identifier, self.attributes); } @end @@ -134,19 +116,12 @@ return self.attributes[key]; } -- (NS_DICTIONARY_OF(NSString *, id) *)featureDictionary { - NSMutableArray *coordinates = [NSMutableArray array]; - for (MGLPolylineFeature *feature in self.polylines) { - [coordinates addObject:feature.mgl_coordinates]; - } - - return @{@"type":@"Feature", - @"properties":(self.attributes) ? self.attributes : @{}, - @"geometry":@{ - @"type":@"MultiLineString", - @"coordinates":coordinates - } - }; +- (NSDictionary *)geoJSONDictionary { + return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier); +} + +- (mbgl::Feature)mbglFeature { + return mbglFeature([self featureObject], identifier, self.attributes); } @end @@ -163,19 +138,12 @@ return self.attributes[key]; } -- (NS_DICTIONARY_OF(NSString *, id) *)featureDictionary { - NSMutableArray *coordinates = [NSMutableArray array]; - for (MGLPolygonFeature *feature in self.polygons) { - [coordinates addObject:feature.mgl_coordinates]; - } - - return @{@"type":@"Feature", - @"properties":(self.attributes) ? self.attributes : @{}, - @"geometry":@{ - @"type":@"MultiPolygon", - @"coordinates":coordinates - } - }; +- (NSDictionary *)geoJSONDictionary { + return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier); +} + +- (mbgl::Feature)mbglFeature { + return mbglFeature([self featureObject], identifier, self.attributes); } @end @@ -190,7 +158,7 @@ @dynamic shapes; -+ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)shapes { ++ (instancetype)shapeCollectionWithShapes:(NSArray *)shapes { return [super shapeCollectionWithShapes:shapes]; } @@ -198,36 +166,17 @@ return self.attributes[key]; } -- (NS_DICTIONARY_OF(NSString *, id) *)featureDictionary { - - return @{@"type":@"Feature", - @"properties":(self.attributes) ? self.attributes : @{}, - @"geometry":@{ - @"type":@"GeometryCollection", - @"geometries":[self geometryCollection:self.shapes] - } - }; +- (NSDictionary *)geoJSONDictionary { + return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier); } -- (NS_MUTABLE_ARRAY_OF(NS_DICTIONARY_OF(NSString *, id) *) *)geometryCollection:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)shapes { - NSMutableArray *geometries = [NSMutableArray array]; - - for (MGLShape<MGLFeature> *shape in shapes) { - if ([shape isKindOfClass:[MGLShapeCollectionFeature class]]) { - [geometries addObject:@{@"type":@"GeometryCollection", - @"geometries":[self geometryCollection:((MGLShapeCollectionFeature *)shape).shapes]}]; - } else { - NSDictionary *geometry = shape.featureDictionary[@"geometry"]; - [geometries addObject:@{@"type":geometry[@"type"], - @"coordinates":geometry[@"coordinates"] }]; - } - } - - return geometries; +- (mbgl::Feature)mbglFeature { + [NSException raise:@"Method unavailable" format:@"%s is not available on %@.", __PRETTY_FUNCTION__, [self class]]; + mbgl::Polygon<double> geometry; + return mbgl::Feature{geometry}; } -@end - +@end /** Transforms an `mbgl::geometry::geometry` type into an instance of the @@ -337,3 +286,21 @@ NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vec } return shapes; } + +mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *attributes) +{ + if (identifier) { + NSExpression *identifierExpression = [NSExpression expressionForConstantValue:identifier]; + feature.id = [identifierExpression mgl_featureIdentifier]; + } + feature.properties = [attributes mgl_propertyMap]; + return feature; +} + +NS_DICTIONARY_OF(NSString *, id) *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier) { + NSMutableDictionary *feature = [@{@"type": @"Feature", + @"properties": (attributes) ?: [NSNull null], + @"geometry": geometry} mutableCopy]; + feature[@"id"] = identifier; + return [feature copy]; +} diff --git a/platform/darwin/src/MGLFeature_Private.h b/platform/darwin/src/MGLFeature_Private.h index fbc7f88559..5fb82bde5b 100644 --- a/platform/darwin/src/MGLFeature_Private.h +++ b/platform/darwin/src/MGLFeature_Private.h @@ -4,8 +4,33 @@ #import <mbgl/util/geo.hpp> #import <mbgl/util/feature.hpp> +NS_ASSUME_NONNULL_BEGIN + /** Returns an array of `MGLFeature` objects converted from the given vector of vector tile features. */ NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features); + +/** + Takes an `mbgl::Feature` object, an identifer, and attributes dictionary and + returns the feature object with converted `mbgl::FeatureIdentifier` and + `mbgl::PropertyMap` properties. + */ +mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *attributes); + +/** + Returns an `NSDictionary` representation of an `MGLFeature`. + */ +NS_DICTIONARY_OF(NSString *, id) *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier); + +@protocol MGLFeaturePrivate <MGLFeature> + +@property (nonatomic, copy, nullable, readwrite) id identifier; +@property (nonatomic, copy, readwrite) NS_DICTIONARY_OF(NSString *, id) *attributes; + +- (mbgl::Feature)mbglFeature; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLGeoJSONSource.mm b/platform/darwin/src/MGLGeoJSONSource.mm index 4417788851..27f2eb8bda 100644 --- a/platform/darwin/src/MGLGeoJSONSource.mm +++ b/platform/darwin/src/MGLGeoJSONSource.mm @@ -115,23 +115,14 @@ NSString * const MGLGeoJSONToleranceOption = @"MGLGeoJSONOptionsClusterTolerance source->setGeoJSON(geojson); _features = MGLFeaturesFromMBGLFeatures(geojson); } else { - - NSMutableArray *featuresArray = [NSMutableArray array]; - for (id<MGLFeature> feature in self.features) { - [featuresArray addObject:[feature featureDictionary]]; + mbgl::FeatureCollection featureCollection; + featureCollection.reserve(self.features.count); + for (id <MGLFeaturePrivate> feature in self.features) { + featureCollection.push_back([feature mbglFeature]); } - - NSDictionary *featureCollection = @{ - @"type":@"FeatureCollection", - @"features":featuresArray}; - - NSError *error; - NSData *featuresJSONData = [NSJSONSerialization dataWithJSONObject:featureCollection options:0 error:&error]; - - NSString *string = [[NSString alloc] initWithData:featuresJSONData encoding:NSUTF8StringEncoding]; - const auto geojson = mapbox::geojson::parse(string.UTF8String).get<mapbox::geojson::feature_collection>(); - source->setGeoJSON(geojson); - _features = MGLFeaturesFromMBGLFeatures(geojson); + const auto geojson = mbgl::GeoJSON{featureCollection}; + source->setGeoJSON(geojson); + _features = MGLFeaturesFromMBGLFeatures(featureCollection); } return std::move(source); diff --git a/platform/darwin/src/MGLMultiPoint.h b/platform/darwin/src/MGLMultiPoint.h index 69c7295842..b33d68f867 100644 --- a/platform/darwin/src/MGLMultiPoint.h +++ b/platform/darwin/src/MGLMultiPoint.h @@ -6,16 +6,25 @@ NS_ASSUME_NONNULL_BEGIN /** - The `MGLMultiPoint` class is an abstract superclass used to define shapes - composed of multiple points. You should not create instances of this class - directly. Instead, you should create instances of the `MGLPolyline` or - `MGLPolygon` classes. However, you can use the method and properties of this - class to access information about the specific points associated with the line - or polygon. + The `MGLMultiPoint` class is used to define shapes composed of multiple points. + This class is also the superclass of `MGLPolyline` and `MGLPolygon`. The + methods and properties of this class can be used to access information about + the specific points associated with a line or polygon. */ @interface MGLMultiPoint : MGLShape /** + Creates and returns an `MGLMultiPoint` object from the specified set of + coordinates. + + @param coords The array of coordinates defining the shape. The data in this + array is copied to the new object. + @param count The number of items in the `coords` array. + @return A new multipoint object. + */ ++ (instancetype)multiPointWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count; + +/** The array of coordinates associated with the shape. This C array is a pointer to a structure inside the multipoint object, diff --git a/platform/darwin/src/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm index 17a61ed081..0090c5e35f 100644 --- a/platform/darwin/src/MGLMultiPoint.mm +++ b/platform/darwin/src/MGLMultiPoint.mm @@ -18,6 +18,11 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) MGLCoordinateBounds _bounds; } ++ (instancetype)multiPointWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count +{ + return [[self alloc] initWithCoordinates:coords count:count]; +} + - (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count { self = [super init]; @@ -141,6 +146,29 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) return mbgl::SymbolAnnotation({mbgl::Point<double>()}); } +- (mbgl::Feature)featureObject +{ + mbgl::MultiPoint<double> multiPoint; + multiPoint.reserve(self.pointCount); + for (NSInteger i = 0; i< self.pointCount; i++) + { + multiPoint.push_back(mbgl::Point<double>(self.coordinates[i].longitude, self.coordinates[i].latitude)); + } + return mbgl::Feature {multiPoint}; +} + +- (NSDictionary *)geoJSONDictionary +{ + NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.pointCount]; + for (NSUInteger index = 0; index < self.pointCount; index++) { + CLLocationCoordinate2D coordinate = self.coordinates[index]; + [coordinates addObject:@[@(coordinate.longitude), @(coordinate.latitude)]]; + } + + return @{@"type": @"MultiPoint", + @"coordinates": coordinates}; +} + - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p; count = %lu; bounds = %@>", diff --git a/platform/darwin/src/MGLMultiPoint_Private.h b/platform/darwin/src/MGLMultiPoint_Private.h index dc39172723..7bc3cae58a 100644 --- a/platform/darwin/src/MGLMultiPoint_Private.h +++ b/platform/darwin/src/MGLMultiPoint_Private.h @@ -3,6 +3,7 @@ #import "MGLGeometry.h" #import <mbgl/annotation/annotation.hpp> +#import <mbgl/util/feature.hpp> #import <vector> #import <CoreGraphics/CoreGraphics.h> diff --git a/platform/darwin/src/MGLPointAnnotation.m b/platform/darwin/src/MGLPointAnnotation.mm index 9495a2c6f8..ce8e4a2355 100644 --- a/platform/darwin/src/MGLPointAnnotation.m +++ b/platform/darwin/src/MGLPointAnnotation.mm @@ -1,5 +1,10 @@ #import "MGLPointAnnotation.h" +#import "MGLShape_Private.h" + +#import <mbgl/util/geometry.hpp> + + @implementation MGLPointAnnotation @synthesize coordinate; @@ -13,4 +18,17 @@ coordinate.latitude, coordinate.longitude]; } +- (NSDictionary *)geoJSONDictionary +{ + return @{@"type": @"Point", + @"coordinates": @[@(self.coordinate.longitude), @(self.coordinate.latitude)]}; +} + +- (mbgl::Feature)featureObject +{ + mbgl::Point<double> point = { self.coordinate.longitude, self.coordinate.latitude }; + return mbgl::Feature {point}; +} + @end + diff --git a/platform/darwin/src/MGLPolygon+MGLAdditions.h b/platform/darwin/src/MGLPolygon+MGLAdditions.h index c9ef95b6bc..f409fb96ca 100644 --- a/platform/darwin/src/MGLPolygon+MGLAdditions.h +++ b/platform/darwin/src/MGLPolygon+MGLAdditions.h @@ -1,11 +1,3 @@ -// -// MGLPolygonFeature+MGLAdditions.h -// ios -// -// Created by Mapbox on 9/30/16. -// Copyright © 2016 Mapbox. All rights reserved. -// - #import <Mapbox/Mapbox.h> @interface MGLPolygon (MGLAdditions) diff --git a/platform/darwin/src/MGLPolygon+MGLAdditions.m b/platform/darwin/src/MGLPolygon+MGLAdditions.m index 74fb5668d1..def4687016 100644 --- a/platform/darwin/src/MGLPolygon+MGLAdditions.m +++ b/platform/darwin/src/MGLPolygon+MGLAdditions.m @@ -1,19 +1,11 @@ -// -// MGLPolygonFeature+MGLAdditions.m -// ios -// -// Created by Mapbox on 9/30/16. -// Copyright © 2016 Mapbox. All rights reserved. -// - #import "MGLPolygon+MGLAdditions.h" @implementation MGLPolygon (MGLAdditions) - (NS_ARRAY_OF(id) *)mgl_coordinates { - NS_MUTABLE_ARRAY_OF(NS_MUTABLE_ARRAY_OF(NS_ARRAY_OF(NSNumber *) *) *) *coordinates = [NSMutableArray array]; + NSMutableArray *coordinates = [NSMutableArray array]; - NS_MUTABLE_ARRAY_OF(NS_ARRAY_OF(NSNumber *) *) *exteriorRing = [NSMutableArray array]; + NSMutableArray *exteriorRing = [NSMutableArray array]; for (NSUInteger index = 0; index < self.pointCount; index++) { CLLocationCoordinate2D coordinate = self.coordinates[index]; [exteriorRing addObject:@[@(coordinate.longitude), @(coordinate.latitude)]]; @@ -21,7 +13,7 @@ [coordinates addObject:exteriorRing]; for (MGLPolygon *interiorPolygon in self.interiorPolygons) { - NS_MUTABLE_ARRAY_OF(NS_ARRAY_OF(NSNumber *) *) *interiorRing = [NSMutableArray array]; + NSMutableArray *interiorRing = [NSMutableArray array]; for (int index = 0; index < interiorPolygon.pointCount; index++) { CLLocationCoordinate2D coordinate = interiorPolygon.coordinates[index]; [interiorRing addObject:@[@(coordinate.longitude), @(coordinate.latitude)]]; @@ -29,7 +21,7 @@ [coordinates addObject:interiorRing]; } - return coordinates; + return [coordinates copy]; } @end diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm index b8f02b6406..eae2cfe75a 100644 --- a/platform/darwin/src/MGLPolygon.mm +++ b/platform/darwin/src/MGLPolygon.mm @@ -3,6 +3,8 @@ #import "MGLMultiPoint_Private.h" #import "MGLGeometry_Private.h" +#import "MGLPolygon+MGLAdditions.h" + @implementation MGLPolygon @dynamic overlayBounds; @@ -36,6 +38,15 @@ return result; } +- (mbgl::Feature)featureObject { + mbgl::Polygon<double> geometry; + geometry.push_back(self.ring); + for (MGLPolygon *polygon in self.interiorPolygons) { + geometry.push_back(polygon.ring); + } + return mbgl::Feature{geometry}; +} + - (mbgl::Annotation)annotationObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate { mbgl::Polygon<double> geometry; geometry.push_back(self.ring); @@ -51,6 +62,11 @@ return annotation; } +- (NSDictionary *)geoJSONDictionary { + return @{@"type": @"Polygon", + @"coordinates": self.mgl_coordinates}; +} + @end @interface MGLMultiPolygon () @@ -87,4 +103,27 @@ return MGLLatLngBoundsFromCoordinateBounds(_overlayBounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds)); } +- (mbgl::Feature)featureObject { + mbgl::MultiPolygon<double> multiPolygon; + multiPolygon.reserve(self.polygons.count); + for (MGLPolygon *polygon in self.polygons) { + mbgl::Polygon<double> geometry; + geometry.push_back(polygon.ring); + for (MGLPolygon *interiorPolygon in polygon.interiorPolygons) { + geometry.push_back(interiorPolygon.ring); + } + multiPolygon.push_back(geometry); + } + return mbgl::Feature {multiPolygon}; +} + +- (NSDictionary *)geoJSONDictionary { + NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.polygons.count]; + for (MGLPolygonFeature *feature in self.polygons) { + [coordinates addObject: feature.mgl_coordinates]; + } + return @{@"type": @"MultiPolygon", + @"coordinates": coordinates}; +} + @end diff --git a/platform/darwin/src/MGLPolyline+MGLAdditions.h b/platform/darwin/src/MGLPolyline+MGLAdditions.h index e1e24a8ebc..4cdbbf17f9 100644 --- a/platform/darwin/src/MGLPolyline+MGLAdditions.h +++ b/platform/darwin/src/MGLPolyline+MGLAdditions.h @@ -1,11 +1,3 @@ -// -// MGLPolyline+MGLPolyline_MGLAdditions.h -// ios -// -// Created by Mapbox on 9/30/16. -// Copyright © 2016 Mapbox. All rights reserved. -// - #import <Mapbox/Mapbox.h> @interface MGLPolyline (MGLAdditions) diff --git a/platform/darwin/src/MGLPolyline+MGLAdditions.m b/platform/darwin/src/MGLPolyline+MGLAdditions.m index e91e4fc192..d1db2c58a0 100644 --- a/platform/darwin/src/MGLPolyline+MGLAdditions.m +++ b/platform/darwin/src/MGLPolyline+MGLAdditions.m @@ -1,25 +1,14 @@ -// -// MGLPolyline+MGLPolyline_MGLAdditions.m -// ios -// -// Created by Mapbox on 9/30/16. -// Copyright © 2016 Mapbox. All rights reserved. -// - #import "MGLPolyline+MGLAdditions.h" @implementation MGLPolyline (MGLAdditions) - (NS_ARRAY_OF(id) *)mgl_coordinates { - - NS_MUTABLE_ARRAY_OF(NS_ARRAY_OF(NSNumber *) *) *coordinates = [NSMutableArray array]; - + NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.pointCount]; for (NSUInteger index = 0; index < self.pointCount; index++) { CLLocationCoordinate2D coordinate = self.coordinates[index]; [coordinates addObject:@[@(coordinate.longitude), @(coordinate.latitude)]]; } - - return coordinates; + return [coordinates copy]; } @end diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm index b81147a3ba..dd2fccf53d 100644 --- a/platform/darwin/src/MGLPolyline.mm +++ b/platform/darwin/src/MGLPolyline.mm @@ -3,6 +3,8 @@ #import "MGLMultiPoint_Private.h" #import "MGLGeometry_Private.h" +#import "MGLPolyline+MGLAdditions.h" + @implementation MGLPolyline @dynamic overlayBounds; @@ -13,17 +15,21 @@ return [[self alloc] initWithCoordinates:coords count:count]; } -- (mbgl::Annotation)annotationObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate { +- (mbgl::LineString<double>)lineString { NSUInteger count = self.pointCount; CLLocationCoordinate2D *coordinates = self.coordinates; - + mbgl::LineString<double> geometry; geometry.reserve(self.pointCount); for (NSUInteger i = 0; i < count; i++) { geometry.push_back(mbgl::Point<double>(coordinates[i].longitude, coordinates[i].latitude)); } + + return geometry; +} - mbgl::LineAnnotation annotation { geometry }; +- (mbgl::Annotation)annotationObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate { + mbgl::LineAnnotation annotation { [self lineString] }; annotation.opacity = { static_cast<float>([delegate alphaForShapeAnnotation:self]) }; annotation.color = { [delegate strokeColorForShapeAnnotation:self] }; annotation.width = { static_cast<float>([delegate lineWidthForPolylineAnnotation:self]) }; @@ -31,6 +37,15 @@ return annotation; } +- (mbgl::Feature)featureObject { + return mbgl::Feature {[self lineString]}; +} + +- (NSDictionary *)geoJSONDictionary { + return @{@"type": @"LineString", + @"coordinates": self.mgl_coordinates}; +} + @end @interface MGLMultiPolyline () @@ -67,4 +82,22 @@ return MGLLatLngBoundsFromCoordinateBounds(_overlayBounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds)); } +- (mbgl::Feature)featureObject { + mbgl::MultiLineString<double> multiLineString; + multiLineString.reserve(self.polylines.count); + for (MGLPolyline *polyline in self.polylines) { + multiLineString.push_back([polyline lineString]); + } + return mbgl::Feature {multiLineString}; +} + +- (NSDictionary *)geoJSONDictionary { + NSMutableArray *coordinates = [NSMutableArray array]; + for (MGLPolylineFeature *feature in self.polylines) { + [coordinates addObject: feature.mgl_coordinates]; + } + return @{@"type": @"MultiLineString", + @"coordinates": coordinates}; +} + @end diff --git a/platform/darwin/src/MGLShape.m b/platform/darwin/src/MGLShape.mm index e3d92c38c8..e3d92c38c8 100644 --- a/platform/darwin/src/MGLShape.m +++ b/platform/darwin/src/MGLShape.mm diff --git a/platform/darwin/src/MGLShapeCollection.m b/platform/darwin/src/MGLShapeCollection.m index 5d42b5a51c..0f011bfd20 100644 --- a/platform/darwin/src/MGLShapeCollection.m +++ b/platform/darwin/src/MGLShapeCollection.m @@ -18,4 +18,18 @@ return _shapes.firstObject.coordinate; } +- (NSDictionary *)geoJSONDictionary { + return @{@"type": @"GeometryCollection", + @"geometries": [self geometryCollection]}; +} + +- (NSArray *)geometryCollection { + NSMutableArray *geometries = [[NSMutableArray alloc] initWithCapacity:self.shapes.count]; + for (id shape in self.shapes) { + NSDictionary *geometry = [shape geoJSONDictionary]; + [geometries addObject:geometry]; + } + return [geometries copy]; +} + @end diff --git a/platform/darwin/src/MGLShape_Private.h b/platform/darwin/src/MGLShape_Private.h new file mode 100644 index 0000000000..a8ee12c207 --- /dev/null +++ b/platform/darwin/src/MGLShape_Private.h @@ -0,0 +1,17 @@ +#import "MGLShape.h" + +#import <mbgl/util/feature.hpp> + +@interface MGLShape (Private) + +/** + Returns an `mbgl::Feature` representation of the `MGLShape`. + */ +- (mbgl::Feature)featureObject; + +/** + Returns a dictionary with the GeoJSON geometry member object. + */ +- (NSDictionary *)geoJSONDictionary; + +@end diff --git a/platform/darwin/src/NSArray+MGLAdditions.h b/platform/darwin/src/NSArray+MGLAdditions.h new file mode 100644 index 0000000000..6871f15486 --- /dev/null +++ b/platform/darwin/src/NSArray+MGLAdditions.h @@ -0,0 +1,9 @@ +#import <Foundation/Foundation.h> + +#import <mbgl/util/feature.hpp> + +@interface NSArray (MGLAdditions) + +- (std::vector<mbgl::Value>)mgl_vector; + +@end diff --git a/platform/darwin/src/NSArray+MGLAdditions.mm b/platform/darwin/src/NSArray+MGLAdditions.mm new file mode 100644 index 0000000000..976eda704f --- /dev/null +++ b/platform/darwin/src/NSArray+MGLAdditions.mm @@ -0,0 +1,26 @@ +#import "NSArray+MGLAdditions.h" + +#import "NSDictionary+MGLAdditions.h" +#import "NSExpression+MGLAdditions.mm" + +@implementation NSArray (MGLAdditions) + +- (std::vector<mbgl::Value>)mgl_vector { + std::vector<mbgl::Value> vector; + vector.reserve(self.count); + for (id value in self) { + if ([value isKindOfClass:[NSArray class]]) { + std::vector<mbgl::Value> innerVector = [value mgl_vector]; + vector.push_back(innerVector); + } else if ([value isKindOfClass:[NSDictionary class]]) { + mbgl::PropertyMap propertyMap = [value mgl_propertyMap]; + vector.push_back(propertyMap); + } else { + NSExpression *expression = [NSExpression expressionForConstantValue:value]; + vector.push_back([expression mgl_filterValue]); + } + } + return vector; +} + +@end diff --git a/platform/darwin/src/NSDictionary+MGLAdditions.h b/platform/darwin/src/NSDictionary+MGLAdditions.h new file mode 100644 index 0000000000..556f21992b --- /dev/null +++ b/platform/darwin/src/NSDictionary+MGLAdditions.h @@ -0,0 +1,13 @@ +#import <Foundation/Foundation.h> + +#import <mbgl/util/feature.hpp> + +NS_ASSUME_NONNULL_BEGIN + +@interface NSDictionary (MGLAdditions) + +- (mbgl::PropertyMap)mgl_propertyMap; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/NSDictionary+MGLAdditions.mm b/platform/darwin/src/NSDictionary+MGLAdditions.mm new file mode 100644 index 0000000000..1023e91a48 --- /dev/null +++ b/platform/darwin/src/NSDictionary+MGLAdditions.mm @@ -0,0 +1,24 @@ +#import "NSDictionary+MGLAdditions.h" + +#import "NSExpression+MGLAdditions.mm" +#import "NSArray+MGLAdditions.h" + +@implementation NSDictionary (MGLAdditions) + +- (mbgl::PropertyMap)mgl_propertyMap { + mbgl::PropertyMap propertyMap; + for (NSString *key in self.allKeys) { + if ([self[key] isKindOfClass:[NSDictionary class]]) { + propertyMap[[key UTF8String]] = [self[key] mgl_propertyMap]; + } else if ([self[key] isKindOfClass:[NSArray class]]) { + NSArray *array = self[key]; + propertyMap[[key UTF8String]] = [array mgl_vector]; + } else { + NSExpression *expression = [NSExpression expressionForConstantValue:self[key]]; + propertyMap[[key UTF8String]] = [expression mgl_filterValue]; + } + } + return propertyMap; +} + +@end diff --git a/platform/darwin/src/NSExpression+MGLAdditions.h b/platform/darwin/src/NSExpression+MGLAdditions.h index 4e8c5ee071..6d0fff5760 100644 --- a/platform/darwin/src/NSExpression+MGLAdditions.h +++ b/platform/darwin/src/NSExpression+MGLAdditions.h @@ -5,7 +5,7 @@ @interface NSExpression (MGLAdditions) - (mbgl::Value)mgl_filterValue; - - (std::vector<mbgl::Value>)mgl_filterValues; +- (mbgl::FeatureIdentifier)mgl_featureIdentifier; @end diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm index 52a0b9bd88..392a6d7f5b 100644 --- a/platform/darwin/src/NSExpression+MGLAdditions.mm +++ b/platform/darwin/src/NSExpression+MGLAdditions.mm @@ -61,4 +61,30 @@ return { }; } +- (mbgl::FeatureIdentifier)mgl_featureIdentifier +{ + id value = self.constantValue; + mbgl::Value mbglValue = [self mgl_filterValue]; + + if ([value isKindOfClass:NSString.class]) { + return mbglValue.get<std::string>(); + } else if ([value isKindOfClass:NSNumber.class]) { + NSNumber *number = (NSNumber *)value; + if ((strcmp([number objCType], @encode(char)) == 0) || + (strcmp([number objCType], @encode(BOOL)) == 0)) { + return mbglValue.get<bool>(); + } else if ( strcmp([number objCType], @encode(double)) == 0 || + strcmp([number objCType], @encode(float)) == 0) { + return mbglValue.get<double>(); + } else if ([number compare:@(0)] == NSOrderedDescending || + [number compare:@(0)] == NSOrderedSame) { + return mbglValue.get<uint64_t>(); + } else if ([number compare:@(0)] == NSOrderedAscending) { + return mbglValue.get<int64_t>(); + } + } + + return {}; +} + @end diff --git a/platform/darwin/test/MGLFeatureTests.mm b/platform/darwin/test/MGLFeatureTests.mm index 1b1722f172..18c3fd16c2 100644 --- a/platform/darwin/test/MGLFeatureTests.mm +++ b/platform/darwin/test/MGLFeatureTests.mm @@ -158,4 +158,169 @@ XCTAssertEqual(string, shape.attributes[@"string"]); } +- (void)testPointFeatureGeoJSONDictionary { + MGLPointFeature<MGLFeaturePrivate> *pointFeature = (MGLPointFeature<MGLFeaturePrivate> *)[[MGLPointFeature alloc] init]; + CLLocationCoordinate2D coordinate = { 10, 10 }; + pointFeature.coordinate = coordinate; + + // A GeoJSON feature + // when there are no identifier or properties + NSDictionary *geoJSONFeature = [pointFeature geoJSONDictionary]; + + // it has the correct type + XCTAssertEqualObjects(geoJSONFeature[@"type"], @"Feature"); + // it has the correct geometry + NSDictionary *expectedGeometry = @{@"type": @"Point", + @"coordinates": @[@(coordinate.longitude), @(coordinate.latitude)]}; + XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry); + // it has no "id" key (or value) + XCTAssertNil(geoJSONFeature[@"id"]); + // it has a null representation of the properties object + XCTAssertEqualObjects(geoJSONFeature[@"properties"], [NSNull null]); + + // when there is a string identifier + pointFeature.identifier = @"string-id"; + + // it has the identifier in the result + geoJSONFeature = [pointFeature geoJSONDictionary]; + XCTAssertEqualObjects(geoJSONFeature[@"id"], pointFeature.identifier); + + // when there are properties + pointFeature.attributes = @{@"name": @"name-value"}; + + // it has the properties value in the result + geoJSONFeature = [pointFeature geoJSONDictionary]; + XCTAssertEqualObjects(geoJSONFeature[@"properties"], pointFeature.attributes); +} + +- (void)testPolylineFeatureGeoJSONDictionary { + CLLocationCoordinate2D coord1 = { 0, 0 }; + CLLocationCoordinate2D coord2 = { 10, 10 }; + CLLocationCoordinate2D coords[] = { coord1, coord2 }; + MGLPolylineFeature *polyLineFeature = [MGLPolylineFeature polylineWithCoordinates:coords count:2]; + + // A GeoJSON feature + NSDictionary *geoJSONFeature = [polyLineFeature geoJSONDictionary]; + + // it has the correct geometry + NSDictionary *expectedGeometry = @{@"type": @"LineString", + @"coordinates": @[@[@(coord1.longitude), @(coord1.latitude)], + @[@(coord2.longitude), @(coord2.latitude)]]}; + XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry); +} + +- (void)testPolygonFeatureGeoJSONDictionary { + CLLocationCoordinate2D coord1 = { 0, 0 }; + CLLocationCoordinate2D coord2 = { 10, 10 }; + CLLocationCoordinate2D coord3 = { 0, 0 }; + CLLocationCoordinate2D coords[] = { coord1, coord2, coord3 }; + MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coords count:3]; + + // A GeoJSON feature + NSDictionary *geoJSONFeature = [polygonFeature geoJSONDictionary]; + + // it has the correct geometry + NSDictionary *expectedGeometry = @{@"type": @"Polygon", + @"coordinates": @[@[@[@(coord1.longitude), @(coord1.latitude)], + @[@(coord2.longitude), @(coord2.latitude)], + @[@(coord3.longitude), @(coord3.latitude)]]]}; + XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry); +} + +- (void)testMultiPointFeatureGeoJSONDictionary { + CLLocationCoordinate2D coord1 = { 0, 0 }; + CLLocationCoordinate2D coord2 = { 10, 10 }; + CLLocationCoordinate2D coord3 = { 0, 0 }; + CLLocationCoordinate2D coords[] = { coord1, coord2, coord3 }; + MGLMultiPointFeature *multiPointFeature = [MGLMultiPointFeature multiPointWithCoordinates:coords count:3]; + + // A GeoJSON feature + NSDictionary *geoJSONFeature = [multiPointFeature geoJSONDictionary]; + + // it has the correct geometry + NSDictionary *expectedGeometry = @{@"type": @"MultiPoint", + @"coordinates": @[@[@(coord1.longitude), @(coord1.latitude)], + @[@(coord2.longitude), @(coord2.latitude)], + @[@(coord3.longitude), @(coord3.latitude)]]}; + XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry); +} + +- (void)testMultiPolylineFeatureGeoJSONDictionary { + CLLocationCoordinate2D coord1 = { 0, 0 }; + CLLocationCoordinate2D coord2 = { 10, 10 }; + CLLocationCoordinate2D coord3 = { 0, 0 }; + CLLocationCoordinate2D coords[] = { coord1, coord2, coord3 }; + + MGLPolyline *polyLine1 = [MGLPolyline polylineWithCoordinates:coords count:3]; + MGLPolyline *polyLine2 = [MGLPolyline polylineWithCoordinates:coords count:3]; + + MGLMultiPolylineFeature *multiPolylineFeature = [MGLMultiPolylineFeature multiPolylineWithPolylines:@[polyLine1, polyLine2]]; + + // A GeoJSON feature + NSDictionary *geoJSONFeature = [multiPolylineFeature geoJSONDictionary]; + + // it has the correct geometry + NSDictionary *expectedGeometry = @{@"type": @"MultiLineString", + @"coordinates": @[@[@[@(coord1.longitude), @(coord1.latitude)], + @[@(coord2.longitude), @(coord2.latitude)], + @[@(coord3.longitude), @(coord3.latitude)]], + @[@[@(coord1.longitude), @(coord1.latitude)], + @[@(coord2.longitude), @(coord2.latitude)], + @[@(coord3.longitude), @(coord3.latitude)]]]}; + XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry); +} + +- (void)testMultiPolygonFeatureGeoJSONDictionary { + CLLocationCoordinate2D coord1 = { 0, 0 }; + CLLocationCoordinate2D coord2 = { 10, 10 }; + CLLocationCoordinate2D coord3 = { 0, 0 }; + CLLocationCoordinate2D coords[] = { coord1, coord2, coord3 }; + + MGLPolygon *polygon1 = [MGLPolygon polygonWithCoordinates:coords count:3]; + MGLPolygon *polygon2 = [MGLPolygon polygonWithCoordinates:coords count:3]; + + MGLMultiPolygonFeature *multiPolylineFeature = [MGLMultiPolygonFeature multiPolygonWithPolygons:@[polygon1, polygon2]]; + + // A GeoJSON feature + NSDictionary *geoJSONFeature = [multiPolylineFeature geoJSONDictionary]; + + // it has the correct geometry + NSDictionary *expectedGeometry = @{@"type": @"MultiPolygon", + @"coordinates": @[ + @[@[@[@(coord1.longitude), @(coord1.latitude)], + @[@(coord2.longitude), @(coord2.latitude)], + @[@(coord3.longitude), @(coord3.latitude)]]], + @[@[@[@(coord1.longitude), @(coord1.latitude)], + @[@(coord2.longitude), @(coord2.latitude)], + @[@(coord3.longitude), @(coord3.latitude)]]]]}; + XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry); +} + +- (void)testShapeCollectionFeatureGeoJSONDictionary { + MGLPointAnnotation *pointFeature = [[MGLPointAnnotation alloc] init]; + CLLocationCoordinate2D pointCoordinate = { 10, 10 }; + pointFeature.coordinate = pointCoordinate; + + CLLocationCoordinate2D coord1 = { 0, 0 }; + CLLocationCoordinate2D coord2 = { 10, 10 }; + CLLocationCoordinate2D coords[] = { coord1, coord2 }; + MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coords count:2]; + + MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[pointFeature, + polyline]]; + // A GeoJSON feature + NSDictionary *geoJSONFeature = [shapeCollectionFeature geoJSONDictionary]; + + // it has the correct geometry + NSDictionary *expectedGeometry = @{@"type": @"GeometryCollection", + @"geometries": @[ + @{@"type": @"Point", + @"coordinates": @[@(pointCoordinate.longitude), @(pointCoordinate.latitude)]}, + @{@"type": @"LineString", + @"coordinates": @[@[@(coord1.longitude), @(coord1.latitude)], + @[@(coord2.longitude), @(coord2.latitude)]]} + ]}; + XCTAssertEqualObjects(geoJSONFeature[@"geometry"], expectedGeometry); +} + @end |