diff options
Diffstat (limited to 'platform/darwin/src/MGLShapeSource.mm')
-rw-r--r-- | platform/darwin/src/MGLShapeSource.mm | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm new file mode 100644 index 0000000000..d062e656c2 --- /dev/null +++ b/platform/darwin/src/MGLShapeSource.mm @@ -0,0 +1,165 @@ +#import "MGLShapeSource_Private.h" + +#import "MGLMapView_Private.h" +#import "MGLSource_Private.h" +#import "MGLFeature_Private.h" +#import "MGLShape_Private.h" + +#import "NSURL+MGLAdditions.h" + +#include <mbgl/style/sources/geojson_source.hpp> + +const MGLShapeSourceOption MGLShapeSourceOptionClustered = @"MGLShapeSourceOptionClustered"; +const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius = @"MGLShapeSourceOptionClusterRadius"; +const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering = @"MGLShapeSourceOptionMaximumZoomLevelForClustering"; +const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel = @"MGLShapeSourceOptionMaximumZoomLevel"; +const MGLShapeSourceOption MGLShapeSourceOptionBuffer = @"MGLShapeSourceOptionBuffer"; +const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLShapeSourceOptionSimplificationTolerance"; + +@interface MGLShapeSource () + +- (instancetype)initWithRawSource:(mbgl::style::GeoJSONSource *)rawSource NS_DESIGNATED_INITIALIZER; + +@property (nonatomic, readwrite) NSDictionary *options; +@property (nonatomic) mbgl::style::GeoJSONSource *rawSource; + +@end + +@implementation MGLShapeSource { + std::unique_ptr<mbgl::style::GeoJSONSource> _pendingSource; +} + +- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(NS_DICTIONARY_OF(NSString *, id) *)options { + if (self = [super initWithIdentifier:identifier]) { + auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options); + auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions); + + _pendingSource = std::move(source); + self.rawSource = _pendingSource.get(); + + self.URL = url; + } + return self; +} + +- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options { + if (self = [super initWithIdentifier:identifier]) { + auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options); + auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions); + + _pendingSource = std::move(source); + self.rawSource = _pendingSource.get(); + + self.shape = shape; + } + return self; +} + +- (instancetype)initWithRawSource:(mbgl::style::GeoJSONSource *)rawSource { + return [super initWithRawSource:rawSource]; +} + +- (void)addToMapView:(MGLMapView *)mapView { + if (_pendingSource == nullptr) { + [NSException raise:@"MGLRedundantSourceException" + format:@"This instance %@ was already added to %@. Adding the same source instance " \ + "to the style more than once is invalid.", self, mapView.style]; + } + + mapView.mbglMap->addSource(std::move(_pendingSource)); +} + +- (void)removeFromMapView:(MGLMapView *)mapView { + auto removedSource = mapView.mbglMap->removeSource(self.identifier.UTF8String); + + _pendingSource = std::move(reinterpret_cast<std::unique_ptr<mbgl::style::GeoJSONSource> &>(removedSource)); + self.rawSource = _pendingSource.get(); +} + +- (mbgl::style::GeoJSONSource *)rawSource { + return (mbgl::style::GeoJSONSource *)super.rawSource; +} + +- (void)setRawSource:(mbgl::style::GeoJSONSource *)rawSource { + super.rawSource = rawSource; +} + +- (NSURL *)URL { + auto url = self.rawSource->getURL(); + return url ? [NSURL URLWithString:@(url->c_str())] : nil; +} + +- (void)setURL:(NSURL *)url { + if (url) { + self.rawSource->setURL(url.mgl_URLByStandardizingScheme.absoluteString.UTF8String); + _shape = nil; + } else { + self.shape = nil; + } +} + +- (void)setShape:(MGLShape *)shape { + self.rawSource->setGeoJSON({ shape.geoJSONObject }); + _shape = shape; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p; identifier = %@; URL = %@; shape = %@>", + NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, self.shape]; +} + +@end + +mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options) { + auto geoJSONOptions = mbgl::style::GeoJSONOptions(); + + 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; + } + + return geoJSONOptions; +} |