diff options
Diffstat (limited to 'platform/darwin/src/MGLShapeSource.mm')
-rw-r--r-- | platform/darwin/src/MGLShapeSource.mm | 355 |
1 files changed, 0 insertions, 355 deletions
diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm deleted file mode 100644 index 2590865ac2..0000000000 --- a/platform/darwin/src/MGLShapeSource.mm +++ /dev/null @@ -1,355 +0,0 @@ -#import "MGLFoundation_Private.h" -#import "MGLShapeSource_Private.h" - -#import "MGLLoggingConfiguration_Private.h" -#import "MGLStyle_Private.h" -#import "MGLStyleValue_Private.h" -#import "MGLMapView_Private.h" -#import "MGLSource_Private.h" -#import "MGLFeature_Private.h" -#import "MGLShape_Private.h" -#import "MGLCluster.h" - -#import "NSPredicate+MGLPrivateAdditions.h" -#import "NSURL+MGLAdditions.h" - -#include <mbgl/map/map.hpp> -#include <mbgl/style/sources/geojson_source.hpp> -#include <mbgl/renderer/renderer.hpp> - -const MGLShapeSourceOption MGLShapeSourceOptionBuffer = @"MGLShapeSourceOptionBuffer"; -const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius = @"MGLShapeSourceOptionClusterRadius"; -const MGLShapeSourceOption MGLShapeSourceOptionClustered = @"MGLShapeSourceOptionClustered"; -const MGLShapeSourceOption MGLShapeSourceOptionClusterProperties = @"MGLShapeSourceOptionClusterProperties"; -const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel = @"MGLShapeSourceOptionMaximumZoomLevel"; -const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering = @"MGLShapeSourceOptionMaximumZoomLevelForClustering"; -const MGLShapeSourceOption MGLShapeSourceOptionMinimumZoomLevel = @"MGLShapeSourceOptionMinimumZoomLevel"; -const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLShapeSourceOptionSimplificationTolerance"; -const MGLShapeSourceOption MGLShapeSourceOptionLineDistanceMetrics = @"MGLShapeSourceOptionLineDistanceMetrics"; - -mbgl::Immutable<mbgl::style::GeoJSONOptions> MGLGeoJSONOptionsFromDictionary(NSDictionary<MGLShapeSourceOption, id> *options) { - auto geoJSONOptions = mbgl::makeMutable<mbgl::style::GeoJSONOptions>(); - - if (NSNumber *value = options[MGLShapeSourceOptionMinimumZoomLevel]) { - if (![value isKindOfClass:[NSNumber class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionMaximumZoomLevel must be an NSNumber."]; - } - geoJSONOptions->minzoom = value.integerValue; - } - - if (NSNumber *value = options[MGLShapeSourceOptionMaximumZoomLevel]) { - if (![value isKindOfClass:[NSNumber class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionMaximumZoomLevel must be an NSNumber."]; - } - geoJSONOptions->maxzoom = value.integerValue; - } - - if (NSNumber *value = options[MGLShapeSourceOptionBuffer]) { - if (![value isKindOfClass:[NSNumber class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionBuffer must be an NSNumber."]; - } - geoJSONOptions->buffer = value.integerValue; - } - - if (NSNumber *value = options[MGLShapeSourceOptionSimplificationTolerance]) { - if (![value isKindOfClass:[NSNumber class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionSimplificationTolerance must be an NSNumber."]; - } - geoJSONOptions->tolerance = value.doubleValue; - } - - if (NSNumber *value = options[MGLShapeSourceOptionClusterRadius]) { - if (![value isKindOfClass:[NSNumber class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionClusterRadius must be an NSNumber."]; - } - geoJSONOptions->clusterRadius = value.integerValue; - } - - if (NSNumber *value = options[MGLShapeSourceOptionMaximumZoomLevelForClustering]) { - if (![value isKindOfClass:[NSNumber class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionMaximumZoomLevelForClustering must be an NSNumber."]; - } - geoJSONOptions->clusterMaxZoom = value.integerValue; - } - - if (NSNumber *value = options[MGLShapeSourceOptionClustered]) { - if (![value isKindOfClass:[NSNumber class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionClustered must be an NSNumber."]; - } - geoJSONOptions->cluster = value.boolValue; - } - - if (NSDictionary *value = options[MGLShapeSourceOptionClusterProperties]) { - if (![value isKindOfClass:[NSDictionary<NSString *, NSArray *> class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionClusterProperties must be an NSDictionary with an NSString as a key and an array containing two NSExpression objects as a value."]; - } - - NSEnumerator *stringEnumerator = [value keyEnumerator]; - NSString *key; - - while (key = [stringEnumerator nextObject]) { - NSArray *expressionsArray = value[key]; - if (![expressionsArray isKindOfClass:[NSArray class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionClusterProperties dictionary member value must be an array containing two objects."]; - } - // Check that the array has 2 values. One should be a the reduce expression and one should be the map expression. - if ([expressionsArray count] != 2) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionClusterProperties member value requires array of two objects."]; - } - - // reduceExpression should be a valid NSExpression - NSExpression *reduceExpression = expressionsArray[0]; - if (![reduceExpression isKindOfClass:[NSExpression class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionClusterProperties array value requires two expression objects."]; - } - auto reduce = MGLClusterPropertyFromNSExpression(reduceExpression); - if (!reduce) { - [NSException raise:NSInvalidArgumentException - format:@"Failed to convert MGLShapeSourceOptionClusterProperties reduce expression."]; - } - - // mapExpression should be a valid NSExpression - NSExpression *mapExpression = expressionsArray[1]; - if (![mapExpression isKindOfClass:[NSExpression class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionClusterProperties member value must contain a valid NSExpression."]; - } - auto map = MGLClusterPropertyFromNSExpression(mapExpression); - if (!map) { - [NSException raise:NSInvalidArgumentException - format:@"Failed to convert MGLShapeSourceOptionClusterProperties map expression."]; - } - - std::string keyString = std::string([key UTF8String]); - - geoJSONOptions->clusterProperties.emplace(keyString, std::make_pair(std::move(map), std::move(reduce))); - } - } - - if (NSNumber *value = options[MGLShapeSourceOptionLineDistanceMetrics]) { - if (![value isKindOfClass:[NSNumber class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionLineDistanceMetrics must be an NSNumber."]; - } - geoJSONOptions->lineMetrics = value.boolValue; - } - - return geoJSONOptions; -} - -@interface MGLShapeSource () - -@property (nonatomic, readwrite) NSDictionary *options; -@property (nonatomic, readonly) mbgl::style::GeoJSONSource *rawSource; - -@end - -@implementation MGLShapeSource - -- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(NSDictionary<NSString *, id> *)options { - auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options); - auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, std::move(geoJSONOptions)); - if (self = [super initWithPendingSource:std::move(source)]) { - self.URL = url; - } - return self; -} - -- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(NSDictionary<MGLShapeSourceOption, id> *)options { - auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options); - auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, std::move(geoJSONOptions)); - if (self = [super initWithPendingSource:std::move(source)]) { - if ([shape isMemberOfClass:[MGLShapeCollection class]]) { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - NSLog(@"MGLShapeCollection initialized with MGLFeatures will not retain attributes." - @"Use MGLShapeCollectionFeature to retain attributes instead." - @"This will be logged only once."); - }); - } - self.shape = shape; - } - return self; -} - -- (instancetype)initWithIdentifier:(NSString *)identifier features:(NSArray<MGLShape<MGLFeature> *> *)features options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options { - for (id <MGLFeature> feature in features) { - if (![feature conformsToProtocol:@protocol(MGLFeature)]) { - [NSException raise:NSInvalidArgumentException format:@"The object %@ included in the features argument does not conform to the MGLFeature protocol.", feature]; - } - } - MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:features]; - return [self initWithIdentifier:identifier shape:shapeCollectionFeature options:options]; -} - -- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NSArray<MGLShape *> *)shapes options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options { - MGLShapeCollection *shapeCollection = [MGLShapeCollection shapeCollectionWithShapes:shapes]; - return [self initWithIdentifier:identifier shape:shapeCollection options:options]; -} - -- (mbgl::style::GeoJSONSource *)rawSource { - return (mbgl::style::GeoJSONSource *)super.rawSource; -} - -- (NSURL *)URL { - MGLAssertStyleSourceIsValid(); - auto url = self.rawSource->getURL(); - return url ? [NSURL URLWithString:@(url->c_str())] : nil; -} - -- (void)setURL:(NSURL *)url { - MGLAssertStyleSourceIsValid(); - if (url) { - self.rawSource->setURL(url.mgl_URLByStandardizingScheme.absoluteString.UTF8String); - _shape = nil; - } else { - self.shape = nil; - } -} - -- (void)setShape:(MGLShape *)shape { - MGLAssertStyleSourceIsValid(); - self.rawSource->setGeoJSON({ shape.geoJSONObject }); - _shape = shape; -} - -- (NSString *)description { - if (self.rawSource) { - return [NSString stringWithFormat:@"<%@: %p; identifier = %@; URL = %@; shape = %@>", - NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, self.shape]; - } - else { - return [NSString stringWithFormat:@"<%@: %p; identifier = %@; URL = <unknown>; shape = %@>", - NSStringFromClass([self class]), (void *)self, self.identifier, self.shape]; - } -} - -- (NSArray<id <MGLFeature>> *)featuresMatchingPredicate:(nullable NSPredicate *)predicate { - MGLAssertStyleSourceIsValid(); - mbgl::optional<mbgl::style::Filter> optionalFilter; - if (predicate) { - optionalFilter = predicate.mgl_filter; - } - - std::vector<mbgl::Feature> features; - if (self.mapView) { - features = self.mapView.renderer->querySourceFeatures(self.rawSource->getID(), { {}, optionalFilter }); - } - return MGLFeaturesFromMBGLFeatures(features); -} - -#pragma mark - MGLCluster management - -- (mbgl::optional<mbgl::FeatureExtensionValue>)featureExtensionValueOfCluster:(MGLShape<MGLCluster> *)cluster extension:(std::string)extension options:(const std::map<std::string, mbgl::Value>)options { - MGLAssertStyleSourceIsValid(); - mbgl::optional<mbgl::FeatureExtensionValue> extensionValue; - - // Check parameters - if (!self.rawSource || !self.mapView || !cluster) { - return extensionValue; - } - - auto geoJSON = [cluster geoJSONObject]; - - if (!geoJSON.is<mbgl::GeoJSONFeature>()) { - MGLAssert(0, @"cluster geoJSON object is not a feature."); - return extensionValue; - } - - auto clusterFeature = geoJSON.get<mbgl::GeoJSONFeature>(); - - extensionValue = self.mapView.renderer->queryFeatureExtensions(self.rawSource->getID(), - clusterFeature, - "supercluster", - extension, - options); - return extensionValue; -} - -- (NSArray<id <MGLFeature>> *)leavesOfCluster:(MGLPointFeatureCluster *)cluster offset:(NSUInteger)offset limit:(NSUInteger)limit { - const std::map<std::string, mbgl::Value> options = { - { "limit", static_cast<uint64_t>(limit) }, - { "offset", static_cast<uint64_t>(offset) } - }; - - auto featureExtension = [self featureExtensionValueOfCluster:cluster extension:"leaves" options:options]; - - if (!featureExtension) { - return @[]; - } - - if (!featureExtension->is<mbgl::FeatureCollection>()) { - return @[]; - } - - std::vector<mbgl::GeoJSONFeature> leaves = featureExtension->get<mbgl::FeatureCollection>(); - return MGLFeaturesFromMBGLFeatures(leaves); -} - -- (NSArray<id <MGLFeature>> *)childrenOfCluster:(MGLPointFeatureCluster *)cluster { - auto featureExtension = [self featureExtensionValueOfCluster:cluster extension:"children" options:{}]; - - if (!featureExtension) { - return @[]; - } - - if (!featureExtension->is<mbgl::FeatureCollection>()) { - return @[]; - } - - std::vector<mbgl::GeoJSONFeature> leaves = featureExtension->get<mbgl::FeatureCollection>(); - return MGLFeaturesFromMBGLFeatures(leaves); -} - -- (double)zoomLevelForExpandingCluster:(MGLPointFeatureCluster *)cluster { - auto featureExtension = [self featureExtensionValueOfCluster:cluster extension:"expansion-zoom" options:{}]; - - if (!featureExtension) { - return -1.0; - } - - if (!featureExtension->is<mbgl::Value>()) { - return -1.0; - } - - auto value = featureExtension->get<mbgl::Value>(); - if (value.is<uint64_t>()) { - auto zoom = value.get<uint64_t>(); - return static_cast<double>(zoom); - } - - return -1.0; -} - -- (void)debugRecursiveLogForFeature:(id <MGLFeature>)feature indent:(NSUInteger)indent { - NSString *description = feature.description; - - // Want our recursive log on a single line - NSString *log = [description stringByReplacingOccurrencesOfString:@"\\s+" - withString:@" " - options:NSRegularExpressionSearch - range:NSMakeRange(0, description.length)]; - - printf("%*s%s\n", (int)indent, "", log.UTF8String); - - MGLPointFeatureCluster *cluster = MGL_OBJC_DYNAMIC_CAST(feature, MGLPointFeatureCluster); - - if (cluster) { - for (id <MGLFeature> child in [self childrenOfCluster:cluster]) { - [self debugRecursiveLogForFeature:child indent:indent + 4]; - } - } -} - -@end |