summaryrefslogtreecommitdiff
path: root/platform/darwin/src/MGLShapeSource.mm
diff options
context:
space:
mode:
Diffstat (limited to 'platform/darwin/src/MGLShapeSource.mm')
-rw-r--r--platform/darwin/src/MGLShapeSource.mm165
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;
+}