diff options
Diffstat (limited to 'platform/darwin/src')
68 files changed, 2844 insertions, 1483 deletions
diff --git a/platform/darwin/src/MGLAttributionInfo.h b/platform/darwin/src/MGLAttributionInfo.h new file mode 100644 index 0000000000..7395e3f346 --- /dev/null +++ b/platform/darwin/src/MGLAttributionInfo.h @@ -0,0 +1,62 @@ +#import <Foundation/Foundation.h> +#import <CoreGraphics/CoreGraphics.h> +#import <CoreLocation/CoreLocation.h> + +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Information about an attribution statement, usually a copyright or trademark + statement, associated with a map content source. + */ +@interface MGLAttributionInfo : NSObject + +/** + Returns an initialized attribution info object with the given title and URL. + + @param title The attribution statement’s title. + @param URL A URL to more information about the entity named in the attribution. + @return An initialized attribution info object. + */ +- (instancetype)initWithTitle:(NSAttributedString *)title URL:(nullable NSURL *)URL; + +/** + The attribution statement’s attributed title text. + */ +@property (nonatomic) NSAttributedString *title; + +/** + The URL to more information about the entity named in the attribution. + + If this property is set, the attribution statement should be displayed as a + hyperlink or action button. Otherwise, if it is `nil`, the attribution + statement should be displayed as plain text. + */ +@property (nonatomic, nullable) NSURL *URL; + +/** + A Boolean value indicating whether the attribution statement is a shortcut to a + feedback tool. + + If this property is set, the statement should be treated as a way for the user + to provide feedback rather than an attribution statement. + */ +@property (nonatomic, getter=isFeedbackLink) BOOL feedbackLink; + +/** + Returns a copy of the `URL` property modified to account for the given center + coordinate and zoom level. + + @param centerCoordinate The map’s center coordinate. + @param zoomLevel The map’s zoom level. See `MGLMapView`’s `zoomLevel` property + for more information. + @return A modified URL containing a fragment that points to the specified + viewport. If the `feedbackLink` property is set to `NO`, this method returns + `nil`. + */ +- (nullable NSURL *)feedbackURLAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLAttributionInfo.mm b/platform/darwin/src/MGLAttributionInfo.mm new file mode 100644 index 0000000000..cf7b3cb22f --- /dev/null +++ b/platform/darwin/src/MGLAttributionInfo.mm @@ -0,0 +1,195 @@ +#import "MGLAttributionInfo_Private.h" + +#if TARGET_OS_IPHONE + #import <UIKit/UIKit.h> +#else + #import <Cocoa/Cocoa.h> +#endif + +#import "MGLMapCamera.h" +#import "NSArray+MGLAdditions.h" +#import "NSString+MGLAdditions.h" + +#include <string> + +@implementation MGLAttributionInfo + ++ (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor { + if (!htmlString) { + return @[]; + } + + NSDictionary *options = @{ + NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, + NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding), + }; + // Apply a bogus, easily detectable style rule to any feedback link, since + // NSAttributedString doesn’t preserve the class attribute. + NSMutableString *css = [NSMutableString stringWithString: + @".mapbox-improve-map { -webkit-text-stroke-width: 1000px; }"]; + if (fontSize) { + [css appendFormat:@"html { font-size: %.1fpx; }", fontSize]; + } + if (linkColor) { + CGFloat red; + CGFloat green; + CGFloat blue; + CGFloat alpha; +#if !TARGET_OS_IPHONE + linkColor = [linkColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; +#endif + [linkColor getRed:&red green:&green blue:&blue alpha:&alpha]; + [css appendFormat: + @"a:link { color: rgba(%f%%, %f%%, %f%%, %f); }", + red * 100, green * 100, blue * 100, alpha]; + } + NSString *styledHTML = [NSString stringWithFormat:@"<style type='text/css'>%@</style>%@", css, htmlString]; + NSData *htmlData = [styledHTML dataUsingEncoding:NSUTF8StringEncoding]; + +#if TARGET_OS_IPHONE + NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithData:htmlData + options:options + documentAttributes:nil + error:NULL]; +#else + NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithHTML:htmlData + options:options + documentAttributes:nil]; +#endif + + NSMutableArray *infos = [NSMutableArray array]; + [attributedString enumerateAttribute:NSLinkAttributeName + inRange:attributedString.mgl_wholeRange + options:0 + usingBlock: + ^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) { + NSCAssert(!value || [value isKindOfClass:[NSURL class]], @"If present, URL attribute must be an NSURL."); + + // Detect feedback links by the bogus style rule applied above. + NSNumber *strokeWidth = [attributedString attribute:NSStrokeWidthAttributeName + atIndex:range.location + effectiveRange:NULL]; + BOOL isFeedbackLink = NO; + if ([strokeWidth floatValue] > 100) { + isFeedbackLink = YES; + [attributedString removeAttribute:NSStrokeWidthAttributeName range:range]; + } + + // Omit whitespace-only strings. + NSAttributedString *title = [[attributedString attributedSubstringFromRange:range] + mgl_attributedStringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if (!title.length) { + return; + } + + MGLAttributionInfo *info = [[MGLAttributionInfo alloc] initWithTitle:title URL:value]; + info.feedbackLink = isFeedbackLink; + [infos addObject:info]; + }]; + return infos; +} + ++ (NSAttributedString *)attributedStringForAttributionInfos:(NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos { + NSMutableArray *titles = [NSMutableArray arrayWithCapacity:attributionInfos.count]; + for (MGLAttributionInfo *info in attributionInfos) { + NSMutableAttributedString *title = info.title.mutableCopy; + if (info.URL) { + [title addAttribute:NSLinkAttributeName value:info.URL range:title.mgl_wholeRange]; + } + [titles addObject:title]; + } + return [titles mgl_attributedComponentsJoinedByString:@" "]; +} + +- (instancetype)initWithTitle:(NSAttributedString *)title URL:(NSURL *)URL { + if (self = [super init]) { + _title = title; + _URL = URL; + } + return self; +} + +- (nullable NSURL *)feedbackURLAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel { + if (!self.feedbackLink) { + return nil; + } + + NSURLComponents *components = [NSURLComponents componentsWithURL:self.URL resolvingAgainstBaseURL:NO]; + components.fragment = [NSString stringWithFormat:@"/%.5f/%.5f/%i", + centerCoordinate.longitude, centerCoordinate.latitude, (int)round(zoomLevel + 1)]; + return components.URL; +} + +- (BOOL)isEqual:(id)object { + return [object isKindOfClass:[self class]] && [[object title] isEqual:self.title] && [[object URL] isEqual:self.URL]; +} + +- (NSUInteger)hash { + return self.title.hash + self.URL.hash; +} + +/** + Returns whether the given attribution info object overlaps with the receiver by + its plain text title. + + @return `NSOrderedAscending` if the given object is a superset of the receiver, + `NSOrderedDescending` if it is a subset of the receiver, or `NSOrderedSame` + if there is no overlap. + */ +- (NSComparisonResult)subsetCompare:(MGLAttributionInfo *)otherInfo { + NSString *title = self.title.string; + NSString *otherTitle = otherInfo.title.string; + if ([title containsString:otherTitle]) { + return NSOrderedDescending; + } + if ([otherTitle containsString:title]) { + return NSOrderedAscending; + } + return NSOrderedSame; +} + +@end + +@implementation NSMutableArray (MGLAttributionInfoAdditions) + +- (void)growArrayByAddingAttributionInfo:(MGLAttributionInfo *)info { + __block BOOL didInsertInfo = NO; + __block BOOL shouldAddInfo = YES; + [self enumerateObjectsUsingBlock:^(MGLAttributionInfo * _Nonnull existingInfo, NSUInteger idx, BOOL * _Nonnull stop) { + switch ([info subsetCompare:existingInfo]) { + case NSOrderedDescending: + // The existing info object is a subset of the one we’re adding. + // Replace the existing object the first time we find a subset; + // remove the existing object every time after that. + if (didInsertInfo) { + [self removeObjectAtIndex:idx]; + } else { + [self replaceObjectAtIndex:idx withObject:info]; + didInsertInfo = YES; + } + break; + + case NSOrderedAscending: + // The info object we’re adding is a subset of the existing one. + // Don’t add the object and stop looking. + shouldAddInfo = NO; + *stop = YES; + break; + + default: + break; + } + }]; + if (shouldAddInfo && !didInsertInfo) { + // No overlapping infos were found, so append the info object. + [self addObject:info]; + } +} + +- (void)growArrayByAddingAttributionInfosFromArray:(NS_ARRAY_OF(MGLAttributionInfo *) *)infos { + for (MGLAttributionInfo *info in infos) { + [self growArrayByAddingAttributionInfo:info]; + } +} + +@end diff --git a/platform/darwin/src/MGLAttributionInfo_Private.h b/platform/darwin/src/MGLAttributionInfo_Private.h new file mode 100644 index 0000000000..c9a428b571 --- /dev/null +++ b/platform/darwin/src/MGLAttributionInfo_Private.h @@ -0,0 +1,48 @@ +#import <Foundation/Foundation.h> +#import <CoreGraphics/CoreGraphics.h> +#import <CoreLocation/CoreLocation.h> + +#import "MGLAttributionInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MGLAttributionInfo (Private) + +/** + Parses and returns the attribution infos contained in the given HTML source + code string. + + @param htmlString The HTML source code to parse. + @param fontSize The default text size in points. + @param linkColor The default link color. + */ ++ (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor; + ++ (NSAttributedString *)attributedStringForAttributionInfos:(NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos; + +@end + +@interface NSMutableArray (MGLAttributionInfoAdditions) + +/** + Adds the given attribution info object to the receiver as long as it isn’t + redundant to any object already in the receiver. Any existing object that is + redundant to the given object is replaced by the given object. + + @param info The info object to add to the receiver. + @return True if the given info object was added to the receiver. + */ +- (void)growArrayByAddingAttributionInfo:(MGLAttributionInfo *)info; + +/** + Adds each of the given attribution info objects to the receiver as long as it + isn’t redundant to any object already in the receiver. Any existing object that + is redundant to the given object is replaced by the given object. + + @param infos An array of info objects to add to the receiver. + */ +- (void)growArrayByAddingAttributionInfosFromArray:(NS_ARRAY_OF(MGLAttributionInfo *) *)infos; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLBackgroundStyleLayer.mm b/platform/darwin/src/MGLBackgroundStyleLayer.mm index 253414852a..f6a00de941 100644 --- a/platform/darwin/src/MGLBackgroundStyleLayer.mm +++ b/platform/darwin/src/MGLBackgroundStyleLayer.mm @@ -26,14 +26,24 @@ if (self = [super initWithIdentifier:identifier]) { auto layer = std::make_unique<mbgl::style::BackgroundLayer>(identifier.UTF8String); _pendingLayer = std::move(layer); - _rawLayer = _pendingLayer.get(); + self.rawLayer = _pendingLayer.get(); } return self; } -#pragma mark - Adding to and removing from a map view +- (mbgl::style::BackgroundLayer *)rawLayer +{ + return (mbgl::style::BackgroundLayer *)super.rawLayer; +} -- (void)addToMapView:(MGLMapView *)mapView +- (void)setRawLayer:(mbgl::style::BackgroundLayer *)rawLayer +{ + super.rawLayer = rawLayer; +} + +#pragma mark - Adding to and removing from a map view + +- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer { if (_pendingLayer == nullptr) { [NSException raise:@"MGLRedundantLayerException" @@ -41,11 +51,6 @@ "to the style more than once is invalid.", self, mapView.style]; } - [self addToMapView:mapView belowLayer:nil]; -} - -- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer -{ if (otherLayer) { const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String}; mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId); @@ -57,7 +62,7 @@ - (void)removeFromMapView:(MGLMapView *)mapView { _pendingLayer = nullptr; - _rawLayer = nullptr; + self.rawLayer = nullptr; auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String); if (!removedLayer) { @@ -72,7 +77,7 @@ removedLayer.release(); _pendingLayer = std::unique_ptr<mbgl::style::BackgroundLayer>(layer); - _rawLayer = _pendingLayer.get(); + self.rawLayer = _pendingLayer.get(); } #pragma mark - Accessing the Paint Attributes @@ -81,13 +86,13 @@ MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(backgroundColor); - _rawLayer->setBackgroundColor(mbglValue); + self.rawLayer->setBackgroundColor(mbglValue); } - (MGLStyleValue<MGLColor *> *)backgroundColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getBackgroundColor() ?: _rawLayer->getDefaultBackgroundColor(); + auto propertyValue = self.rawLayer->getBackgroundColor() ?: self.rawLayer->getDefaultBackgroundColor(); return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue); } @@ -95,13 +100,13 @@ MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(backgroundOpacity); - _rawLayer->setBackgroundOpacity(mbglValue); + self.rawLayer->setBackgroundOpacity(mbglValue); } - (MGLStyleValue<NSNumber *> *)backgroundOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getBackgroundOpacity() ?: _rawLayer->getDefaultBackgroundOpacity(); + auto propertyValue = self.rawLayer->getBackgroundOpacity() ?: self.rawLayer->getDefaultBackgroundOpacity(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -109,13 +114,13 @@ MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(backgroundPattern); - _rawLayer->setBackgroundPattern(mbglValue); + self.rawLayer->setBackgroundPattern(mbglValue); } - (MGLStyleValue<NSString *> *)backgroundPattern { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getBackgroundPattern() ?: _rawLayer->getDefaultBackgroundPattern(); + auto propertyValue = self.rawLayer->getBackgroundPattern() ?: self.rawLayer->getDefaultBackgroundPattern(); return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue); } diff --git a/platform/darwin/src/MGLCircleStyleLayer.mm b/platform/darwin/src/MGLCircleStyleLayer.mm index 781682d4d1..e8ee2bca7e 100644 --- a/platform/darwin/src/MGLCircleStyleLayer.mm +++ b/platform/darwin/src/MGLCircleStyleLayer.mm @@ -39,15 +39,26 @@ namespace mbgl { if (self = [super initWithIdentifier:identifier source:source]) { auto layer = std::make_unique<mbgl::style::CircleLayer>(identifier.UTF8String, source.identifier.UTF8String); _pendingLayer = std::move(layer); - _rawLayer = _pendingLayer.get(); + self.rawLayer = _pendingLayer.get(); } return self; } + +- (mbgl::style::CircleLayer *)rawLayer +{ + return (mbgl::style::CircleLayer *)super.rawLayer; +} + +- (void)setRawLayer:(mbgl::style::CircleLayer *)rawLayer +{ + super.rawLayer = rawLayer; +} + - (NSString *)sourceLayerIdentifier { MGLAssertStyleLayerIsValid(); - auto layerID = _rawLayer->getSourceLayer(); + auto layerID = self.rawLayer->getSourceLayer(); return layerID.empty() ? nil : @(layerID.c_str()); } @@ -55,25 +66,26 @@ namespace mbgl { { MGLAssertStyleLayerIsValid(); - _rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: ""); + self.rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: ""); } - (void)setPredicate:(NSPredicate *)predicate { MGLAssertStyleLayerIsValid(); - _rawLayer->setFilter(predicate.mgl_filter); + self.rawLayer->setFilter(predicate.mgl_filter); } - (NSPredicate *)predicate { MGLAssertStyleLayerIsValid(); - return [NSPredicate mgl_predicateWithFilter:_rawLayer->getFilter()]; + return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()]; } -#pragma mark - Adding to and removing from a map view -- (void)addToMapView:(MGLMapView *)mapView +#pragma mark - Adding to and removing from a map view + +- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer { if (_pendingLayer == nullptr) { [NSException raise:@"MGLRedundantLayerException" @@ -81,11 +93,6 @@ namespace mbgl { "to the style more than once is invalid.", self, mapView.style]; } - [self addToMapView:mapView belowLayer:nil]; -} - -- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer -{ if (otherLayer) { const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String}; mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId); @@ -97,7 +104,7 @@ namespace mbgl { - (void)removeFromMapView:(MGLMapView *)mapView { _pendingLayer = nullptr; - _rawLayer = nullptr; + self.rawLayer = nullptr; auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String); if (!removedLayer) { @@ -112,7 +119,7 @@ namespace mbgl { removedLayer.release(); _pendingLayer = std::unique_ptr<mbgl::style::CircleLayer>(layer); - _rawLayer = _pendingLayer.get(); + self.rawLayer = _pendingLayer.get(); } #pragma mark - Accessing the Paint Attributes @@ -121,13 +128,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleBlur); - _rawLayer->setCircleBlur(mbglValue); + self.rawLayer->setCircleBlur(mbglValue); } - (MGLStyleValue<NSNumber *> *)circleBlur { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getCircleBlur() ?: _rawLayer->getDefaultCircleBlur(); + auto propertyValue = self.rawLayer->getCircleBlur() ?: self.rawLayer->getDefaultCircleBlur(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -135,13 +142,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(circleColor); - _rawLayer->setCircleColor(mbglValue); + self.rawLayer->setCircleColor(mbglValue); } - (MGLStyleValue<MGLColor *> *)circleColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getCircleColor() ?: _rawLayer->getDefaultCircleColor(); + auto propertyValue = self.rawLayer->getCircleColor() ?: self.rawLayer->getDefaultCircleColor(); return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue); } @@ -149,13 +156,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleOpacity); - _rawLayer->setCircleOpacity(mbglValue); + self.rawLayer->setCircleOpacity(mbglValue); } - (MGLStyleValue<NSNumber *> *)circleOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getCircleOpacity() ?: _rawLayer->getDefaultCircleOpacity(); + auto propertyValue = self.rawLayer->getCircleOpacity() ?: self.rawLayer->getDefaultCircleOpacity(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -163,13 +170,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCirclePitchScale>().toEnumPropertyValue(circlePitchScale); - _rawLayer->setCirclePitchScale(mbglValue); + self.rawLayer->setCirclePitchScale(mbglValue); } - (MGLStyleValue<NSValue *> *)circlePitchScale { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getCirclePitchScale() ?: _rawLayer->getDefaultCirclePitchScale(); + auto propertyValue = self.rawLayer->getCirclePitchScale() ?: self.rawLayer->getDefaultCirclePitchScale(); return MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCirclePitchScale>().toEnumStyleValue(propertyValue); } @@ -177,13 +184,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleRadius); - _rawLayer->setCircleRadius(mbglValue); + self.rawLayer->setCircleRadius(mbglValue); } - (MGLStyleValue<NSNumber *> *)circleRadius { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getCircleRadius() ?: _rawLayer->getDefaultCircleRadius(); + auto propertyValue = self.rawLayer->getCircleRadius() ?: self.rawLayer->getDefaultCircleRadius(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -191,13 +198,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(circleStrokeColor); - _rawLayer->setCircleStrokeColor(mbglValue); + self.rawLayer->setCircleStrokeColor(mbglValue); } - (MGLStyleValue<MGLColor *> *)circleStrokeColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getCircleStrokeColor() ?: _rawLayer->getDefaultCircleStrokeColor(); + auto propertyValue = self.rawLayer->getCircleStrokeColor() ?: self.rawLayer->getDefaultCircleStrokeColor(); return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue); } @@ -205,13 +212,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleStrokeOpacity); - _rawLayer->setCircleStrokeOpacity(mbglValue); + self.rawLayer->setCircleStrokeOpacity(mbglValue); } - (MGLStyleValue<NSNumber *> *)circleStrokeOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getCircleStrokeOpacity() ?: _rawLayer->getDefaultCircleStrokeOpacity(); + auto propertyValue = self.rawLayer->getCircleStrokeOpacity() ?: self.rawLayer->getDefaultCircleStrokeOpacity(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -219,13 +226,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleStrokeWidth); - _rawLayer->setCircleStrokeWidth(mbglValue); + self.rawLayer->setCircleStrokeWidth(mbglValue); } - (MGLStyleValue<NSNumber *> *)circleStrokeWidth { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getCircleStrokeWidth() ?: _rawLayer->getDefaultCircleStrokeWidth(); + auto propertyValue = self.rawLayer->getCircleStrokeWidth() ?: self.rawLayer->getDefaultCircleStrokeWidth(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -233,13 +240,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(circleTranslate); - _rawLayer->setCircleTranslate(mbglValue); + self.rawLayer->setCircleTranslate(mbglValue); } - (MGLStyleValue<NSValue *> *)circleTranslate { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getCircleTranslate() ?: _rawLayer->getDefaultCircleTranslate(); + auto propertyValue = self.rawLayer->getCircleTranslate() ?: self.rawLayer->getDefaultCircleTranslate(); return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue); } @@ -247,13 +254,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslateAnchor>().toEnumPropertyValue(circleTranslateAnchor); - _rawLayer->setCircleTranslateAnchor(mbglValue); + self.rawLayer->setCircleTranslateAnchor(mbglValue); } - (MGLStyleValue<NSValue *> *)circleTranslateAnchor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getCircleTranslateAnchor() ?: _rawLayer->getDefaultCircleTranslateAnchor(); + auto propertyValue = self.rawLayer->getCircleTranslateAnchor() ?: self.rawLayer->getDefaultCircleTranslateAnchor(); return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslateAnchor>().toEnumStyleValue(propertyValue); } diff --git a/platform/darwin/src/MGLFeature.h b/platform/darwin/src/MGLFeature.h index 384c5a073e..ed4ff627b9 100644 --- a/platform/darwin/src/MGLFeature.h +++ b/platform/darwin/src/MGLFeature.h @@ -19,7 +19,7 @@ NS_ASSUME_NONNULL_BEGIN using `-[MGLMapView visibleFeaturesAtPoint:]` and related methods. Each feature object associates a shape with an identifier and attributes as specified by the source. Like ordinary `MGLAnnotation` objects, some kinds of `MGLFeature` - objects can also be added to a map view using an `MGLGeoJSONSource` or + objects can also be added to a map view using an `MGLShapeSource` or `-[MGLMapView addAnnotations:]` and related methods. */ @protocol MGLFeature <MGLAnnotation> @@ -52,7 +52,7 @@ NS_ASSUME_NONNULL_BEGIN layer reference. Note that while it is possible to change this value on feature instances obtained from `-[MGLMapView visibleFeaturesAtPoint:]` and related methods, there will be no effect on the map. Setting this value can be useful - when the feature instance is used to initialize an `MGLGeoJSONSource` and that + when the feature instance is used to initialize an `MGLShapeSource` and that source is added to the map and styled. */ @property (nonatomic, copy, nullable) id identifier; @@ -87,7 +87,7 @@ NS_ASSUME_NONNULL_BEGIN layer references. Note that while it is possible to change this value on feature instances obtained from `-[MGLMapView visibleFeaturesAtPoint:]` and related methods, there will be no effect on the map. Setting this value can be useful - when the feature instance is used to initialize an `MGLGeoJSONSource` and that + when the feature instance is used to initialize an `MGLShapeSource` and that source is added to the map and styled. */ @property (nonatomic, copy) NS_DICTIONARY_OF(NSString *, id) *attributes; diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm index 5483433710..c1e0c312a0 100644 --- a/platform/darwin/src/MGLFeature.mm +++ b/platform/darwin/src/MGLFeature.mm @@ -14,9 +14,10 @@ #import "NSExpression+MGLAdditions.h" #import <mbgl/util/geometry.hpp> +#import <mbgl/style/conversion/geojson.hpp> #import <mapbox/geometry/feature.hpp> -@interface MGLPointFeature () <MGLFeaturePrivate> +@interface MGLPointFeature () @end @implementation MGLPointFeature @@ -32,13 +33,13 @@ return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier); } -- (mbgl::Feature)mbglFeature { - return mbglFeature([self featureObject], identifier, self.attributes); +- (mbgl::GeoJSON)geoJSONObject { + return mbglFeature({[self geometryObject]}, identifier, self.attributes); } @end -@interface MGLPolylineFeature () <MGLFeaturePrivate> +@interface MGLPolylineFeature () @end @implementation MGLPolylineFeature @@ -54,13 +55,13 @@ return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier); } -- (mbgl::Feature)mbglFeature { - return mbglFeature([self featureObject], identifier, self.attributes); +- (mbgl::GeoJSON)geoJSONObject { + return mbglFeature({[self geometryObject]}, identifier, self.attributes); } @end -@interface MGLPolygonFeature () <MGLFeaturePrivate> +@interface MGLPolygonFeature () @end @implementation MGLPolygonFeature @@ -76,13 +77,13 @@ return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier); } -- (mbgl::Feature)mbglFeature { - return mbglFeature([self featureObject], identifier, self.attributes); +- (mbgl::GeoJSON)geoJSONObject { + return mbglFeature({[self geometryObject]}, identifier, self.attributes); } @end -@interface MGLPointCollectionFeature () <MGLFeaturePrivate> +@interface MGLPointCollectionFeature () @end @implementation MGLPointCollectionFeature @@ -98,13 +99,13 @@ return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier); } -- (mbgl::Feature)mbglFeature { - return mbglFeature([self featureObject], identifier, self.attributes); +- (mbgl::GeoJSON)geoJSONObject { + return mbglFeature({[self geometryObject]}, identifier, self.attributes); } @end -@interface MGLMultiPolylineFeature () <MGLFeaturePrivate> +@interface MGLMultiPolylineFeature () @end @implementation MGLMultiPolylineFeature @@ -120,13 +121,13 @@ return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier); } -- (mbgl::Feature)mbglFeature { - return mbglFeature([self featureObject], identifier, self.attributes); +- (mbgl::GeoJSON)geoJSONObject { + return mbglFeature({[self geometryObject]}, identifier, self.attributes); } @end -@interface MGLMultiPolygonFeature () <MGLFeaturePrivate> +@interface MGLMultiPolygonFeature () @end @implementation MGLMultiPolygonFeature @@ -142,13 +143,13 @@ return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier); } -- (mbgl::Feature)mbglFeature { - return mbglFeature([self featureObject], identifier, self.attributes); +- (mbgl::GeoJSON)geoJSONObject { + return mbglFeature({[self geometryObject]}, identifier, self.attributes); } @end -@interface MGLShapeCollectionFeature () <MGLFeaturePrivate> +@interface MGLShapeCollectionFeature () @end @implementation MGLShapeCollectionFeature @@ -170,10 +171,15 @@ return NSDictionaryFeatureForGeometry([super geoJSONDictionary], self.attributes, self.identifier); } -- (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}; +- (mbgl::GeoJSON)geoJSONObject { + mbgl::FeatureCollection featureCollection; + featureCollection.reserve(self.shapes.count); + for (MGLShape <MGLFeature> *feature in self.shapes) { + auto geoJSONObject = feature.geoJSONObject; + NSAssert(geoJSONObject.is<mbgl::Feature>(), @"Feature collection must only contain features."); + featureCollection.push_back(geoJSONObject.get<mbgl::Feature>()); + } + return featureCollection; } @end @@ -185,27 +191,27 @@ template <typename T> class GeometryEvaluator { public: - MGLShape <MGLFeaturePrivate> * operator()(const mbgl::Point<T> &geometry) const { + MGLShape <MGLFeature> * operator()(const mbgl::Point<T> &geometry) const { MGLPointFeature *feature = [[MGLPointFeature alloc] init]; feature.coordinate = toLocationCoordinate2D(geometry); return feature; } - MGLShape <MGLFeaturePrivate> * operator()(const mbgl::LineString<T> &geometry) const { + MGLShape <MGLFeature> * operator()(const mbgl::LineString<T> &geometry) const { std::vector<CLLocationCoordinate2D> coordinates = toLocationCoordinates2D(geometry); return [MGLPolylineFeature polylineWithCoordinates:&coordinates[0] count:coordinates.size()]; } - MGLShape <MGLFeaturePrivate> * operator()(const mbgl::Polygon<T> &geometry) const { + MGLShape <MGLFeature> * operator()(const mbgl::Polygon<T> &geometry) const { return toShape<MGLPolygonFeature>(geometry); } - MGLShape <MGLFeaturePrivate> * operator()(const mbgl::MultiPoint<T> &geometry) const { + MGLShape <MGLFeature> * operator()(const mbgl::MultiPoint<T> &geometry) const { std::vector<CLLocationCoordinate2D> coordinates = toLocationCoordinates2D(geometry); return [[MGLPointCollectionFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()]; } - MGLShape <MGLFeaturePrivate> * operator()(const mbgl::MultiLineString<T> &geometry) const { + MGLShape <MGLFeature> * operator()(const mbgl::MultiLineString<T> &geometry) const { NSMutableArray *polylines = [NSMutableArray arrayWithCapacity:geometry.size()]; for (auto &lineString : geometry) { std::vector<CLLocationCoordinate2D> coordinates = toLocationCoordinates2D(lineString); @@ -216,7 +222,7 @@ public: return [MGLMultiPolylineFeature multiPolylineWithPolylines:polylines]; } - MGLShape <MGLFeaturePrivate> * operator()(const mbgl::MultiPolygon<T> &geometry) const { + MGLShape <MGLFeature> * operator()(const mbgl::MultiPolygon<T> &geometry) const { NSMutableArray *polygons = [NSMutableArray arrayWithCapacity:geometry.size()]; for (auto &polygon : geometry) { [polygons addObject:toShape(polygon)]; @@ -225,11 +231,11 @@ public: return [MGLMultiPolygonFeature multiPolygonWithPolygons:polygons]; } - MGLShape <MGLFeaturePrivate> * operator()(const mapbox::geometry::geometry_collection<T> &collection) const { + MGLShape <MGLFeature> * operator()(const mapbox::geometry::geometry_collection<T> &collection) const { NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:collection.size()]; for (auto &geometry : collection) { // This is very much like the transformation that happens in MGLFeaturesFromMBGLFeatures(), but these are raw geometries with no associated feature IDs or attributes. - MGLShape <MGLFeaturePrivate> *shape = mapbox::geometry::geometry<T>::visit(geometry, *this); + MGLShape <MGLFeature> *shape = mapbox::geometry::geometry<T>::visit(geometry, *this); [shapes addObject:shape]; } return [MGLShapeCollectionFeature shapeCollectionWithShapes:shapes]; @@ -266,27 +272,60 @@ private: } }; +template <typename T> +class GeoJSONEvaluator { +public: + MGLShape <MGLFeature> * operator()(const mbgl::Geometry<T> &geometry) const { + GeometryEvaluator<T> evaluator; + MGLShape <MGLFeature> *shape = mapbox::geometry::geometry<T>::visit(geometry, evaluator); + return shape; + } + + MGLShape <MGLFeature> * operator()(const mbgl::Feature &feature) const { + MGLShape <MGLFeature> *shape = (MGLShape <MGLFeature> *)MGLFeatureFromMBGLFeature(feature); + return shape; + } + + MGLShape <MGLFeature> * operator()(const mbgl::FeatureCollection &collection) const { + NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:collection.size()]; + for (const auto &feature : collection) { + [shapes addObject:MGLFeatureFromMBGLFeature(feature)]; + } + return [MGLShapeCollectionFeature shapeCollectionWithShapes:shapes]; + } +}; + NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features) { NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:features.size()]; for (const auto &feature : features) { - NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:feature.properties.size()]; - for (auto &pair : feature.properties) { - auto &value = pair.second; - ValueEvaluator evaluator; - attributes[@(pair.first.c_str())] = mbgl::Value::visit(value, evaluator); - } - - GeometryEvaluator<double> evaluator; - MGLShape <MGLFeaturePrivate> *shape = mapbox::geometry::geometry<double>::visit(feature.geometry, evaluator); - if (feature.id) { - shape.identifier = mbgl::FeatureIdentifier::visit(*feature.id, ValueEvaluator()); - } - shape.attributes = attributes; - [shapes addObject:shape]; + [shapes addObject:MGLFeatureFromMBGLFeature(feature)]; } return shapes; } +id <MGLFeature> MGLFeatureFromMBGLFeature(const mbgl::Feature &feature) { + NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:feature.properties.size()]; + for (auto &pair : feature.properties) { + auto &value = pair.second; + ValueEvaluator evaluator; + attributes[@(pair.first.c_str())] = mbgl::Value::visit(value, evaluator); + } + GeometryEvaluator<double> evaluator; + MGLShape <MGLFeature> *shape = mapbox::geometry::geometry<double>::visit(feature.geometry, evaluator); + if (feature.id) { + shape.identifier = mbgl::FeatureIdentifier::visit(*feature.id, ValueEvaluator()); + } + shape.attributes = attributes; + + return shape; +} + +MGLShape* MGLShapeFromGeoJSON(const mapbox::geojson::geojson &geojson) { + GeoJSONEvaluator<double> evaluator; + MGLShape *shape = mapbox::geojson::geojson::visit(geojson, evaluator); + return shape; +} + mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *attributes) { if (identifier) { diff --git a/platform/darwin/src/MGLFeature_Private.h b/platform/darwin/src/MGLFeature_Private.h index e6858c7c11..97af509893 100644 --- a/platform/darwin/src/MGLFeature_Private.h +++ b/platform/darwin/src/MGLFeature_Private.h @@ -3,6 +3,7 @@ #import <mbgl/util/geo.hpp> #import <mbgl/util/feature.hpp> +#import <mbgl/style/conversion/geojson.hpp> NS_ASSUME_NONNULL_BEGIN @@ -13,6 +14,17 @@ NS_ASSUME_NONNULL_BEGIN NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features); /** + Returns an `MGLFeature` object converted from the given mbgl::Feature + */ +id <MGLFeature> MGLFeatureFromMBGLFeature(const mbgl::Feature &feature); + +/** + Returns an `MGLShape` representing the given geojson. The shape can be + a feature, a collection of features, or a geometry. + */ +MGLShape* MGLShapeFromGeoJSON(const mapbox::geojson::geojson &geojson); + +/** Takes an `mbgl::Feature` object, an identifer, and attributes dictionary and returns the feature object with converted `mbgl::FeatureIdentifier` and `mbgl::PropertyMap` properties. @@ -24,10 +36,4 @@ mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *at */ NS_DICTIONARY_OF(NSString *, id) *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier); -@protocol MGLFeaturePrivate <MGLFeature> - -- (mbgl::Feature)mbglFeature; - -@end - NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLFillStyleLayer.h b/platform/darwin/src/MGLFillStyleLayer.h index 9bbda26ce4..cf8c18b5c2 100644 --- a/platform/darwin/src/MGLFillStyleLayer.h +++ b/platform/darwin/src/MGLFillStyleLayer.h @@ -36,8 +36,13 @@ typedef NS_ENUM(NSUInteger, MGLFillTranslateAnchor) { Whether or not the fill should be antialiased. The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `YES`. Set this property to `nil` to reset it to the default value. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-antialias"><code>fill-antialias</code></a> paint property in the Mapbox Style Specification. */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillAntialias; +@property (nonatomic, null_resettable, getter=isFillAntialiased) MGLStyleValue<NSNumber *> *fillAntialiased; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillAntialias __attribute__((unavailable("Use fillAntialiased instead."))); #if TARGET_OS_IPHONE /** @@ -69,7 +74,7 @@ typedef NS_ENUM(NSUInteger, MGLFillTranslateAnchor) { /** The outline color of the fill. Matches the value of `fillColor` if unspecified. - This property is only applied to the style if `fillPattern` is set to `nil`, and `fillAntialias` is set to an `MGLStyleValue` object containing an `NSNumber` object containing `YES`. Otherwise, it is ignored. + This property is only applied to the style if `fillPattern` is set to `nil`, and `fillAntialiased` is set to an `MGLStyleValue` object containing an `NSNumber` object containing `YES`. Otherwise, it is ignored. */ @property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *fillOutlineColor; diff --git a/platform/darwin/src/MGLFillStyleLayer.mm b/platform/darwin/src/MGLFillStyleLayer.mm index 87a5144c6b..891ab85d0b 100644 --- a/platform/darwin/src/MGLFillStyleLayer.mm +++ b/platform/darwin/src/MGLFillStyleLayer.mm @@ -34,15 +34,26 @@ namespace mbgl { if (self = [super initWithIdentifier:identifier source:source]) { auto layer = std::make_unique<mbgl::style::FillLayer>(identifier.UTF8String, source.identifier.UTF8String); _pendingLayer = std::move(layer); - _rawLayer = _pendingLayer.get(); + self.rawLayer = _pendingLayer.get(); } return self; } + +- (mbgl::style::FillLayer *)rawLayer +{ + return (mbgl::style::FillLayer *)super.rawLayer; +} + +- (void)setRawLayer:(mbgl::style::FillLayer *)rawLayer +{ + super.rawLayer = rawLayer; +} + - (NSString *)sourceLayerIdentifier { MGLAssertStyleLayerIsValid(); - auto layerID = _rawLayer->getSourceLayer(); + auto layerID = self.rawLayer->getSourceLayer(); return layerID.empty() ? nil : @(layerID.c_str()); } @@ -50,25 +61,26 @@ namespace mbgl { { MGLAssertStyleLayerIsValid(); - _rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: ""); + self.rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: ""); } - (void)setPredicate:(NSPredicate *)predicate { MGLAssertStyleLayerIsValid(); - _rawLayer->setFilter(predicate.mgl_filter); + self.rawLayer->setFilter(predicate.mgl_filter); } - (NSPredicate *)predicate { MGLAssertStyleLayerIsValid(); - return [NSPredicate mgl_predicateWithFilter:_rawLayer->getFilter()]; + return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()]; } -#pragma mark - Adding to and removing from a map view -- (void)addToMapView:(MGLMapView *)mapView +#pragma mark - Adding to and removing from a map view + +- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer { if (_pendingLayer == nullptr) { [NSException raise:@"MGLRedundantLayerException" @@ -76,11 +88,6 @@ namespace mbgl { "to the style more than once is invalid.", self, mapView.style]; } - [self addToMapView:mapView belowLayer:nil]; -} - -- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer -{ if (otherLayer) { const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String}; mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId); @@ -92,7 +99,7 @@ namespace mbgl { - (void)removeFromMapView:(MGLMapView *)mapView { _pendingLayer = nullptr; - _rawLayer = nullptr; + self.rawLayer = nullptr; auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String); if (!removedLayer) { @@ -107,36 +114,41 @@ namespace mbgl { removedLayer.release(); _pendingLayer = std::unique_ptr<mbgl::style::FillLayer>(layer); - _rawLayer = _pendingLayer.get(); + self.rawLayer = _pendingLayer.get(); } #pragma mark - Accessing the Paint Attributes -- (void)setFillAntialias:(MGLStyleValue<NSNumber *> *)fillAntialias { +- (void)setFillAntialiased:(MGLStyleValue<NSNumber *> *)fillAntialiased { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(fillAntialias); - _rawLayer->setFillAntialias(mbglValue); + auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(fillAntialiased); + self.rawLayer->setFillAntialias(mbglValue); } -- (MGLStyleValue<NSNumber *> *)fillAntialias { +- (MGLStyleValue<NSNumber *> *)isFillAntialiased { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getFillAntialias() ?: _rawLayer->getDefaultFillAntialias(); + auto propertyValue = self.rawLayer->getFillAntialias() ?: self.rawLayer->getDefaultFillAntialias(); return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue); } + +- (void)setFillAntialias:(MGLStyleValue<NSNumber *> *)fillAntialias { + NSAssert(NO, @"Use -setFillAntialiased: instead."); +} + - (void)setFillColor:(MGLStyleValue<MGLColor *> *)fillColor { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(fillColor); - _rawLayer->setFillColor(mbglValue); + self.rawLayer->setFillColor(mbglValue); } - (MGLStyleValue<MGLColor *> *)fillColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getFillColor() ?: _rawLayer->getDefaultFillColor(); + auto propertyValue = self.rawLayer->getFillColor() ?: self.rawLayer->getDefaultFillColor(); return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue); } @@ -144,13 +156,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(fillOpacity); - _rawLayer->setFillOpacity(mbglValue); + self.rawLayer->setFillOpacity(mbglValue); } - (MGLStyleValue<NSNumber *> *)fillOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getFillOpacity() ?: _rawLayer->getDefaultFillOpacity(); + auto propertyValue = self.rawLayer->getFillOpacity() ?: self.rawLayer->getDefaultFillOpacity(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -158,13 +170,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(fillOutlineColor); - _rawLayer->setFillOutlineColor(mbglValue); + self.rawLayer->setFillOutlineColor(mbglValue); } - (MGLStyleValue<MGLColor *> *)fillOutlineColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getFillOutlineColor() ?: _rawLayer->getDefaultFillOutlineColor(); + auto propertyValue = self.rawLayer->getFillOutlineColor() ?: self.rawLayer->getDefaultFillOutlineColor(); return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue); } @@ -172,13 +184,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(fillPattern); - _rawLayer->setFillPattern(mbglValue); + self.rawLayer->setFillPattern(mbglValue); } - (MGLStyleValue<NSString *> *)fillPattern { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getFillPattern() ?: _rawLayer->getDefaultFillPattern(); + auto propertyValue = self.rawLayer->getFillPattern() ?: self.rawLayer->getDefaultFillPattern(); return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue); } @@ -186,13 +198,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(fillTranslate); - _rawLayer->setFillTranslate(mbglValue); + self.rawLayer->setFillTranslate(mbglValue); } - (MGLStyleValue<NSValue *> *)fillTranslate { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getFillTranslate() ?: _rawLayer->getDefaultFillTranslate(); + auto propertyValue = self.rawLayer->getFillTranslate() ?: self.rawLayer->getDefaultFillTranslate(); return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue); } @@ -200,13 +212,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslateAnchor>().toEnumPropertyValue(fillTranslateAnchor); - _rawLayer->setFillTranslateAnchor(mbglValue); + self.rawLayer->setFillTranslateAnchor(mbglValue); } - (MGLStyleValue<NSValue *> *)fillTranslateAnchor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getFillTranslateAnchor() ?: _rawLayer->getDefaultFillTranslateAnchor(); + auto propertyValue = self.rawLayer->getFillTranslateAnchor() ?: self.rawLayer->getDefaultFillTranslateAnchor(); return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslateAnchor>().toEnumStyleValue(propertyValue); } diff --git a/platform/darwin/src/MGLGeoJSONSource.h b/platform/darwin/src/MGLGeoJSONSource.h deleted file mode 100644 index 30232c6211..0000000000 --- a/platform/darwin/src/MGLGeoJSONSource.h +++ /dev/null @@ -1,144 +0,0 @@ -#import "MGLSource.h" - -#import "MGLTypes.h" - -NS_ASSUME_NONNULL_BEGIN - -@protocol MGLFeature; - -/** - Options for `MGLGeoJSONSource` objects. - */ -typedef NSString *MGLGeoJSONSourceOption NS_STRING_ENUM; - -/** - An `NSNumber` object containing a Boolean enabling or disabling clustering. - If the `features` property contains point features, setting this option to - `YES` clusters the points by radius into groups. The default value is `NO`. - */ -extern const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionClustered; - -/** - An `NSNumber` object containing an integer; specifies the radius of each - cluster if clustering is enabled. A value of 512 produces a radius equal to - the width of a tile. The default value is 50. - */ -extern const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionClusterRadius; - -/** - An `NSNumber` object containing an integer; specifies the maximum zoom level at - which to cluster points if clustering is enabled. Defaults to one zoom level - less than the value of `MGLGeoJSONSourceOptionMaximumZoomLevel` so that, at the - maximum zoom level, the features are not clustered. - */ -extern const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionMaximumZoomLevelForClustering; - -/** - An `NSNumber` object containing an integer; specifies the maximum zoom level at - which to create vector tiles. A greater value produces greater detail at high - zoom levels. The default value is 18. - */ -extern const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionMaximumZoomLevel; - -/** - An `NSNumber` object containing an integer; specifies the size of the tile - buffer on each side. A value of 0 produces no buffer. A value of 512 produces a - buffer as wide as the tile itself. Larger values produce fewer rendering - artifacts near tile edges and slower performance. The default value is 128. - */ -extern const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionBuffer; - -/** - An `NSNumber` object containing a double; specifies the Douglas-Peucker - simplification tolerance. A greater value produces simpler geometries and - improves performance. The default value is 0.375. - */ -extern const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionSimplificationTolerance; - -/** - A GeoJSON source. - - @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">The - style specification.</a> - */ -@interface MGLGeoJSONSource : MGLSource - -#pragma mark Initializing a Source - -/** - Returns a GeoJSON source initialized with an identifier, GeoJSON data, and a - dictionary of options for the source according to the - <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">style - specification</a>. - - @param identifier A string that uniquely identifies the source. - @param geoJSONData An `NSData` object representing GeoJSON source code. - @param options An `NSDictionary` of options for this source. - @return An initialized GeoJSON source. - */ -- (instancetype)initWithIdentifier:(NSString *)identifier geoJSONData:(NSData *)data options:(nullable NS_DICTIONARY_OF(MGLGeoJSONSourceOption, id) *)options NS_DESIGNATED_INITIALIZER; - -/** - Returns a GeoJSON source with an identifier, URL, and dictionary of options for - the source according to the - <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">style - specification</a>. - - @param identifier A string that uniquely identifies the source. - @param URL An HTTP(S) URL, absolute file URL, or local file URL relative to the - current application’s resource bundle. - @param options An `NSDictionary` of options for this source. - @return An initialized GeoJSON source. - */ -- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(nullable NS_DICTIONARY_OF(MGLGeoJSONSourceOption, id) *)options NS_DESIGNATED_INITIALIZER; - -/** - Returns a GeoJSON source with an identifier, features dictionary, and dictionary - of options for the source according to the - <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">style - specification</a>. - - @param identifier A string that uniquely identifies the source. - @param features An array of features that conform to the `MGLFeature` protocol. - @param options An `NSDictionary` of options for this source. - @return An initialized GeoJSON source. - */ -- (instancetype)initWithIdentifier:(NSString *)identifier features:(NSArray<id<MGLFeature>> *)features options:(nullable NS_DICTIONARY_OF(MGLGeoJSONSourceOption, id) *)options NS_DESIGNATED_INITIALIZER; - -#pragma mark Accessing a Source’s Content - -/** - The contents of the source. - - If the receiver was initialized using `-initWithIdentifier:URL:options:`, this property - is set to `nil`. This property is unavailable until the receiver is passed into - `-[MGLStyle addSource]`. - */ -@property (nonatomic, nullable) NS_ARRAY_OF(id <MGLFeature>) *features; - -/** - A GeoJSON representation of the contents of the source. - - Use the `features` property instead to get an object representation of the - contents. Alternatively, use `NSJSONSerialization` with the value of this - property to transform it into Foundation types. - - If the receiver was initialized using `-initWithIdentifier:URL:options` or - `-initWithIdentifier:features:options`, this property is set to `nil`. - This property is unavailable until the receiver is passed - into `-[MGLStyle addSource]`. - */ -@property (nonatomic, nullable, copy) NSData *geoJSONData; - -/** - The URL to the GeoJSON document that specifies the contents of the source. - - If the receiver was initialized using `-initWithIdentifier:geoJSONData:options`, this - property is set to `nil`. - */ -@property (nonatomic, nullable) NSURL *URL; - - -@end - -NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLGeoJSONSource.mm b/platform/darwin/src/MGLGeoJSONSource.mm deleted file mode 100644 index 8b37ba47cd..0000000000 --- a/platform/darwin/src/MGLGeoJSONSource.mm +++ /dev/null @@ -1,207 +0,0 @@ -#import "MGLGeoJSONSource_Private.h" - -#import "MGLMapView_Private.h" -#import "MGLSource_Private.h" -#import "MGLFeature_Private.h" - -#import "NSURL+MGLAdditions.h" - -#include <mbgl/style/sources/geojson_source.hpp> - -const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionClustered = @"MGLGeoJSONSourceOptionClustered"; -const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionClusterRadius = @"MGLGeoJSONSourceOptionClusterRadius"; -const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionMaximumZoomLevelForClustering = @"MGLGeoJSONSourceOptionMaximumZoomLevelForClustering"; -const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionMaximumZoomLevel = @"MGLGeoJSONSourceOptionMaximumZoomLevel"; -const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionBuffer = @"MGLGeoJSONSourceOptionBuffer"; -const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionSimplificationTolerance = @"MGLGeoJSONSourceOptionSimplificationTolerance"; - -@interface MGLGeoJSONSource () - -@property (nonatomic, readwrite) NSDictionary *options; -@property (nonatomic) mbgl::style::GeoJSONSource *rawSource; - -@end - -@implementation MGLGeoJSONSource -{ - std::unique_ptr<mbgl::style::GeoJSONSource> _pendingSource; -} - -- (instancetype)initWithIdentifier:(NSString *)identifier geoJSONData:(NSData *)data options:(NS_DICTIONARY_OF(NSString *, id) *)options -{ - if (self = [super initWithIdentifier:identifier]) - { - _geoJSONData = data; - _options = options; - [self commonInit]; - } - return self; -} - -- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(NS_DICTIONARY_OF(NSString *, id) *)options -{ - if (self = [super initWithIdentifier:identifier]) - { - _URL = url; - _options = options; - [self commonInit]; - } - return self; -} - -- (instancetype)initWithIdentifier:(NSString *)identifier features:(NSArray<id<MGLFeature>> *)features options:(NS_DICTIONARY_OF(NSString *,id) *)options { - if (self = [super initWithIdentifier:identifier]) { - _features = features; - _options = options; - [self commonInit]; - } - - return self; -} - -- (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(); -} - -- (void)commonInit -{ - auto source = std::make_unique<mbgl::style::GeoJSONSource>(self.identifier.UTF8String, self.geoJSONOptions); - - if (self.URL) { - NSURL *url = self.URL.mgl_URLByStandardizingScheme; - source->setURL(url.absoluteString.UTF8String); - _features = nil; - } else if (self.geoJSONData) { - NSString *string = [[NSString alloc] initWithData:self.geoJSONData encoding:NSUTF8StringEncoding]; - const auto geojson = mapbox::geojson::parse(string.UTF8String).get<mapbox::geojson::feature_collection>(); - source->setGeoJSON(geojson); - _features = MGLFeaturesFromMBGLFeatures(geojson); - } else { - mbgl::FeatureCollection featureCollection; - featureCollection.reserve(self.features.count); - for (id <MGLFeaturePrivate> feature in self.features) { - featureCollection.push_back([feature mbglFeature]); - } - const auto geojson = mbgl::GeoJSON{featureCollection}; - source->setGeoJSON(geojson); - _features = MGLFeaturesFromMBGLFeatures(featureCollection); - } - - _pendingSource = std::move(source); - self.rawSource = _pendingSource.get(); -} - -- (mbgl::style::GeoJSONOptions)geoJSONOptions -{ - auto mbglOptions = mbgl::style::GeoJSONOptions(); - - if (id value = self.options[MGLGeoJSONSourceOptionMaximumZoomLevel]) { - [self validateValue:value]; - mbglOptions.maxzoom = [value integerValue]; - } - - if (id value = self.options[MGLGeoJSONSourceOptionBuffer]) { - [self validateValue:value]; - mbglOptions.buffer = [value integerValue]; - } - - if (id value = self.options[MGLGeoJSONSourceOptionSimplificationTolerance]) { - [self validateValue:value]; - mbglOptions.tolerance = [value doubleValue]; - } - - if (id value = self.options[MGLGeoJSONSourceOptionClusterRadius]) { - [self validateValue:value]; - mbglOptions.clusterRadius = [value integerValue]; - } - - if (id value = self.options[MGLGeoJSONSourceOptionMaximumZoomLevelForClustering]) { - [self validateValue:value]; - mbglOptions.clusterMaxZoom = [value integerValue]; - } - - if (id value = self.options[MGLGeoJSONSourceOptionClustered]) { - [self validateValue:value]; - mbglOptions.cluster = [value boolValue]; - } - - return mbglOptions; -} - -- (void)validateValue:(id)value -{ - if (! [value isKindOfClass:[NSNumber class]]) - { - [NSException raise:@"Value not handled" format:@"%@ is not an NSNumber", value]; - } -} - -- (void)setGeoJSONData:(NSData *)geoJSONData -{ - _geoJSONData = geoJSONData; - - if (self.rawSource == NULL) - { - [self commonInit]; - } - - NSString *string = [[NSString alloc] initWithData:_geoJSONData encoding:NSUTF8StringEncoding]; - const auto geojson = mapbox::geojson::parse(string.UTF8String).get<mapbox::geojson::feature_collection>(); - self.rawSource->setGeoJSON(geojson); - - _features = MGLFeaturesFromMBGLFeatures(geojson); -} - -- (void)setURL:(NSURL *)URL -{ - _URL = URL; - - if (self.rawSource == NULL) - { - [self commonInit]; - } - - NSURL *url = self.URL.mgl_URLByStandardizingScheme; - self.rawSource->setURL(url.absoluteString.UTF8String); -} - -- (void)setFeatures:(NSArray *)features -{ - if (self.rawSource == NULL) - { - [self commonInit]; - } - - mbgl::FeatureCollection featureCollection; - featureCollection.reserve(features.count); - for (id <MGLFeaturePrivate> feature in features) { - featureCollection.push_back([feature mbglFeature]); - } - const auto geojson = mbgl::GeoJSON{featureCollection}; - self.rawSource->setGeoJSON(geojson); - - _features = MGLFeaturesFromMBGLFeatures(featureCollection); -} - -- (NSString *)description -{ - return [NSString stringWithFormat:@"<%@: %p; identifier = %@; URL = %@; geoJSONData = %@; features = %@>", - NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, self.geoJSONData, self.features]; -} - -@end diff --git a/platform/darwin/src/MGLGeoJSONSource_Private.h b/platform/darwin/src/MGLGeoJSONSource_Private.h deleted file mode 100644 index de5bb10fac..0000000000 --- a/platform/darwin/src/MGLGeoJSONSource_Private.h +++ /dev/null @@ -1,10 +0,0 @@ -#import "MGLGeoJSONSource.h" -#import "MGLGeoJSONSource_Private.h" - -#include <mbgl/style/sources/geojson_source.hpp> - -@interface MGLGeoJSONSource (Private) - -- (mbgl::style::GeoJSONOptions)geoJSONOptions; - -@end diff --git a/platform/darwin/src/MGLGeometry.h b/platform/darwin/src/MGLGeometry.h index e2a4d818b9..8e36b86d96 100644 --- a/platform/darwin/src/MGLGeometry.h +++ b/platform/darwin/src/MGLGeometry.h @@ -62,6 +62,14 @@ NS_INLINE BOOL MGLCoordinateBoundsEqualToCoordinateBounds(MGLCoordinateBounds bo bounds1.ne.longitude == bounds2.ne.longitude); } +/** Returns `YES` if the two coordinate bounds intersect. */ +NS_INLINE BOOL MGLCoordinateBoundsIntersectsCoordinateBounds(MGLCoordinateBounds bounds1, MGLCoordinateBounds bounds2) { + return (bounds1.ne.latitude > bounds2.sw.latitude && + bounds1.sw.latitude < bounds2.ne.latitude && + bounds1.ne.longitude > bounds2.sw.longitude && + bounds1.sw.longitude < bounds2.ne.longitude); +} + /** Returns `YES` if the coordinate is within the coordinate bounds. */ NS_INLINE BOOL MGLCoordinateInCoordinateBounds(CLLocationCoordinate2D coordinate, MGLCoordinateBounds bounds) { return (coordinate.latitude >= bounds.sw.latitude && diff --git a/platform/darwin/src/MGLLineStyleLayer.h b/platform/darwin/src/MGLLineStyleLayer.h index 74d8f7bfe9..c47c7d5166 100644 --- a/platform/darwin/src/MGLLineStyleLayer.h +++ b/platform/darwin/src/MGLLineStyleLayer.h @@ -141,8 +141,13 @@ typedef NS_ENUM(NSUInteger, MGLLineTranslateAnchor) { This property is measured in line widths. This property is only applied to the style if `linePattern` is set to `nil`. Otherwise, it is ignored. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-dasharray"><code>line-dasharray</code></a> paint property in the Mapbox Style Specification. */ -@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSNumber *> *> *lineDasharray; +@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSNumber *> *> *lineDashPattern; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSNumber *> *> *lineDasharray __attribute__((unavailable("Use lineDashPattern instead."))); /** Draws a line casing outside of a line's actual path. Value indicates the width of the inner gap. diff --git a/platform/darwin/src/MGLLineStyleLayer.mm b/platform/darwin/src/MGLLineStyleLayer.mm index b155ec65d6..48164ed0c8 100644 --- a/platform/darwin/src/MGLLineStyleLayer.mm +++ b/platform/darwin/src/MGLLineStyleLayer.mm @@ -46,15 +46,26 @@ namespace mbgl { if (self = [super initWithIdentifier:identifier source:source]) { auto layer = std::make_unique<mbgl::style::LineLayer>(identifier.UTF8String, source.identifier.UTF8String); _pendingLayer = std::move(layer); - _rawLayer = _pendingLayer.get(); + self.rawLayer = _pendingLayer.get(); } return self; } + +- (mbgl::style::LineLayer *)rawLayer +{ + return (mbgl::style::LineLayer *)super.rawLayer; +} + +- (void)setRawLayer:(mbgl::style::LineLayer *)rawLayer +{ + super.rawLayer = rawLayer; +} + - (NSString *)sourceLayerIdentifier { MGLAssertStyleLayerIsValid(); - auto layerID = _rawLayer->getSourceLayer(); + auto layerID = self.rawLayer->getSourceLayer(); return layerID.empty() ? nil : @(layerID.c_str()); } @@ -62,25 +73,26 @@ namespace mbgl { { MGLAssertStyleLayerIsValid(); - _rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: ""); + self.rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: ""); } - (void)setPredicate:(NSPredicate *)predicate { MGLAssertStyleLayerIsValid(); - _rawLayer->setFilter(predicate.mgl_filter); + self.rawLayer->setFilter(predicate.mgl_filter); } - (NSPredicate *)predicate { MGLAssertStyleLayerIsValid(); - return [NSPredicate mgl_predicateWithFilter:_rawLayer->getFilter()]; + return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()]; } -#pragma mark - Adding to and removing from a map view -- (void)addToMapView:(MGLMapView *)mapView +#pragma mark - Adding to and removing from a map view + +- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer { if (_pendingLayer == nullptr) { [NSException raise:@"MGLRedundantLayerException" @@ -88,11 +100,6 @@ namespace mbgl { "to the style more than once is invalid.", self, mapView.style]; } - [self addToMapView:mapView belowLayer:nil]; -} - -- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer -{ if (otherLayer) { const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String}; mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId); @@ -104,7 +111,7 @@ namespace mbgl { - (void)removeFromMapView:(MGLMapView *)mapView { _pendingLayer = nullptr; - _rawLayer = nullptr; + self.rawLayer = nullptr; auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String); if (!removedLayer) { @@ -119,7 +126,7 @@ namespace mbgl { removedLayer.release(); _pendingLayer = std::unique_ptr<mbgl::style::LineLayer>(layer); - _rawLayer = _pendingLayer.get(); + self.rawLayer = _pendingLayer.get(); } #pragma mark - Accessing the Layout Attributes @@ -128,13 +135,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::style::LineCapType, NSValue *, mbgl::style::LineCapType, MGLLineCap>().toEnumPropertyValue(lineCap); - _rawLayer->setLineCap(mbglValue); + self.rawLayer->setLineCap(mbglValue); } - (MGLStyleValue<NSValue *> *)lineCap { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getLineCap() ?: _rawLayer->getDefaultLineCap(); + auto propertyValue = self.rawLayer->getLineCap() ?: self.rawLayer->getDefaultLineCap(); return MGLStyleValueTransformer<mbgl::style::LineCapType, NSValue *, mbgl::style::LineCapType, MGLLineCap>().toEnumStyleValue(propertyValue); } @@ -142,13 +149,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toEnumPropertyValue(lineJoin); - _rawLayer->setLineJoin(mbglValue); + self.rawLayer->setLineJoin(mbglValue); } - (MGLStyleValue<NSValue *> *)lineJoin { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getLineJoin() ?: _rawLayer->getDefaultLineJoin(); + auto propertyValue = self.rawLayer->getLineJoin() ?: self.rawLayer->getDefaultLineJoin(); return MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toEnumStyleValue(propertyValue); } @@ -156,13 +163,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineMiterLimit); - _rawLayer->setLineMiterLimit(mbglValue); + self.rawLayer->setLineMiterLimit(mbglValue); } - (MGLStyleValue<NSNumber *> *)lineMiterLimit { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getLineMiterLimit() ?: _rawLayer->getDefaultLineMiterLimit(); + auto propertyValue = self.rawLayer->getLineMiterLimit() ?: self.rawLayer->getDefaultLineMiterLimit(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -170,13 +177,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineRoundLimit); - _rawLayer->setLineRoundLimit(mbglValue); + self.rawLayer->setLineRoundLimit(mbglValue); } - (MGLStyleValue<NSNumber *> *)lineRoundLimit { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getLineRoundLimit() ?: _rawLayer->getDefaultLineRoundLimit(); + auto propertyValue = self.rawLayer->getLineRoundLimit() ?: self.rawLayer->getDefaultLineRoundLimit(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -186,13 +193,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineBlur); - _rawLayer->setLineBlur(mbglValue); + self.rawLayer->setLineBlur(mbglValue); } - (MGLStyleValue<NSNumber *> *)lineBlur { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getLineBlur() ?: _rawLayer->getDefaultLineBlur(); + auto propertyValue = self.rawLayer->getLineBlur() ?: self.rawLayer->getDefaultLineBlur(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -200,41 +207,46 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(lineColor); - _rawLayer->setLineColor(mbglValue); + self.rawLayer->setLineColor(mbglValue); } - (MGLStyleValue<MGLColor *> *)lineColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getLineColor() ?: _rawLayer->getDefaultLineColor(); + auto propertyValue = self.rawLayer->getLineColor() ?: self.rawLayer->getDefaultLineColor(); return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue); } -- (void)setLineDasharray:(MGLStyleValue<NSArray<NSNumber *> *> *)lineDasharray { +- (void)setLineDashPattern:(MGLStyleValue<NSArray<NSNumber *> *> *)lineDashPattern { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer<std::vector<float>, NSArray<NSNumber *> *, float>().toPropertyValue(lineDasharray); - _rawLayer->setLineDasharray(mbglValue); + auto mbglValue = MGLStyleValueTransformer<std::vector<float>, NSArray<NSNumber *> *, float>().toPropertyValue(lineDashPattern); + self.rawLayer->setLineDasharray(mbglValue); } -- (MGLStyleValue<NSArray<NSNumber *> *> *)lineDasharray { +- (MGLStyleValue<NSArray<NSNumber *> *> *)lineDashPattern { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getLineDasharray() ?: _rawLayer->getDefaultLineDasharray(); + auto propertyValue = self.rawLayer->getLineDasharray() ?: self.rawLayer->getDefaultLineDasharray(); return MGLStyleValueTransformer<std::vector<float>, NSArray<NSNumber *> *, float>().toStyleValue(propertyValue); } + +- (void)setLineDasharray:(MGLStyleValue<NSArray<NSNumber *> *> *)lineDasharray { + NSAssert(NO, @"Use -setLineDashPattern: instead."); +} + - (void)setLineGapWidth:(MGLStyleValue<NSNumber *> *)lineGapWidth { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineGapWidth); - _rawLayer->setLineGapWidth(mbglValue); + self.rawLayer->setLineGapWidth(mbglValue); } - (MGLStyleValue<NSNumber *> *)lineGapWidth { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getLineGapWidth() ?: _rawLayer->getDefaultLineGapWidth(); + auto propertyValue = self.rawLayer->getLineGapWidth() ?: self.rawLayer->getDefaultLineGapWidth(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -242,13 +254,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineOffset); - _rawLayer->setLineOffset(mbglValue); + self.rawLayer->setLineOffset(mbglValue); } - (MGLStyleValue<NSNumber *> *)lineOffset { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getLineOffset() ?: _rawLayer->getDefaultLineOffset(); + auto propertyValue = self.rawLayer->getLineOffset() ?: self.rawLayer->getDefaultLineOffset(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -256,13 +268,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineOpacity); - _rawLayer->setLineOpacity(mbglValue); + self.rawLayer->setLineOpacity(mbglValue); } - (MGLStyleValue<NSNumber *> *)lineOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getLineOpacity() ?: _rawLayer->getDefaultLineOpacity(); + auto propertyValue = self.rawLayer->getLineOpacity() ?: self.rawLayer->getDefaultLineOpacity(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -270,13 +282,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(linePattern); - _rawLayer->setLinePattern(mbglValue); + self.rawLayer->setLinePattern(mbglValue); } - (MGLStyleValue<NSString *> *)linePattern { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getLinePattern() ?: _rawLayer->getDefaultLinePattern(); + auto propertyValue = self.rawLayer->getLinePattern() ?: self.rawLayer->getDefaultLinePattern(); return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue); } @@ -284,13 +296,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(lineTranslate); - _rawLayer->setLineTranslate(mbglValue); + self.rawLayer->setLineTranslate(mbglValue); } - (MGLStyleValue<NSValue *> *)lineTranslate { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getLineTranslate() ?: _rawLayer->getDefaultLineTranslate(); + auto propertyValue = self.rawLayer->getLineTranslate() ?: self.rawLayer->getDefaultLineTranslate(); return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue); } @@ -298,13 +310,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslateAnchor>().toEnumPropertyValue(lineTranslateAnchor); - _rawLayer->setLineTranslateAnchor(mbglValue); + self.rawLayer->setLineTranslateAnchor(mbglValue); } - (MGLStyleValue<NSValue *> *)lineTranslateAnchor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getLineTranslateAnchor() ?: _rawLayer->getDefaultLineTranslateAnchor(); + auto propertyValue = self.rawLayer->getLineTranslateAnchor() ?: self.rawLayer->getDefaultLineTranslateAnchor(); return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslateAnchor>().toEnumStyleValue(propertyValue); } @@ -312,13 +324,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineWidth); - _rawLayer->setLineWidth(mbglValue); + self.rawLayer->setLineWidth(mbglValue); } - (MGLStyleValue<NSNumber *> *)lineWidth { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getLineWidth() ?: _rawLayer->getDefaultLineWidth(); + auto propertyValue = self.rawLayer->getLineWidth() ?: self.rawLayer->getDefaultLineWidth(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } diff --git a/platform/darwin/src/MGLMultiPoint.h b/platform/darwin/src/MGLMultiPoint.h index 3431fc2483..ed40ee9cad 100644 --- a/platform/darwin/src/MGLMultiPoint.h +++ b/platform/darwin/src/MGLMultiPoint.h @@ -7,67 +7,133 @@ 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 + composed of multiple vertices. 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. + class to access information about the vertices of the line or polygon. */ @interface MGLMultiPoint : MGLShape /** - The array of coordinates associated with the shape. + The array of vertices associated with the shape. - This C array is a pointer to a structure inside the multipoint object, - which may have a lifetime shorter than the multipoint object and will - certainly not have a longer lifetime. Therefore, you should copy the C - array if it needs to be stored outside of the memory context in which you - use this property. + This C array is a pointer to a structure inside the multipoint object, which + may have a lifetime shorter than the multipoint object and will certainly not + have a longer lifetime. Therefore, you should copy the C array if it needs to + be stored outside of the memory context in which you use this property. */ @property (nonatomic, readonly) CLLocationCoordinate2D *coordinates NS_RETURNS_INNER_POINTER; -/** The number of coordinates associated with the shape. (read-only) */ +/** The number of vertices in the shape. */ @property (nonatomic, readonly) NSUInteger pointCount; /** - Retrieves one or more coordinates associated with the shape. + Retrieves the vertices of part of the shape. - @param coords On input, you must provide a C array of structures large enough - to hold the desired number of coordinates. On output, this structure - contains the requested coordinate data. - @param range The range of points you want. The `location` field indicates the - first point you are requesting, with `0` being the first point, `1` being - the second point, and so on. The `length` field indicates the number of - points you want. The array in _`coords`_ must be large enough to accommodate - the number of requested coordinates. + @param coords On input, you must provide a C array of `CLLocationCoordinate2D` + structures large enough to hold the desired number of coordinates. On + output, this structure contains the requested coordinate data. + @param range The range of vertices you want. The `location` field indicates + the first vertex you are requesting, with `0` being the first vertex, `1` + being the second vertex, and so on. The `length` field indicates the number + of vertices you want. The array in `coords` must be large enough to + accommodate the number of requested coordinates. */ - (void)getCoordinates:(CLLocationCoordinate2D *)coords range:(NSRange)range; /** - Updates one or more coordinates for the shape, which will instantaneously - cause the shape to be redrawn if it is currently visible on the map. + Sets the shape’s vertices to the given C array of vertices. - @param range The range of points to update. The `location` field indicates the - first point you are replacing, with `0` being the first point, `1` being - the second point, and so on. The `length` field indicates the number of - points to update. The array in _`coords`_ must be equal in number to the - length of the range. If you want to append to the existing coordinates - array use `-[MGLMultiPoint appendCoordinates:count:]`. @param coords The array of coordinates defining the shape. The data in this - array is copied to the object. + array is copied to the shape’s `coordinates` property. + @param count The number of coordinates from the `coords` array. */ -- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords; +- (void)setCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count; + +/** + Inserts the given vertices into the shape. If the shape is currently visible on + the map, it is redrawn immediately. + + @param coords The array of coordinates to insert into the shape. The data in + this array is copied to the shape’s `coordinate` property. + @param count The number of items in the `coords` array. + @param index The zero-based index at which the first coordinate in `coords` + will appear in the `coordinates` property. + */ +- (void)insertCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count atIndex:(NSUInteger)index; /** - Appends one or more coordinates for the shape, which will instantaneously - cause the shape to be redrawn if it is currently visible on the map. + Appends the given vertices to the shape. If the shape is currently visible on + the map, it is redrawn immediately. @param coords The array of coordinates to add to the shape. The data in this - array is copied to the new object. + array is copied to the shape’s `coordinate` property. @param count The number of items in the `coords` array. */ - (void)appendCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count; +/** + Replaces the vertices at the given range in the shape with the same number of + vertices from a given C array. If the shape is currently visible on the map, it + is redrawn immediately. + + The number of coordinates in `coords` must be equal to the length of `range`. + If you want to insert or delete one or more vertices, use the + `-replaceCoordinatesInRange:withCoordinates:count:` method. + + If `range` extends beyond the shape’s `coordinates` property, an + `NSRangeException` is raised. If you want to append new vertices to the shape, + use the `-appendCoordinates:count:` method. + + @param range The range of vertices to replace. The `location` field indicates + the first vertex you are replacing, with `0` being the first vertex, `1` + being the second vertex, and so on. The `length` field indicates the number + of vertices to replace. + @param coords The array of coordinates defining part of the shape. The data in + this array is copied to the shape’s `coordinate` property. + */ +- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords; + +/** + Replaces the vertices at the given range in the shape with the specified number + of vertices from a given C array. If the shape is currently visible on the map, + it is redrawn immediately. + + If `count` is greater than the `length` field of `range`, some vertices will + effectively be inserted into the shape. On the other hand, if `count` is less + than the `length` field of `range`, some vertices will effectively be removed. + + If `range` extends beyond the shape’s `coordinates` property, an + `NSRangeException` is raised. If you want to append new vertices to the shape, + use the `-appendCoordinates:count:` method. + + @param range The range of vertices to replace. The `location` field indicates + the first vertex you are replacing, with `0` being the first vertex, `1` + being the second vertex, and so on. The `length` field indicates the number + of vertices to replace. + @param coords The array of coordinates defining part of the shape. The data in + this array is copied to the shape’s `coordinates` property. + @param count The number of coordinates from the `coords` array to insert in + place of the coordinates in `range`. The sum of `range`’s length and this + count must not exceed the number of items currently in the `coordinates` + property. + */ +- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count; + +/** + Removes the vertices at the given range from the shape. If the shape is + currently visible on the map, it is redrawn immediately. + + If `range` extends beyond the shape’s `coordinates` property, an + `NSRangeException` is raised. + + @param range The range of vertices to remove. The `location` field indicates + the first vertex you are removing, with `0` being the first vertex, `1` + being the second vertex, and so on. The `length` field indicates the number + of vertices to remove. + */ +- (void)removeCoordinatesInRange:(NSRange)range; + @end NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm index 57b57889f3..c49e970c6b 100644 --- a/platform/darwin/src/MGLMultiPoint.mm +++ b/platform/darwin/src/MGLMultiPoint.mm @@ -2,19 +2,12 @@ #import "MGLGeometry_Private.h" #import "MGLTypes.h" -#import <mbgl/util/geo.hpp> - -mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) -{ - if (!cgColor) return { 0, 0, 0, 0 }; - NSCAssert(CGColorGetNumberOfComponents(cgColor) >= 4, @"Color must have at least 4 components"); - const CGFloat *components = CGColorGetComponents(cgColor); - return { (float)components[0], (float)components[1], (float)components[2], (float)components[3] }; -} +#include <mbgl/util/geo.hpp> +#include <mbgl/util/optional.hpp> @implementation MGLMultiPoint { - MGLCoordinateBounds _bounds; + mbgl::optional<mbgl::LatLngBounds> _bounds; std::vector<CLLocationCoordinate2D> _coordinates; } @@ -24,9 +17,11 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) if (self) { - NSAssert(count > 0, @"A multipoint must have coordinates"); + if (!count) { + [NSException raise:NSInvalidArgumentException + format:@"A multipoint must have at least one vertex."]; + } _coordinates = { coords, coords + count }; - [self computeBounds]; } return self; @@ -65,52 +60,87 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) std::copy(_coordinates.begin() + range.location, _coordinates.begin() + NSMaxRange(range), coords); } -- (void)appendCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count -{ +- (void)setCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count { + if (!count) { + [NSException raise:NSInvalidArgumentException + format:@"A multipoint must have at least one vertex."]; + } + + [self willChangeValueForKey:@"coordinates"]; + _coordinates = { coords, coords + count }; + _bounds = {}; + [self didChangeValueForKey:@"coordinates"]; +} + +- (void)insertCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count atIndex:(NSUInteger)index { + if (!count) { + return; + } + + if (index > _coordinates.size()) { + [NSException raise:NSRangeException + format:@"Invalid index %lu for existing coordinate count %ld", + (unsigned long)index, (unsigned long)[self pointCount]]; + } + [self willChangeValueForKey:@"coordinates"]; - _coordinates.insert(_coordinates.end(), count, *coords); - [self computeBounds]; + _coordinates.insert(_coordinates.begin() + index, count, *coords); + _bounds = {}; [self didChangeValueForKey:@"coordinates"]; } +- (void)appendCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count +{ + [self insertCoordinates:coords count:count atIndex:_coordinates.size()]; +} + - (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords { - if (range.length == 0) - { + [self replaceCoordinatesInRange:range withCoordinates:coords count:range.length]; +} + +- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count { + if (!count && !range.length) { return; } - if (NSMaxRange(range) > _coordinates.size()) - { + if (NSMaxRange(range) > _coordinates.size()) { [NSException raise:NSRangeException format:@"Invalid range %@ for existing coordinate count %ld", NSStringFromRange(range), (unsigned long)[self pointCount]]; } [self willChangeValueForKey:@"coordinates"]; - std::copy(coords, coords + range.length, _coordinates.begin() + range.location); - [self computeBounds]; + std::copy(coords, coords + MIN(count, range.length), _coordinates.begin() + range.location); + if (count >= range.length) { + _coordinates.insert(_coordinates.begin() + NSMaxRange(range), coords, coords + count - range.length); + } else { + _coordinates.erase(_coordinates.begin() + range.location + count, _coordinates.begin() + NSMaxRange(range)); + } + _bounds = {}; [self didChangeValueForKey:@"coordinates"]; } -- (void)computeBounds -{ - mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty(); - for (auto coordinate : _coordinates) - { - bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude)); - } - _bounds = MGLCoordinateBoundsFromLatLngBounds(bounds); +- (void)removeCoordinatesInRange:(NSRange)range { + CLLocationCoordinate2D coords; + [self replaceCoordinatesInRange:range withCoordinates:&coords count:0]; } - (MGLCoordinateBounds)overlayBounds { - return _bounds; + if (!_bounds) { + mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty(); + for (auto coordinate : _coordinates) { + bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude)); + } + _bounds = bounds; + } + return MGLCoordinateBoundsFromLatLngBounds(*_bounds); } - (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds { - return MGLLatLngBoundsFromCoordinateBounds(_bounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds)); + return MGLCoordinateBoundsIntersectsCoordinateBounds(self.overlayBounds, overlayBounds); } - (mbgl::Annotation)annotationObjectWithDelegate:(__unused id <MGLMultiPointDelegate>)delegate @@ -122,7 +152,8 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p; count = %lu; bounds = %@>", - NSStringFromClass([self class]), (void *)self, (unsigned long)[self pointCount], MGLStringFromCoordinateBounds(_bounds)]; + NSStringFromClass([self class]), (void *)self, (unsigned long)[self pointCount], + MGLStringFromCoordinateBounds(self.overlayBounds)]; } @end diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.h b/platform/darwin/src/MGLOpenGLStyleLayer.h new file mode 100644 index 0000000000..7cb6b147c2 --- /dev/null +++ b/platform/darwin/src/MGLOpenGLStyleLayer.h @@ -0,0 +1,34 @@ +#import <Foundation/Foundation.h> +#import <CoreLocation/CoreLocation.h> + +#import "MGLStyleValue.h" +#import "MGLStyleLayer.h" + +NS_ASSUME_NONNULL_BEGIN + +@class MGLMapView; + +typedef struct MGLStyleLayerDrawingContext { + CGSize size; + CLLocationCoordinate2D centerCoordinate; + double zoomLevel; + CLLocationDirection direction; + CGFloat pitch; + CGFloat perspectiveSkew; +} MGLStyleLayerDrawingContext; + +@interface MGLOpenGLStyleLayer : MGLStyleLayer + +@property (nonatomic, weak, readonly) MGLMapView *mapView; + +- (void)didMoveToMapView:(MGLMapView *)mapView; + +- (void)willMoveFromMapView:(MGLMapView *)mapView; + +- (void)drawInMapView:(MGLMapView *)mapView withContext:(MGLStyleLayerDrawingContext)context; + +- (void)setNeedsDisplay; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.mm b/platform/darwin/src/MGLOpenGLStyleLayer.mm new file mode 100644 index 0000000000..f109ea85b0 --- /dev/null +++ b/platform/darwin/src/MGLOpenGLStyleLayer.mm @@ -0,0 +1,209 @@ +#import "MGLOpenGLStyleLayer.h" + +#import "MGLMapView_Private.h" +#import "MGLStyle_Private.h" +#import "MGLStyleLayer_Private.h" + +#include <mbgl/style/layers/custom_layer.hpp> +#include <mbgl/math/wrap.hpp> + +/** + Runs the preparation handler block contained in the given context, which is + implicitly an instance of `MGLOpenGLStyleLayer`. + + @param context An `MGLOpenGLStyleLayer` instance that was provided as context + when creating an OpenGL style layer. + */ +void MGLPrepareCustomStyleLayer(void *context) { + MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context; + [layer didMoveToMapView:layer.mapView]; +} + +/** + Runs the drawing handler block contained in the given context, which is + implicitly an instance of `MGLOpenGLStyleLayer`. + + @param context An `MGLOpenGLStyleLayer` instance that was provided as context + when creating an OpenGL style layer. + */ +void MGLDrawCustomStyleLayer(void *context, const mbgl::style::CustomLayerRenderParameters ¶ms) { + MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context; + MGLStyleLayerDrawingContext drawingContext = { + .size = CGSizeMake(params.width, params.height), + .centerCoordinate = CLLocationCoordinate2DMake(params.latitude, params.longitude), + .zoomLevel = params.zoom, + .direction = mbgl::util::wrap(params.bearing, 0., 360.), + .pitch = static_cast<CGFloat>(params.pitch), + .perspectiveSkew = static_cast<CGFloat>(params.altitude), + }; + [layer drawInMapView:layer.mapView withContext:drawingContext]; +} + +/** + Runs the completion handler block contained in the given context, which is + implicitly an instance of `MGLOpenGLStyleLayer`. + + @param context An `MGLOpenGLStyleLayer` instance that was provided as context + when creating an OpenGL style layer. + */ +void MGLFinishCustomStyleLayer(void *context) { + MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context; + [layer willMoveFromMapView:layer.mapView]; +} + +/** + An `MGLOpenGLStyleLayer` is a style layer that is rendered by OpenGL code in + Objective-C blocks or Swift closures that you specify. You may initialize a new + OpenGL style layer to add to an `MGLStyle` or obtain one from an `MGLMapView`’s + current style using the `-[MGLStyle layerWithIdentifier:]` method. + + @warning This API is undocumented and therefore unsupported. It may change at + any time without notice. + */ +@interface MGLOpenGLStyleLayer () + +@property (nonatomic) mbgl::style::CustomLayer *rawLayer; + +/** + The map view whose style currently contains the layer. + + If the layer is not currently part of any map view’s style, this property is + set to `nil`. + */ +@property (nonatomic, weak, readwrite) MGLMapView *mapView; + +@end + +@implementation MGLOpenGLStyleLayer { + std::unique_ptr<mbgl::style::CustomLayer> _pendingLayer; +} + +/** + Returns an OpenGL style layer object initialized with the given identifier. + + After initializing and configuring the style layer, add it to a map view’s + style using the `-[MGLStyle addLayer:]` or + `-[MGLStyle insertLayer:belowLayer:]` method. + + @param identifier A string that uniquely identifies the layer in the style to + which it is added. + @return An initialized OpenGL style layer. + */ +- (instancetype)initWithIdentifier:(NSString *)identifier { + if (self = [super initWithIdentifier:identifier]) { + auto layer = std::make_unique<mbgl::style::CustomLayer>(identifier.UTF8String, + MGLPrepareCustomStyleLayer, + MGLDrawCustomStyleLayer, + MGLFinishCustomStyleLayer, + (__bridge void *)self); + _pendingLayer = std::move(layer); + self.rawLayer = _pendingLayer.get(); + } + return self; +} + +- (mbgl::style::CustomLayer *)rawLayer { + return (mbgl::style::CustomLayer *)super.rawLayer; +} + +- (void)setRawLayer:(mbgl::style::CustomLayer *)rawLayer { + super.rawLayer = rawLayer; +} + +#pragma mark - Adding to and removing from a map view + +- (void)setMapView:(MGLMapView *)mapView { + if (_mapView && mapView) { + [NSException raise:@"MGLLayerReuseException" + format:@"%@ cannot be added to more than one MGLStyle at a time.", self]; + } + _mapView.style.openGLLayers[self.identifier] = nil; + _mapView = mapView; + _mapView.style.openGLLayers[self.identifier] = self; +} + +- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer { + self.mapView = mapView; + if (otherLayer) { + const mbgl::optional<std::string> belowLayerId{ otherLayer.identifier.UTF8String }; + mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId); + } else { + mapView.mbglMap->addLayer(std::move(_pendingLayer)); + } +} + +- (void)removeFromMapView:(MGLMapView *)mapView { + auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String); + self.mapView = nil; + if (!removedLayer) { + return; + } + _pendingLayer = std::move(reinterpret_cast<std::unique_ptr<mbgl::style::CustomLayer> &>(removedLayer)); + self.rawLayer = _pendingLayer.get(); +} + +/** + Called immediately after a layer is added to a map view’s style. + + This method is intended to be overridden in a subclass. You can use this method + to perform any setup work before the layer is used to draw a frame. For + example, you might use this method to compile an OpenGL shader. The default + implementation of this method does nothing. + + Any resource acquired in this method must be released in + `-willMoveFromMapView:`. + + @param mapView The map view to whose style the layer has been added. + */ +- (void)didMoveToMapView:(MGLMapView *)mapView { + +} + +/** + Called immediately before a layer is removed from a map view’s style. + + This method is intended to be overridden in a subclass. You can use this method + to perform any teardown work once the layer has drawn its last frame and is + about to be removed from the style. The default implementation of this method + does nothing. + + This method may be called even if `-didMoveToMapView:` has not been called. + + @param mapView The map view from whose style the layer is about to be removed. + */ +- (void)willMoveFromMapView:(MGLMapView *)mapView { + +} + +/** + Called each time the layer needs to draw a new frame in a map view. + + This method is intended to be overridden in a subclass. You can use this method + to draw the layer’s content. The default implementation of this method does + nothing. + + Your implementation should not make any assumptions about the OpenGL state, + other than that the current OpenGL context is active. It may make changes to + the OpenGL state. It is not required to reset values such as the depth mask, + stencil mask, or corresponding test flags to their original values. + + Be sure to draw your fragments with a <var>z</var> value of 1 to take advantage + of the opaque fragment culling, in case the style contains any opaque layers + above this layer. + + @param mapView The map view to which the layer draws. + @param context A context structure with information defining the frame to draw. + */ +- (void)drawInMapView:(MGLMapView *)mapView withContext:(MGLStyleLayerDrawingContext)context { + +} + +/** + Forces the map view associated with this style to redraw the receiving layer, + causing the `-drawInMapView:withContext:` method to be called. + */ +- (void)setNeedsDisplay { + [self.mapView setNeedsGLDisplay]; +} + +@end diff --git a/platform/darwin/src/MGLOverlay.h b/platform/darwin/src/MGLOverlay.h index 48d10d9de1..1066a86d1e 100644 --- a/platform/darwin/src/MGLOverlay.h +++ b/platform/darwin/src/MGLOverlay.h @@ -17,14 +17,6 @@ NS_ASSUME_NONNULL_BEGIN example, you could use an overlay to show the boundaries of a national park or trace a bus route along city streets. This SDK defines several concrete classes that conform to this protocol and define standard shapes. - - Because overlays are also annotations, they have similar usage pattern to - annotations. When added to a map view using the `-addOverlay:` method, that - view detects whenever the overlay’s defined region intersects the visible - portion of the map. At that point, the map view asks its delegate to provide a - special overlay view to draw the visual representation of the overlay. If you - add an overlay to a map view as an annotation instead, it is treated as an - annotation with a single point. */ @protocol MGLOverlay <MGLAnnotation> diff --git a/platform/darwin/src/MGLPointAnnotation.mm b/platform/darwin/src/MGLPointAnnotation.mm index ce8e4a2355..d2e87f07d1 100644 --- a/platform/darwin/src/MGLPointAnnotation.mm +++ b/platform/darwin/src/MGLPointAnnotation.mm @@ -24,10 +24,10 @@ @"coordinates": @[@(self.coordinate.longitude), @(self.coordinate.latitude)]}; } -- (mbgl::Feature)featureObject +- (mbgl::Geometry<double>)geometryObject { mbgl::Point<double> point = { self.coordinate.longitude, self.coordinate.latitude }; - return mbgl::Feature {point}; + return point; } @end diff --git a/platform/darwin/src/MGLPointCollection.h b/platform/darwin/src/MGLPointCollection.h index ce3e95a16d..95af9dae5e 100644 --- a/platform/darwin/src/MGLPointCollection.h +++ b/platform/darwin/src/MGLPointCollection.h @@ -11,7 +11,7 @@ @note `MGLPointCollection` objects cannot be added to a map view using `-[MGLMapView addAnnotations:]` and related methods. However, when used in a - `MGLPointCollectionFeature` to initialize a `MGLGeoJSONSource` that is added + `MGLPointCollectionFeature` to initialize a `MGLShapeSource` that is added to the map view's style, the point collection represents as a group of distinct annotations. */ diff --git a/platform/darwin/src/MGLPointCollection.mm b/platform/darwin/src/MGLPointCollection.mm index ab4a9c978e..387a575b2d 100644 --- a/platform/darwin/src/MGLPointCollection.mm +++ b/platform/darwin/src/MGLPointCollection.mm @@ -1,17 +1,19 @@ #import "MGLPointCollection_Private.h" #import "MGLGeometry_Private.h" +#import <mbgl/util/geojson.hpp> #import <mbgl/util/geometry.hpp> -#import <mbgl/util/feature.hpp> NS_ASSUME_NONNULL_BEGIN @implementation MGLPointCollection { - MGLCoordinateBounds _bounds; + MGLCoordinateBounds _overlayBounds; std::vector<CLLocationCoordinate2D> _coordinates; } +@synthesize overlayBounds = _overlayBounds; + + (instancetype)pointCollectionWithCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count { return [[self alloc] initWithCoordinates:coords count:count]; @@ -28,7 +30,7 @@ NS_ASSUME_NONNULL_BEGIN { bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude)); } - _bounds = MGLCoordinateBoundsFromLatLngBounds(bounds); + _overlayBounds = MGLCoordinateBoundsFromLatLngBounds(bounds); } return self; } @@ -61,17 +63,12 @@ NS_ASSUME_NONNULL_BEGIN std::copy(_coordinates.begin() + range.location, _coordinates.begin() + NSMaxRange(range), coords); } -- (MGLCoordinateBounds)overlayBounds -{ - return _bounds; -} - - (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds { - return MGLLatLngBoundsFromCoordinateBounds(_bounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds)); + return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds); } -- (mbgl::Feature)featureObject +- (mbgl::Geometry<double>)geometryObject { mbgl::MultiPoint<double> multiPoint; multiPoint.reserve(self.pointCount); @@ -79,7 +76,7 @@ NS_ASSUME_NONNULL_BEGIN { multiPoint.push_back(mbgl::Point<double>(self.coordinates[i].longitude, self.coordinates[i].latitude)); } - return mbgl::Feature {multiPoint}; + return multiPoint; } - (NSDictionary *)geoJSONDictionary diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm index 7562db6e61..393bd31d0d 100644 --- a/platform/darwin/src/MGLPolygon.mm +++ b/platform/darwin/src/MGLPolygon.mm @@ -5,6 +5,8 @@ #import "MGLPolygon+MGLAdditions.h" +#import <mbgl/util/geojson.hpp> + @implementation MGLPolygon @dynamic overlayBounds; @@ -38,23 +40,22 @@ return result; } -- (mbgl::Feature)featureObject { +- (mbgl::Polygon<double>)polygon { mbgl::Polygon<double> geometry; geometry.push_back(self.ring); for (MGLPolygon *polygon in self.interiorPolygons) { geometry.push_back(polygon.ring); } - return mbgl::Feature{geometry}; + return geometry; } -- (mbgl::Annotation)annotationObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate { - mbgl::Polygon<double> geometry; - geometry.push_back(self.ring); - for (MGLPolygon *polygon in self.interiorPolygons) { - geometry.push_back(polygon.ring); - } +- (mbgl::Geometry<double>)geometryObject { + return [self polygon]; +} - mbgl::FillAnnotation annotation { geometry }; +- (mbgl::Annotation)annotationObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate { + + mbgl::FillAnnotation annotation { [self polygon] }; annotation.opacity = { static_cast<float>([delegate alphaForShapeAnnotation:self]) }; annotation.outlineColor = { [delegate strokeColorForShapeAnnotation:self] }; annotation.color = { [delegate fillColorForPolygonAnnotation:self] }; @@ -100,10 +101,10 @@ } - (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds { - return MGLLatLngBoundsFromCoordinateBounds(_overlayBounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds)); + return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds); } -- (mbgl::Feature)featureObject { +- (mbgl::Geometry<double>)geometryObject { mbgl::MultiPolygon<double> multiPolygon; multiPolygon.reserve(self.polygons.count); for (MGLPolygon *polygon in self.polygons) { @@ -114,7 +115,7 @@ } multiPolygon.push_back(geometry); } - return mbgl::Feature {multiPolygon}; + return multiPolygon; } - (NSDictionary *)geoJSONDictionary { diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm index 1801dfd44e..0baeb68e1a 100644 --- a/platform/darwin/src/MGLPolyline.mm +++ b/platform/darwin/src/MGLPolyline.mm @@ -5,6 +5,8 @@ #import "MGLPolyline+MGLAdditions.h" +#import <mbgl/util/geojson.hpp> + @implementation MGLPolyline @dynamic overlayBounds; @@ -37,8 +39,8 @@ return annotation; } -- (mbgl::Feature)featureObject { - return mbgl::Feature {[self lineString]}; +- (mbgl::Geometry<double>)geometryObject { + return [self lineString]; } - (NSDictionary *)geoJSONDictionary { @@ -79,16 +81,16 @@ } - (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds { - return MGLLatLngBoundsFromCoordinateBounds(_overlayBounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds)); + return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds); } -- (mbgl::Feature)featureObject { +- (mbgl::Geometry<double>)geometryObject { mbgl::MultiLineString<double> multiLineString; multiLineString.reserve(self.polylines.count); for (MGLPolyline *polyline in self.polylines) { multiLineString.push_back([polyline lineString]); } - return mbgl::Feature {multiLineString}; + return multiLineString; } - (NSDictionary *)geoJSONDictionary { diff --git a/platform/darwin/src/MGLRasterSource.h b/platform/darwin/src/MGLRasterSource.h index 78f5af8a6a..262e8f2ce1 100644 --- a/platform/darwin/src/MGLRasterSource.h +++ b/platform/darwin/src/MGLRasterSource.h @@ -1,88 +1,94 @@ -#import "MGLSource.h" -#import "MGLTypes.h" +#import "MGLTileSource.h" #import <CoreGraphics/CoreGraphics.h> -@class MGLTileSet; - NS_ASSUME_NONNULL_BEGIN /** - A raster tile source. + An `NSNumber` object containing a floating-point number that specifies the + width and height (measured in points) at which the map displays each raster + image tile when the map’s zoom level is an integer. The raster source scales + its images up or down when the map’s zoom level falls between two integers. + + The default value for this option is 512. Version 4 of the + <a href="https://www.mapbox.com/api-documentation/#maps">Mapbox Maps API</a> + requires a value of 256, as do many third-party tile servers, so consult your + provider’s documentation for the correct value. - @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-raster">The - style specification.</a> + This option is only applicable to `MGLRasterSource` objects; it is ignored when + initializing `MGLVectorSource` objects. */ -@interface MGLRasterSource : MGLSource +extern const MGLTileSourceOption MGLTileSourceOptionTileSize; + +/** + `MGLRasterSource` is a map content source that supplies raster image tiles to + be shown on the map. The location of and metadata about the tiles are defined + either by an option dictionary or by an external file that conforms to the + <a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>. + A raster source is added to an `MGLStyle` object along with one or more + `MGLRasterStyleLayer` objects. Use a raster style layer to control the + appearance of content supplied by the raster source. + + Each + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-raster"><code>raster</code></a> + source defined by the style JSON file is represented at runtime by an + `MGLRasterSource` object that you can use to initialize new style layers. You + can also add and remove sources dynamically using methods such as + `-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`. + */ +@interface MGLRasterSource : MGLTileSource #pragma mark Initializing a Source /** - Returns a raster source initialized with an identifier, TileJSON configuration - URL, and tile size. + Returns a raster source initialized with an identifier and configuration URL. After initializing and configuring the source, add it to a map view’s style using the `-[MGLStyle addSource:]` method. + The URL may be a full HTTP or HTTPS URL or, for tile sets hosted by Mapbox, a + Mapbox URL indicating a map identifier (`mapbox://<mapid>`). The URL should + point to a JSON file that conforms to the + <a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>. + + If a Mapbox URL is specified, this source uses a tile size of 256. For all + other tile sets, the default value is 512. (See the + `MGLTileSourceOptionTileSize` documentation for more information about tile + sizes.) If you need to use a tile size other than the default, use the + `-initWithIdentifier:configurationURL:tileSize:` method. + @param identifier A string that uniquely identifies the source in the style to which it is added. - @param url A URL to a TileJSON configuration file describing the source’s - contents and other metadata. - @param tileSize The height and width (measured in points) at which to display - each tile in this source when the map’s zoom level is an integer. + @param configurationURL A URL to a TileJSON configuration file describing the + source’s contents and other metadata. @return An initialized raster source. */ -- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url tileSize:(CGFloat)tileSize NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL; /** - Returns a raster source initialized with the given identifier, tile size, and - tile set. + Returns a raster source initialized with an identifier, configuration URL, and + tile size. After initializing and configuring the source, add it to a map view’s style using the `-[MGLStyle addSource:]` method. - + + The URL may be a full HTTP or HTTPS URL or, for tile sets hosted by Mapbox, a + Mapbox URL indicating a map identifier (`mapbox://<mapid>`). The URL should + point to a JSON file that conforms to the + <a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>. + @param identifier A string that uniquely identifies the source in the style to which it is added. - @param tileSet A tile set describing the source’s contents and other metadata. - @param tileSize The height and width (measured in points) at which to display - each tile in this source when the map’s zoom level is an integer. + @param configurationURL A URL to a TileJSON configuration file describing the + source’s contents and other metadata. + @param tileSize The width and height (measured in points) of each tiled image + in the raster source. See the `MGLTileSourceOptionTileSize` documentation + for details. @return An initialized raster source. */ -- (instancetype)initWithIdentifier:(NSString *)identifier tileSet:(MGLTileSet *)tileSet tileSize:(CGFloat)tileSize NS_DESIGNATED_INITIALIZER; - -#pragma mark Accessing a Source’s Content +- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize NS_DESIGNATED_INITIALIZER; -/** - A URL to a TileJSON configuration file describing the source’s contents and - other metadata. - - The URL may be a full HTTP or HTTPS URL or a Mapbox URL indicating the tile - set’s map ID (`mapbox://<mapid>`). - - @see <a href="https://www.mapbox.com/help/an-open-platform/#tilejson">The - TileJSON specification.</a> - */ -@property (nonatomic, readonly, copy) NSURL *URL; - -/** - The height and width (measured in points) at which to display each tile in this - source when the map’s zoom level is an integer. - - A tile may be scaled up or down when the zoom level is between two integers. - - The default value of this property is 512 points. - */ -@property (nonatomic, readonly, assign) NSUInteger tileSize; - -/** - The tile set used to locate and download tiles. - - A tile set holds the raster tile URL template strings and associated - configuration for those strings. It can be passed in place of the URL - to TileJSON in order to create a source configured to download tiles - from ordinary web URLs. - */ -@property (nonatomic, readonly, nullable) MGLTileSet *tileSet; +- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options NS_DESIGNATED_INITIALIZER; @end diff --git a/platform/darwin/src/MGLRasterSource.mm b/platform/darwin/src/MGLRasterSource.mm index 62472050e3..edca8bced1 100644 --- a/platform/darwin/src/MGLRasterSource.mm +++ b/platform/darwin/src/MGLRasterSource.mm @@ -1,90 +1,103 @@ -#import "MGLRasterSource.h" +#import "MGLRasterSource_Private.h" #import "MGLMapView_Private.h" #import "MGLSource_Private.h" -#import "MGLTileSet_Private.h" +#import "MGLTileSource_Private.h" #import "NSURL+MGLAdditions.h" #include <mbgl/style/sources/raster_source.hpp> +const MGLTileSourceOption MGLTileSourceOptionTileSize = @"MGLTileSourceOptionTileSize"; + +static const CGFloat MGLRasterSourceClassicTileSize = 256; +static const CGFloat MGLRasterSourceRetinaTileSize = 512; + @interface MGLRasterSource () +- (instancetype)initWithRawSource:(mbgl::style::RasterSource *)rawSource NS_DESIGNATED_INITIALIZER; + @property (nonatomic) mbgl::style::RasterSource *rawSource; @end -@implementation MGLRasterSource -{ +@implementation MGLRasterSource { std::unique_ptr<mbgl::style::RasterSource> _pendingSource; } -- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url tileSize:(CGFloat)tileSize -{ - if (self = [super initWithIdentifier:identifier]) { - _URL = url; - _tileSize = tileSize; - [self commonInit]; +- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL { + // The style specification default is 512, but 256 is the expected value for + // any tile set that would be accessed through a mapbox: URL and therefore + // any tile URL that this option currently affects. + BOOL isMapboxURL = ([configurationURL.scheme isEqualToString:@"mapbox"] + && [configurationURL.host containsString:@"."] + && (!configurationURL.path.length || [configurationURL.path isEqualToString:@"/"])); + CGFloat tileSize = isMapboxURL ? MGLRasterSourceClassicTileSize : MGLRasterSourceRetinaTileSize; + return [self initWithIdentifier:identifier configurationURL:configurationURL tileSize:tileSize]; +} + +- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize { + if (self = [super initWithIdentifier:identifier configurationURL:configurationURL]) { + auto source = std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String, + configurationURL.mgl_URLByStandardizingScheme.absoluteString.UTF8String, + uint16_t(round(tileSize))); + _pendingSource = std::move(source); + self.rawSource = _pendingSource.get(); } return self; } -- (instancetype)initWithIdentifier:(NSString *)identifier tileSet:(MGLTileSet *)tileSet tileSize:(CGFloat)tileSize; -{ - if (self = [super initWithIdentifier:identifier]) - { - _tileSet = tileSet; - _tileSize = tileSize; - [self commonInit]; +- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options { + if (self = [super initWithIdentifier:identifier tileURLTemplates:tileURLTemplates options:options]) { + mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options); + + uint16_t tileSize; + if (NSNumber *tileSizeNumber = options[MGLTileSourceOptionTileSize]) { + if (![tileSizeNumber isKindOfClass:[NSNumber class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLTileSourceOptionTileSize must be set to an NSNumber."]; + } + tileSize = static_cast<uint16_t>(round(tileSizeNumber.doubleValue)); + } + + auto source = std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String, tileSet, tileSize); + _pendingSource = std::move(source); + self.rawSource = _pendingSource.get(); } return self; } -- (void)commonInit -{ - std::unique_ptr<mbgl::style::RasterSource> source; - - if (self.URL) - { - source = std::make_unique<mbgl::style::RasterSource>(self.identifier.UTF8String, - self.URL.mgl_URLByStandardizingScheme.absoluteString.UTF8String, - uint16_t(self.tileSize)); - } - else - { - source = std::make_unique<mbgl::style::RasterSource>(self.identifier.UTF8String, - self.tileSet.mbglTileset, - uint16_t(self.tileSize)); - } - - _pendingSource = std::move(source); - self.rawSource = _pendingSource.get(); +- (instancetype)initWithRawSource:(mbgl::style::RasterSource *)rawSource { + return [super initWithRawSource:rawSource]; } -- (void)addToMapView:(MGLMapView *)mapView -{ +- (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]; + @"to the style more than once is invalid.", self, mapView.style]; } mapView.mbglMap->addSource(std::move(_pendingSource)); } -- (void)removeFromMapView:(MGLMapView *)mapView -{ +- (void)removeFromMapView:(MGLMapView *)mapView { auto removedSource = mapView.mbglMap->removeSource(self.identifier.UTF8String); _pendingSource = std::move(reinterpret_cast<std::unique_ptr<mbgl::style::RasterSource> &>(removedSource)); self.rawSource = _pendingSource.get(); } -- (NSString *)description -{ - return [NSString stringWithFormat: - @"<%@: %p; identifier = %@; URL = %@; tileSet = %@; tileSize = %lu>", - NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, - self.tileSet, (unsigned long)self.tileSize]; +- (mbgl::style::RasterSource *)rawSource { + return (mbgl::style::RasterSource *)super.rawSource; +} + +- (void)setRawSource:(mbgl::style::RasterSource *)rawSource { + super.rawSource = rawSource; +} + +- (NSString *)attributionHTMLString { + auto attribution = self.rawSource->getAttribution(); + return attribution ? @(attribution->c_str()) : nil; } @end diff --git a/platform/darwin/src/MGLRasterSource_Private.h b/platform/darwin/src/MGLRasterSource_Private.h new file mode 100644 index 0000000000..47b1c13517 --- /dev/null +++ b/platform/darwin/src/MGLRasterSource_Private.h @@ -0,0 +1,17 @@ +#import "MGLRasterSource.h" + +NS_ASSUME_NONNULL_BEGIN + +namespace mbgl { + namespace style { + class RasterSource; + } +} + +@interface MGLRasterSource (Private) + +- (instancetype)initWithRawSource:(mbgl::style::RasterSource *)rawSource; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLRasterStyleLayer.h b/platform/darwin/src/MGLRasterStyleLayer.h index 68b187a908..def5221d62 100644 --- a/platform/darwin/src/MGLRasterStyleLayer.h +++ b/platform/darwin/src/MGLRasterStyleLayer.h @@ -20,16 +20,26 @@ NS_ASSUME_NONNULL_BEGIN Increase or reduce the brightness of the image. The value is the maximum brightness. The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-max"><code>raster-brightness-max</code></a> paint property in the Mapbox Style Specification. */ @property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumRasterBrightness; + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterBrightnessMax __attribute__((unavailable("Use maximumRasterBrightness instead."))); + /** Increase or reduce the brightness of the image. The value is the minimum brightness. The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-min"><code>raster-brightness-min</code></a> paint property in the Mapbox Style Specification. */ @property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *minimumRasterBrightness; + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterBrightnessMin __attribute__((unavailable("Use minimumRasterBrightness instead."))); + /** Increase or reduce the contrast of the image. @@ -52,8 +62,13 @@ NS_ASSUME_NONNULL_BEGIN This property is measured in degrees. The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-hue-rotate"><code>raster-hue-rotate</code></a> paint property in the Mapbox Style Specification. */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterHueRotate; +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterHueRotation; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterHueRotate __attribute__((unavailable("Use rasterHueRotation instead."))); /** The opacity at which the image will be drawn. diff --git a/platform/darwin/src/MGLRasterStyleLayer.mm b/platform/darwin/src/MGLRasterStyleLayer.mm index 3b2c3bd83b..e61532773c 100644 --- a/platform/darwin/src/MGLRasterStyleLayer.mm +++ b/platform/darwin/src/MGLRasterStyleLayer.mm @@ -26,13 +26,24 @@ if (self = [super initWithIdentifier:identifier source:source]) { auto layer = std::make_unique<mbgl::style::RasterLayer>(identifier.UTF8String, source.identifier.UTF8String); _pendingLayer = std::move(layer); - _rawLayer = _pendingLayer.get(); + self.rawLayer = _pendingLayer.get(); } return self; } -#pragma mark - Adding to and removing from a map view -- (void)addToMapView:(MGLMapView *)mapView +- (mbgl::style::RasterLayer *)rawLayer +{ + return (mbgl::style::RasterLayer *)super.rawLayer; +} + +- (void)setRawLayer:(mbgl::style::RasterLayer *)rawLayer +{ + super.rawLayer = rawLayer; +} + +#pragma mark - Adding to and removing from a map view + +- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer { if (_pendingLayer == nullptr) { [NSException raise:@"MGLRedundantLayerException" @@ -40,11 +51,6 @@ "to the style more than once is invalid.", self, mapView.style]; } - [self addToMapView:mapView belowLayer:nil]; -} - -- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer -{ if (otherLayer) { const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String}; mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId); @@ -56,7 +62,7 @@ - (void)removeFromMapView:(MGLMapView *)mapView { _pendingLayer = nullptr; - _rawLayer = nullptr; + self.rawLayer = nullptr; auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String); if (!removedLayer) { @@ -71,7 +77,7 @@ removedLayer.release(); _pendingLayer = std::unique_ptr<mbgl::style::RasterLayer>(layer); - _rawLayer = _pendingLayer.get(); + self.rawLayer = _pendingLayer.get(); } #pragma mark - Accessing the Paint Attributes @@ -80,41 +86,51 @@ MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(maximumRasterBrightness); - _rawLayer->setRasterBrightnessMax(mbglValue); + self.rawLayer->setRasterBrightnessMax(mbglValue); } - (MGLStyleValue<NSNumber *> *)maximumRasterBrightness { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getRasterBrightnessMax() ?: _rawLayer->getDefaultRasterBrightnessMax(); + auto propertyValue = self.rawLayer->getRasterBrightnessMax() ?: self.rawLayer->getDefaultRasterBrightnessMax(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } + +- (void)setRasterBrightnessMax:(MGLStyleValue<NSNumber *> *)rasterBrightnessMax { + NSAssert(NO, @"Use -setMaximumRasterBrightness: instead."); +} + - (void)setMinimumRasterBrightness:(MGLStyleValue<NSNumber *> *)minimumRasterBrightness { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(minimumRasterBrightness); - _rawLayer->setRasterBrightnessMin(mbglValue); + self.rawLayer->setRasterBrightnessMin(mbglValue); } - (MGLStyleValue<NSNumber *> *)minimumRasterBrightness { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getRasterBrightnessMin() ?: _rawLayer->getDefaultRasterBrightnessMin(); + auto propertyValue = self.rawLayer->getRasterBrightnessMin() ?: self.rawLayer->getDefaultRasterBrightnessMin(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } + +- (void)setRasterBrightnessMin:(MGLStyleValue<NSNumber *> *)rasterBrightnessMin { + NSAssert(NO, @"Use -setMinimumRasterBrightness: instead."); +} + - (void)setRasterContrast:(MGLStyleValue<NSNumber *> *)rasterContrast { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterContrast); - _rawLayer->setRasterContrast(mbglValue); + self.rawLayer->setRasterContrast(mbglValue); } - (MGLStyleValue<NSNumber *> *)rasterContrast { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getRasterContrast() ?: _rawLayer->getDefaultRasterContrast(); + auto propertyValue = self.rawLayer->getRasterContrast() ?: self.rawLayer->getDefaultRasterContrast(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -122,41 +138,46 @@ MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterFadeDuration); - _rawLayer->setRasterFadeDuration(mbglValue); + self.rawLayer->setRasterFadeDuration(mbglValue); } - (MGLStyleValue<NSNumber *> *)rasterFadeDuration { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getRasterFadeDuration() ?: _rawLayer->getDefaultRasterFadeDuration(); + auto propertyValue = self.rawLayer->getRasterFadeDuration() ?: self.rawLayer->getDefaultRasterFadeDuration(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } -- (void)setRasterHueRotate:(MGLStyleValue<NSNumber *> *)rasterHueRotate { +- (void)setRasterHueRotation:(MGLStyleValue<NSNumber *> *)rasterHueRotation { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterHueRotate); - _rawLayer->setRasterHueRotate(mbglValue); + auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterHueRotation); + self.rawLayer->setRasterHueRotate(mbglValue); } -- (MGLStyleValue<NSNumber *> *)rasterHueRotate { +- (MGLStyleValue<NSNumber *> *)rasterHueRotation { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getRasterHueRotate() ?: _rawLayer->getDefaultRasterHueRotate(); + auto propertyValue = self.rawLayer->getRasterHueRotate() ?: self.rawLayer->getDefaultRasterHueRotate(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } + +- (void)setRasterHueRotate:(MGLStyleValue<NSNumber *> *)rasterHueRotate { + NSAssert(NO, @"Use -setRasterHueRotation: instead."); +} + - (void)setRasterOpacity:(MGLStyleValue<NSNumber *> *)rasterOpacity { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterOpacity); - _rawLayer->setRasterOpacity(mbglValue); + self.rawLayer->setRasterOpacity(mbglValue); } - (MGLStyleValue<NSNumber *> *)rasterOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getRasterOpacity() ?: _rawLayer->getDefaultRasterOpacity(); + auto propertyValue = self.rawLayer->getRasterOpacity() ?: self.rawLayer->getDefaultRasterOpacity(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -164,13 +185,13 @@ MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterSaturation); - _rawLayer->setRasterSaturation(mbglValue); + self.rawLayer->setRasterSaturation(mbglValue); } - (MGLStyleValue<NSNumber *> *)rasterSaturation { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getRasterSaturation() ?: _rawLayer->getDefaultRasterSaturation(); + auto propertyValue = self.rawLayer->getRasterSaturation() ?: self.rawLayer->getDefaultRasterSaturation(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } diff --git a/platform/darwin/src/MGLRuntimeStylingTests.m.ejs b/platform/darwin/src/MGLRuntimeStylingTests.m.ejs deleted file mode 100644 index 720ee4547e..0000000000 --- a/platform/darwin/src/MGLRuntimeStylingTests.m.ejs +++ /dev/null @@ -1,59 +0,0 @@ -<% - const type = locals.type; - const layoutProperties = locals.layoutProperties; - const paintProperties = locals.paintProperties; --%> -// This file is generated. -// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`. - -#import "MGLStyleLayerTests.h" - -@interface MGL<%- camelize(type) %>LayerTests : MGLStyleLayerTests -@end - -@implementation MGL<%- camelize(type) %>LayerTests - -- (void)test<%- camelize(type) %>Layer { -<% if (type === 'background') { -%> - MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID"]; -<% } else { -%> - NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"]; - NSURL *url = [NSURL fileURLWithPath:filePath]; - MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil]; - [self.mapView.style addSource:source]; - MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID" source:source]; -<% } -%> - [self.mapView.style addLayer:layer]; - -<% for (const property of layoutProperties) { -%> - <%- testImplementation(property, type) %> -<% } -%> -<% for (const property of paintProperties) { -%> - <%- testImplementation(property, type) %> -<% } -%> - - MGL<%- camelize(type) %>StyleLayer *gLayer = (MGL<%- camelize(type) %>StyleLayer *)[self.mapView.style layerWithIdentifier:@"layerID"]; - XCTAssertTrue([gLayer isKindOfClass:[MGL<%- camelize(type) %>StyleLayer class]]); -<% for (const property of layoutProperties) { -%> - <%- testGetterImplementation(property, type) %> -<% } -%> -<% for (const property of paintProperties) { -%> - <%- testGetterImplementation(property, type) %> -<% } -%> - -<% for (const property of layoutProperties) { -%> - <%- testImplementation(property, type, true) %> -<% } -%> -<% for (const property of paintProperties) { -%> - <%- testImplementation(property, type, true) %> -<% } -%> - -<% for (const property of layoutProperties) { -%> - <%- testGetterImplementation(property, type, true) %> -<% } -%> -<% for (const property of paintProperties) { -%> - <%- testGetterImplementation(property, type, true) %> -<% } -%> -} - -@end diff --git a/platform/darwin/src/MGLShape.h b/platform/darwin/src/MGLShape.h index ce9375c910..af815da0e9 100644 --- a/platform/darwin/src/MGLShape.h +++ b/platform/darwin/src/MGLShape.h @@ -13,6 +13,30 @@ NS_ASSUME_NONNULL_BEGIN */ @interface MGLShape : NSObject <MGLAnnotation> +#pragma mark Creating a Shape + +/** + Returns an `MGLShape` object initialized with the given data interpreted as a + string containing a GeoJSON object. + + If the GeoJSON object is a geometry, the returned value is a kind of + `MGLShape`. If it is a feature object, the returned value is a kind of + `MGLShape` that conforms to the `MGLFeature` protocol. If it is a feature + collection object, the returned value is an instance of + `MGLShapeCollectionFeature`. + + @param data String data containing GeoJSON source code. + @param encoding The encoding used by `data`. + @param outError Upon return, if an error has occurred, a pointer to an + `NSError` object describing the error. Pass in `NULL` to ignore any error. + @return An `MGLShape` object representation of `data`, or `nil` if `data` could + not be parsed as valid GeoJSON source code. If `nil`, `outError` contains an + `NSError` object describing the problem. + */ ++ (nullable MGLShape *)shapeWithData:(NSData *)data encoding:(NSStringEncoding)encoding error:(NSError * _Nullable *)outError; + +#pragma mark Accessing the Shape Attributes + /** The title of the shape annotation. The default value of this property is `nil`. */ @@ -34,6 +58,17 @@ NS_ASSUME_NONNULL_BEGIN #endif +#pragma mark Creating GeoJSON Data + +/** + Returns the GeoJSON string representation of the shape encapsulated in a data + object. + + @param encoding The string encoding to use. + @return A data object containing the shape’s GeoJSON string representation. + */ +- (NSData *)geoJSONDataUsingEncoding:(NSStringEncoding)encoding; + @end NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLShape.mm b/platform/darwin/src/MGLShape.mm index e3d92c38c8..889ef8b3d7 100644 --- a/platform/darwin/src/MGLShape.mm +++ b/platform/darwin/src/MGLShape.mm @@ -1,14 +1,52 @@ -#import "MGLShape.h" +#import "MGLShape_Private.h" + +#import "MGLFeature_Private.h" @implementation MGLShape -- (CLLocationCoordinate2D)coordinate -{ - [[NSException exceptionWithName:@"MGLAbstractClassException" - reason:@"MGLShape is an abstract class" - userInfo:nil] raise]; ++ (nullable MGLShape *)shapeWithData:(NSData *)data encoding:(NSStringEncoding)encoding error:(NSError * _Nullable *)outError { + NSString *string = [[NSString alloc] initWithData:data encoding:encoding]; + if (!string) { + if (outError) { + *outError = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeUnknown userInfo:nil]; + } + return nil; + } + + try { + const auto geojson = mapbox::geojson::parse(string.UTF8String); + return MGLShapeFromGeoJSON(geojson); + } catch (std::runtime_error &err) { + if (outError) { + *outError = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeUnknown userInfo:@{ + NSLocalizedFailureReasonErrorKey: @(err.what()), + }]; + } + return nil; + } +} + +- (mbgl::GeoJSON)geoJSONObject { + return self.geometryObject; +} + +- (mbgl::Geometry<double>)geometryObject { + [NSException raise:@"MGLAbstractClassException" + format:@"MGLShape is an abstract class"]; + return mbgl::Point<double>(); +} + +- (NSData *)geoJSONDataUsingEncoding:(NSStringEncoding)encoding { + auto geometry = self.geoJSONObject; + NSString *string = @(mapbox::geojson::stringify(geometry).c_str()); + return [string dataUsingEncoding:NSUTF8StringEncoding]; +} + +- (CLLocationCoordinate2D)coordinate { + [NSException raise:@"MGLAbstractClassException" + format:@"MGLShape is an abstract class"]; - return CLLocationCoordinate2DMake(MAXFLOAT, MAXFLOAT); + return kCLLocationCoordinate2DInvalid; } @end diff --git a/platform/darwin/src/MGLShapeCollection.m b/platform/darwin/src/MGLShapeCollection.mm index 0f011bfd20..e317a443fe 100644 --- a/platform/darwin/src/MGLShapeCollection.m +++ b/platform/darwin/src/MGLShapeCollection.mm @@ -1,5 +1,9 @@ #import "MGLShapeCollection.h" +#import "MGLShape_Private.h" + +#import <mbgl/style/conversion/geojson.hpp> + @implementation MGLShapeCollection + (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes { @@ -32,4 +36,13 @@ return [geometries copy]; } +- (mbgl::Geometry<double>)geometryObject { + mapbox::geojson::geometry_collection collection; + collection.reserve(self.shapes.count); + for (MGLShape *shape in self.shapes) { + collection.push_back([shape geometryObject]); + } + return collection; +} + @end diff --git a/platform/darwin/src/MGLShapeSource.h b/platform/darwin/src/MGLShapeSource.h new file mode 100644 index 0000000000..68cb40a83f --- /dev/null +++ b/platform/darwin/src/MGLShapeSource.h @@ -0,0 +1,135 @@ +#import "MGLSource.h" + +#import "MGLTypes.h" +#import "MGLShape.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol MGLFeature; + +/** + Options for `MGLShapeSource` objects. + */ +typedef NSString *MGLShapeSourceOption NS_STRING_ENUM; + +/** + An `NSNumber` object containing a Boolean enabling or disabling clustering. + If the `shape` property contains point shapes, setting this option to + `YES` clusters the points by radius into groups. The default value is `NO`. + */ +extern const MGLShapeSourceOption MGLShapeSourceOptionClustered; + +/** + An `NSNumber` object containing an integer; specifies the radius of each + cluster if clustering is enabled. A value of 512 produces a radius equal to + the width of a tile. The default value is 50. + */ +extern const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius; + +/** + An `NSNumber` object containing an integer; specifies the maximum zoom level at + which to cluster points if clustering is enabled. Defaults to one zoom level + less than the value of `MGLShapeSourceOptionMaximumZoomLevel` so that, at the + maximum zoom level, the shapes are not clustered. + */ +extern const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering; + +/** + An `NSNumber` object containing an integer; specifies the maximum zoom level at + which to create vector tiles. A greater value produces greater detail at high + zoom levels. The default value is 18. + */ +extern const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel; + +/** + An `NSNumber` object containing an integer; specifies the size of the tile + buffer on each side. A value of 0 produces no buffer. A value of 512 produces a + buffer as wide as the tile itself. Larger values produce fewer rendering + artifacts near tile edges and slower performance. The default value is 128. + */ +extern const MGLShapeSourceOption MGLShapeSourceOptionBuffer; + +/** + An `NSNumber` object containing a double; specifies the Douglas-Peucker + simplification tolerance. A greater value produces simpler geometries and + improves performance. The default value is 0.375. + */ +extern const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance; + +/** + `MGLShapeSource` is a map content source that supplies vector shapes to be + shown on the map. The shapes may be instances of `MGLShape` or `MGLFeature`, + or they may be defined by local or external + <a href="http://geojson.org/">GeoJSON</a> code. A shape source is added to an + `MGLStyle` object along with an `MGLVectorStyleLayer` object. The vector style + layer defines the appearance of any content supplied by the shape source. + + Each + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson"><code>geojson</code></a> + source defined by the style JSON file is represented at runtime by an + `MGLShapeSource` object that you can use to refine the map’s content and + initialize new style layers. You can also add and remove sources dynamically + using methods such as `-[MGLStyle addSource:]` and + `-[MGLStyle sourceWithIdentifier:]`. + + Any vector style layer initialized with a shape source should have a `nil` + value in its `sourceLayerIdentifier` property. + */ +@interface MGLShapeSource : MGLSource + +#pragma mark Initializing a Source + +/** + Returns a shape source with an identifier, URL, and dictionary of options for + the source. + + @param identifier A string that uniquely identifies the source. + @param URL An HTTP(S) URL, absolute file URL, or local file URL relative to the + current application’s resource bundle. + @param options An `NSDictionary` of options for this source. + @return An initialized shape source. + */ +- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER; + +/** + Returns a shape source with an identifier, a shape, and dictionary of options + for the source. + + To specify attributes about the shape, use an instance of an `MGLShape` + subclass that conforms to the `MGLFeature` protocol, such as `MGLPointFeature`. + To include multiple shapes in the source, use an `MGLShapeCollection` or + `MGLShapeCollectionFeature` object. + + To create a shape from GeoJSON source code, use the + `+[MGLShape shapeWithData:encoding:error:]` method. + + @param identifier A string that uniquely identifies the source. + @param shape A concrete subclass of `MGLShape` + @param options An `NSDictionary` of options for this source. + @return An initialized shape source. + */ +- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER; + +#pragma mark Accessing a Source’s Content + +/** + The contents of the source. A shape can represent a GeoJSON geometry, a + feature, or a collection of features. + + If the receiver was initialized using `-initWithIdentifier:URL:options:`, this + property is set to `nil`. This property is unavailable until the receiver is + passed into `-[MGLStyle addSource:]`. + */ +@property (nonatomic, copy, nullable) MGLShape *shape; + +/** + The URL to the GeoJSON document that specifies the contents of the source. + + If the receiver was initialized using `-initWithIdentifier:shape:options:`, + this property is set to `nil`. + */ +@property (nonatomic, copy, nullable) NSURL *URL; + +@end + +NS_ASSUME_NONNULL_END 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; +} diff --git a/platform/darwin/src/MGLShapeSource_Private.h b/platform/darwin/src/MGLShapeSource_Private.h new file mode 100644 index 0000000000..584a5a4b30 --- /dev/null +++ b/platform/darwin/src/MGLShapeSource_Private.h @@ -0,0 +1,21 @@ +#import "MGLShapeSource.h" +#import "MGLShapeSource_Private.h" + +NS_ASSUME_NONNULL_BEGIN + +namespace mbgl { + namespace style { + class GeoJSONOptions; + struct GeoJSONSource; + } +} + +@interface MGLShapeSource (Private) + +- (instancetype)initWithRawSource:(mbgl::style::GeoJSONSource *)rawSource; + +@end + +mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options); + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLShape_Private.h b/platform/darwin/src/MGLShape_Private.h index a8ee12c207..15d1c1eb97 100644 --- a/platform/darwin/src/MGLShape_Private.h +++ b/platform/darwin/src/MGLShape_Private.h @@ -1,13 +1,19 @@ #import "MGLShape.h" -#import <mbgl/util/feature.hpp> +#import <mbgl/util/geojson.hpp> +#import <mbgl/util/geometry.hpp> @interface MGLShape (Private) /** - Returns an `mbgl::Feature` representation of the `MGLShape`. + Returns an `mbgl::GeoJSON` representation of the `MGLShape`. */ -- (mbgl::Feature)featureObject; +- (mbgl::GeoJSON)geoJSONObject; + +/** + Returns an `mbgl::Geometry<double>` representation of the `MGLShape`. + */ +- (mbgl::Geometry<double>)geometryObject; /** Returns a dictionary with the GeoJSON geometry member object. diff --git a/platform/darwin/src/MGLSource.h b/platform/darwin/src/MGLSource.h index ec3733bf08..6b381fca19 100644 --- a/platform/darwin/src/MGLSource.h +++ b/platform/darwin/src/MGLSource.h @@ -1,17 +1,29 @@ #import <Foundation/Foundation.h> +NS_ASSUME_NONNULL_BEGIN + /** - A source supplies data to be shown on the map. Sources don't contain styling - details like color or width. Use subclasses of `MGLStyleLayer` to give visual - representation to sources. + `MGLSource` is an abstract base class for map content sources. A map content + source supplies content to be shown on the map. A source is added to an + `MGLStyle` object along with an `MGLForegroundStyleLayer` object. The + foreground style layer defines the appearance of any content supplied by the + source. + + Each source defined by the style JSON file is represented at runtime by an + `MGLSource` object that you can use to refine the map’s content. You can also + add and remove sources dynamically using methods such as + `-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`. - You should use the concrete subclasses of `MGLSource` to create vector, - raster, GeoJSON, and other source types. + Do not create instances of this class directly, and do not create your own + subclasses of this class. Instead, create instances of `MGLShapeSource` and the + concrete subclasses of `MGLTileSource`. */ @interface MGLSource : NSObject #pragma mark Initializing a Source +- (instancetype)init __attribute__((unavailable("Use -initWithIdentifier: instead."))); + /** Returns a source initialized with an identifier. @@ -32,3 +44,5 @@ @property (nonatomic, copy) NSString *identifier; @end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLSource.mm b/platform/darwin/src/MGLSource.mm index 2fa580df89..c96b6c41c6 100644 --- a/platform/darwin/src/MGLSource.mm +++ b/platform/darwin/src/MGLSource.mm @@ -20,6 +20,14 @@ return self; } +- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource { + NSString *identifier = @(rawSource->getID().c_str()); + if (self = [self initWithIdentifier:identifier]) { + _rawSource = rawSource; + } + return self; +} + - (void)addToMapView:(MGLMapView *)mapView { [NSException raise:NSInvalidArgumentException format: @"The source %@ cannot be added to the style. " diff --git a/platform/darwin/src/MGLSource_Private.h b/platform/darwin/src/MGLSource_Private.h index 5f63f1fb1d..6e1d2e379c 100644 --- a/platform/darwin/src/MGLSource_Private.h +++ b/platform/darwin/src/MGLSource_Private.h @@ -1,12 +1,23 @@ #import "MGLSource.h" -#include <mbgl/style/source.hpp> +NS_ASSUME_NONNULL_BEGIN + +namespace mbgl { + namespace style { + class Source; + } +} @class MGLMapView; @interface MGLSource (Private) /** + Initializes and returns a source with a raw pointer to the backing store. + */ +- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource; + +/** A raw pointer to the mbgl object, which is always initialized, either to the value returned by `mbgl::Map getSource`, or for independently created objects, to the pointer value held in `pendingSource`. In the latter case, this raw @@ -37,3 +48,5 @@ - (void)removeFromMapView:(MGLMapView *)mapView; @end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLStyle.h b/platform/darwin/src/MGLStyle.h index 54ca267bab..96dd502c30 100644 --- a/platform/darwin/src/MGLStyle.h +++ b/platform/darwin/src/MGLStyle.h @@ -30,14 +30,24 @@ NS_ASSUME_NONNULL_BEGIN static const NSInteger MGLStyleDefaultVersion = 9; /** - The proxy object for the current map style for customization purposes and a - set of convenience methods for creating style URLs of default styles provided - by Mapbox. + The proxy object for the current map style. + + MGLStyle provides a set of convenience methods for changing Mapbox + default styles using `-[MGLMapView styleURL]`. <a href="https://www.mapbox.com/maps/">Learn more about Mapbox default styles</a>. + + It is also possible to directly manipulate the current map style + via `-[MGLMapView style]` by updating the style's data sources or layers. + + @note Wait until the map style has finished loading before modifying a map's + style via any of the MGLStyle instance methods below. + You can use the `MGLMapViewDelegate` methods `-mapViewDidFinishLoadingMap:` + or `-mapView:didFinishLoadingStyle:` as indicators that it's safe + to modify the map's style. */ @interface MGLStyle : NSObject -#pragma mark Accessing Common Styles +#pragma mark Accessing Default Styles /** Returns the URL to version 8 of the @@ -199,11 +209,11 @@ static const NSInteger MGLStyleDefaultVersion = 9; /** Adds a new source to the current style. - - @note Adding the same source instance more than once will result in a + + @note Adding the same source instance more than once will result in a `MGLRedundantSourceException`. Reusing the same source identifier, even with different source instances, will result in a - `MGLRedundantSourceIdentiferException`. + `MGLRedundantSourceIdentifierException`. @param source The source to add to the current style. */ @@ -251,7 +261,7 @@ static const NSInteger MGLStyleDefaultVersion = 9; /** Adds a new layer on top of existing layers. - + @note Adding the same layer instance more than once will result in a `MGLRedundantLayerException`. Reusing the same layer identifer, even with different layer instances, will also result in an exception. @@ -372,10 +382,28 @@ static const NSInteger MGLStyleDefaultVersion = 9; #pragma mark Managing a Style’s Images /** + Returns the image associated with the given name in the style. + + @note Names and their associated images are not guaranteed to exist across + styles or different versions of the same style. Applications that use this + API must first set the style URL to an explicitly versioned style using a + convenience method like `+[MGLStyle outdoorsStyleURLWithVersion:]`, + `MGLMapView`'s “Style URL” inspectable in Interface Builder, or a manually + constructed `NSURL`. This approach also avoids image name changes that will + occur in the default style over time. + + @param name The name associated with the image you want to obtain. + @return The image associated with the given name, or `nil` if no image is + associated with that name. + */ +- (nullable MGLImage *)imageForName:(NSString *)name; + +/** Adds or overrides an image used by the style’s layers. To use an image in a style layer, give it a unique name using this method, then - set the `iconImage` property of an `MGLSymbolStyleLayer` object to that name. + set the `iconImageName` property of an `MGLSymbolStyleLayer` object to that + name. @param image The image for the name. @param name The name of the image to set to the style. diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm index 7d7ca73a58..9ea9e760f5 100644 --- a/platform/darwin/src/MGLStyle.mm +++ b/platform/darwin/src/MGLStyle.mm @@ -1,4 +1,4 @@ -#import "MGLStyle.h" +#import "MGLStyle_Private.h" #import "MGLMapView_Private.h" #import "MGLStyleLayer.h" @@ -8,6 +8,7 @@ #import "MGLSymbolStyleLayer.h" #import "MGLRasterStyleLayer.h" #import "MGLBackgroundStyleLayer.h" +#import "MGLOpenGLStyleLayer.h" #import "MGLStyle_Private.h" #import "MGLStyleLayer_Private.h" @@ -16,9 +17,12 @@ #import "NSDate+MGLAdditions.h" #import "MGLSource.h" +#import "MGLTileSource_Private.h" #import "MGLVectorSource.h" #import "MGLRasterSource.h" -#import "MGLGeoJSONSource.h" +#import "MGLShapeSource.h" + +#import "MGLAttributionInfo_Private.h" #include <mbgl/util/default_styles.hpp> #include <mbgl/sprite/sprite_image.hpp> @@ -28,6 +32,7 @@ #include <mbgl/style/layers/raster_layer.hpp> #include <mbgl/style/layers/circle_layer.hpp> #include <mbgl/style/layers/background_layer.hpp> +#include <mbgl/style/layers/custom_layer.hpp> #include <mbgl/style/sources/geojson_source.hpp> #include <mbgl/style/sources/vector_source.hpp> #include <mbgl/style/sources/raster_source.hpp> @@ -42,6 +47,7 @@ @property (nonatomic, readwrite, weak) MGLMapView *mapView; @property (readonly, copy, nullable) NSURL *URL; +@property (nonatomic, readwrite, strong) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLOpenGLStyleLayer *) *openGLLayers; @end @@ -108,6 +114,7 @@ static NSURL *MGLStyleURL_emerald; - (instancetype)initWithMapView:(MGLMapView *)mapView { if (self = [super init]) { _mapView = mapView; + _openGLLayers = [NSMutableDictionary dictionary]; } return self; } @@ -157,25 +164,18 @@ static NSURL *MGLStyleURL_emerald; return rawSource ? [self sourceFromMBGLSource:rawSource] : nil; } -- (MGLSource *)sourceFromMBGLSource:(mbgl::style::Source *)mbglSource { - NSString *identifier = @(mbglSource->getID().c_str()); - +- (MGLSource *)sourceFromMBGLSource:(mbgl::style::Source *)source { // TODO: Fill in options specific to the respective source classes // https://github.com/mapbox/mapbox-gl-native/issues/6584 - MGLSource *source; - if (mbglSource->is<mbgl::style::VectorSource>()) { - source = [[MGLVectorSource alloc] initWithIdentifier:identifier]; - } else if (mbglSource->is<mbgl::style::GeoJSONSource>()) { - source = [[MGLGeoJSONSource alloc] initWithIdentifier:identifier]; - } else if (mbglSource->is<mbgl::style::RasterSource>()) { - source = [[MGLRasterSource alloc] initWithIdentifier:identifier]; + if (auto vectorSource = source->as<mbgl::style::VectorSource>()) { + return [[MGLVectorSource alloc] initWithRawSource:vectorSource]; + } else if (auto geoJSONSource = source->as<mbgl::style::GeoJSONSource>()) { + return [[MGLShapeSource alloc] initWithRawSource:geoJSONSource]; + } else if (auto rasterSource = source->as<mbgl::style::RasterSource>()) { + return [[MGLRasterSource alloc] initWithRawSource:rasterSource]; } else { - source = [[MGLSource alloc] initWithIdentifier:identifier]; + return [[MGLSource alloc] initWithRawSource:source]; } - - source.rawSource = mbglSource; - - return source; } - (void)addSource:(MGLSource *)source @@ -190,7 +190,7 @@ static NSURL *MGLStyleURL_emerald; try { [source addToMapView:self.mapView]; } catch (std::runtime_error & err) { - [NSException raise:@"MGLRedundantSourceIdentiferException" format:@"%s", err.what()]; + [NSException raise:@"MGLRedundantSourceIdentifierException" format:@"%s", err.what()]; } } @@ -205,6 +205,24 @@ static NSURL *MGLStyleURL_emerald; [source removeFromMapView:self.mapView]; } +- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor { + // It’d be incredibly convenient to use -sources here, but this operation + // depends on the sources being sorted in ascending order by creation, as + // with the std::vector used in mbgl. + auto rawSources = self.mapView.mbglMap->getSources(); + NSMutableArray *infos = [NSMutableArray arrayWithCapacity:rawSources.size()]; + for (auto rawSource = rawSources.begin(); rawSource != rawSources.end(); ++rawSource) { + MGLTileSource *source = (MGLTileSource *)[self sourceFromMBGLSource:*rawSource]; + if (![source isKindOfClass:[MGLTileSource class]]) { + continue; + } + + NSArray *tileSetInfos = [source attributionInfosWithFontSize:fontSize linkColor:linkColor]; + [infos growArrayByAddingAttributionInfosFromArray:tileSetInfos]; + } + return infos; +} + #pragma mark Style layers - (NS_MUTABLE_ARRAY_OF(MGLStyleLayer *) *)layers @@ -272,7 +290,7 @@ static NSURL *MGLStyleURL_emerald; format:@"Cannot insert style layer at out-of-bounds index %lu.", (unsigned long)index]; } else if (index == 0) { try { - [styleLayer addToMapView:self.mapView]; + [styleLayer addToMapView:self.mapView belowLayer:nil]; } catch (const std::runtime_error & err) { [NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()]; } @@ -294,7 +312,8 @@ static NSURL *MGLStyleURL_emerald; format:@"Cannot remove style layer at out-of-bounds index %lu.", (unsigned long)index]; } auto layer = layers.at(layers.size() - 1 - index); - self.mapView.mbglMap->removeLayer(layer->getID()); + MGLStyleLayer *styleLayer = [self layerFromMBGLLayer:layer]; + [styleLayer removeFromMapView:self.mapView]; } - (MGLStyleLayer *)layerFromMBGLLayer:(mbgl::style::Layer *)mbglLayer @@ -318,8 +337,15 @@ static NSURL *MGLStyleURL_emerald; } else if (auto circleLayer = mbglLayer->as<mbgl::style::CircleLayer>()) { MGLSource *source = [self sourceWithIdentifier:@(circleLayer->getSourceID().c_str())]; styleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:identifier source:source]; - } else if (mbglLayer->as<mbgl::style::BackgroundLayer>()) { + } else if (mbglLayer->is<mbgl::style::BackgroundLayer>()) { styleLayer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:identifier]; + } else if (auto customLayer = mbglLayer->as<mbgl::style::CustomLayer>()) { + styleLayer = self.openGLLayers[identifier]; + if (styleLayer) { + NSAssert(styleLayer.rawLayer == customLayer, @"%@ wraps a CustomLayer that differs from the one associated with the underlying style.", styleLayer); + return styleLayer; + } + styleLayer = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:identifier]; } else { NSAssert(NO, @"Unrecognized layer type"); return nil; @@ -359,7 +385,7 @@ static NSURL *MGLStyleURL_emerald; } [self willChangeValueForKey:@"layers"]; try { - [layer addToMapView:self.mapView]; + [layer addToMapView:self.mapView belowLayer:nil]; } catch (std::runtime_error & err) { [NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()]; } @@ -430,7 +456,7 @@ static NSURL *MGLStyleURL_emerald; sibling]; } else if (index + 1 == layers.size()) { try { - [layer addToMapView:self.mapView]; + [layer addToMapView:self.mapView belowLayer:nil]; } catch (std::runtime_error & err) { [NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()]; } @@ -509,19 +535,39 @@ static NSURL *MGLStyleURL_emerald; - (void)setImage:(MGLImage *)image forName:(NSString *)name { - NSAssert(image, @"image is null"); - NSAssert(name, @"name is null"); + if (!image) { + [NSException raise:NSInvalidArgumentException + format:@"Cannot assign nil image to “%@”.", name]; + } + if (!name) { + [NSException raise:NSInvalidArgumentException + format:@"Cannot assign image %@ to a nil name.", image]; + } self.mapView.mbglMap->addImage([name UTF8String], image.mgl_spriteImage); } - (void)removeImageForName:(NSString *)name { - NSAssert(name, @"name is null"); + if (!name) { + [NSException raise:NSInvalidArgumentException + format:@"Cannot remove image with nil name."]; + } self.mapView.mbglMap->removeImage([name UTF8String]); } +- (MGLImage *)imageForName:(NSString *)name +{ + if (!name) { + [NSException raise:NSInvalidArgumentException + format:@"Cannot get image with nil name."]; + } + + auto spriteImage = self.mapView.mbglMap->getImage([name UTF8String]); + return spriteImage ? [[MGLImage alloc] initWithMGLSpriteImage:spriteImage] : nil; +} + - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p; name = %@, URL = %@>", diff --git a/platform/darwin/src/MGLStyleLayer.h.ejs b/platform/darwin/src/MGLStyleLayer.h.ejs index b97d070b90..3b576e766b 100644 --- a/platform/darwin/src/MGLStyleLayer.h.ejs +++ b/platform/darwin/src/MGLStyleLayer.h.ejs @@ -91,9 +91,17 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) { <%- propertyReqs(property, layoutPropertiesByName, type) %> <% } -%> +<% if (property.original) { -%> + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-<%- type -%>-<%- property.original -%>"><code><%- property.original -%></code></a> layout property in the Mapbox Style Specification. +<% } -%> */ -@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(property.name) %>; +@property (nonatomic<% if (!property.required) { %>, null_resettable<% } if (property.getter) { %>, getter=<%- objCGetter(property) -%><% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(property.name) %>; +<% if (property.original) { %> +@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> __attribute__((unavailable("Use <%- camelizeWithLeadingLowercase(property.name) %> instead."))); + +<% } -%> <% } -%> <% } -%> <% if (paintProperties.length) { -%> @@ -109,9 +117,17 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) { <%- propertyReqs(property, paintPropertiesByName, type) %> <% } -%> +<% if (property.original) { -%> + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-<%- property.original -%>"><code><%- property.original -%></code></a> paint property in the Mapbox Style Specification. +<% } -%> */ -@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(property.name) %>; +@property (nonatomic<% if (!property.required) { %>, null_resettable<% } if (property.getter) { %>, getter=<%- objCGetter(property) -%><% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(property.name) %>; +<% if (property.original) { %> +@property (nonatomic<% if (!property.required) { %>, null_resettable<% } %>) MGLStyleValue<<%- propertyType(property, true) %>> *<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> __attribute__((unavailable("Use <%- camelizeWithLeadingLowercase(property.name) %> instead."))); + +<% } -%> <% } -%> <% } -%> @end diff --git a/platform/darwin/src/MGLStyleLayer.mm b/platform/darwin/src/MGLStyleLayer.mm index 6d9dabf25e..97f8f86b26 100644 --- a/platform/darwin/src/MGLStyleLayer.mm +++ b/platform/darwin/src/MGLStyleLayer.mm @@ -3,6 +3,12 @@ #include <mbgl/style/layer.hpp> +@interface MGLStyleLayer () + +@property (nonatomic) mbgl::style::Layer *rawLayer; + +@end + @implementation MGLStyleLayer - (instancetype)initWithIdentifier:(NSString *)identifier diff --git a/platform/darwin/src/MGLStyleLayer.mm.ejs b/platform/darwin/src/MGLStyleLayer.mm.ejs index 82d8a2561c..baeed3b882 100644 --- a/platform/darwin/src/MGLStyleLayer.mm.ejs +++ b/platform/darwin/src/MGLStyleLayer.mm.ejs @@ -21,9 +21,9 @@ namespace mbgl { <% if (layoutProperties.length) { -%> <% for (const property of layoutProperties) { -%> <% if (property.type == "enum") { -%> - MBGL_DEFINE_ENUM(MGL<%- camelize(originalPropertyName(property)) %>, { + MBGL_DEFINE_ENUM(MGL<%- camelize(property.name) %>, { <% for (const value in property.values) { -%> - { MGL<%- camelize(originalPropertyName(property)) %><%- camelize(value) %>, "<%-value%>" }, + { MGL<%- camelize(property.name) %><%- camelize(value) %>, "<%-value%>" }, <% } -%> }); @@ -33,9 +33,9 @@ namespace mbgl { <% if (paintProperties.length) { -%> <% for (const property of paintProperties) { -%> <% if (property.type == "enum") { -%> - MBGL_DEFINE_ENUM(MGL<%- camelize(originalPropertyName(property)) %>, { + MBGL_DEFINE_ENUM(MGL<%- camelize(property.name) %>, { <% for (const value in property.values) { -%> - { MGL<%- camelize(originalPropertyName(property)) %><%- camelize(value) %>, "<%-value%>" }, + { MGL<%- camelize(property.name) %><%- camelize(value) %>, "<%-value%>" }, <% } -%> }); @@ -62,7 +62,7 @@ namespace mbgl { if (self = [super initWithIdentifier:identifier]) { auto layer = std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(identifier.UTF8String); _pendingLayer = std::move(layer); - _rawLayer = _pendingLayer.get(); + self.rawLayer = _pendingLayer.get(); } return self; } @@ -73,17 +73,28 @@ namespace mbgl { if (self = [super initWithIdentifier:identifier source:source]) { auto layer = std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(identifier.UTF8String, source.identifier.UTF8String); _pendingLayer = std::move(layer); - _rawLayer = _pendingLayer.get(); + self.rawLayer = _pendingLayer.get(); } return self; } + <% } -%> +- (mbgl::style::<%- camelize(type) %>Layer *)rawLayer +{ + return (mbgl::style::<%- camelize(type) %>Layer *)super.rawLayer; +} + +- (void)setRawLayer:(mbgl::style::<%- camelize(type) %>Layer *)rawLayer +{ + super.rawLayer = rawLayer; +} + <% if (type !== 'background' && type !== 'raster') { -%> - (NSString *)sourceLayerIdentifier { MGLAssertStyleLayerIsValid(); - auto layerID = _rawLayer->getSourceLayer(); + auto layerID = self.rawLayer->getSourceLayer(); return layerID.empty() ? nil : @(layerID.c_str()); } @@ -91,26 +102,27 @@ namespace mbgl { { MGLAssertStyleLayerIsValid(); - _rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: ""); + self.rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: ""); } - (void)setPredicate:(NSPredicate *)predicate { MGLAssertStyleLayerIsValid(); - _rawLayer->setFilter(predicate.mgl_filter); + self.rawLayer->setFilter(predicate.mgl_filter); } - (NSPredicate *)predicate { MGLAssertStyleLayerIsValid(); - return [NSPredicate mgl_predicateWithFilter:_rawLayer->getFilter()]; + return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()]; } + <% } -%> -#pragma mark - Adding to and removing from a map view +#pragma mark - Adding to and removing from a map view -- (void)addToMapView:(MGLMapView *)mapView +- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer { if (_pendingLayer == nullptr) { [NSException raise:@"MGLRedundantLayerException" @@ -118,11 +130,6 @@ namespace mbgl { "to the style more than once is invalid.", self, mapView.style]; } - [self addToMapView:mapView belowLayer:nil]; -} - -- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer -{ if (otherLayer) { const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String}; mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId); @@ -134,7 +141,7 @@ namespace mbgl { - (void)removeFromMapView:(MGLMapView *)mapView { _pendingLayer = nullptr; - _rawLayer = nullptr; + self.rawLayer = nullptr; auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String); if (!removedLayer) { @@ -149,7 +156,7 @@ namespace mbgl { removedLayer.release(); _pendingLayer = std::unique_ptr<mbgl::style::<%- camelize(type) %>Layer>(layer); - _rawLayer = _pendingLayer.get(); + self.rawLayer = _pendingLayer.get(); } <% if (layoutProperties.length) { -%> @@ -160,25 +167,35 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); <% if (property.type == "enum") { -%> - auto mbglValue = MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(originalPropertyName(property)) %>>().toEnumPropertyValue(<%- objCName(property) %>); - _rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue); + auto mbglValue = MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>); + self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue); <% } else { -%> auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>); - _rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue); + self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue); <% } -%> } -- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCName(property) %> { +- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCGetter(property) %> { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: _rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>(); + auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>(); <% if (property.type == "enum") { -%> - return MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(originalPropertyName(property)) %>>().toEnumStyleValue(propertyValue); + return MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue); <% } else { -%> return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(propertyValue); <% } -%> } +<% if (property.original) { %> +- (void)set<%- camelize(originalPropertyName(property)) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> { + self.<%- camelizeWithLeadingLowercase(property.name) %> = <%- camelizeWithLeadingLowercase(originalPropertyName(property)) %>; +} + +- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> { + return self.<%- objCGetter(property) %>; +} + +<% } -%> <% } -%> <% } -%> <% if (paintProperties.length) { -%> @@ -189,25 +206,31 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); <% if (property.type == "enum") { -%> - auto mbglValue = MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(originalPropertyName(property)) %>>().toEnumPropertyValue(<%- objCName(property) %>); - _rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue); + auto mbglValue = MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>); + self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue); <% } else { -%> auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>); - _rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue); + self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue); <% } -%> } -- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCName(property) %> { +- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCGetter(property) %> { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: _rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>(); + auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>(); <% if (property.type == "enum") { -%> - return MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(originalPropertyName(property)) %>>().toEnumStyleValue(propertyValue); + return MGLStyleValueTransformer<mbgl::style::<%- mbglType(property) %>, NSValue *, mbgl::style::<%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue); <% } else { -%> return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(propertyValue); <% } -%> } +<% if (property.original) { %> +- (void)set<%- camelize(originalPropertyName(property)) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- camelizeWithLeadingLowercase(originalPropertyName(property)) %> { + NSAssert(NO, @"Use -set<%- camelize(property.name) %>: instead."); +} + +<% } -%> <% } -%> <% } -%> diff --git a/platform/darwin/src/MGLStyleLayer_Private.h b/platform/darwin/src/MGLStyleLayer_Private.h index e723c8cf1b..8f1cdfb4a1 100644 --- a/platform/darwin/src/MGLStyleLayer_Private.h +++ b/platform/darwin/src/MGLStyleLayer_Private.h @@ -5,6 +5,8 @@ #include <mbgl/style/layer.hpp> +NS_ASSUME_NONNULL_BEGIN + /** Assert that the style layer is valid. @@ -19,7 +21,7 @@ @"-[MGLStyle removeLayer:] has been called " \ @"with this instance but another style layer instance was added with the same identifer. It is an " \ @"error to send any message to this layer since it cannot be recovered after removal due to the " \ - @"identifer collision. Use unique identifiers for all layer instances including layers of " \ + @"identifier collision. Use unique identifiers for all layer instances including layers of " \ @"different types."]; \ } \ } while (NO); @@ -40,13 +42,14 @@ @property (nonatomic) mbgl::style::Layer *rawLayer; /** - Adds the mbgl style layer that this object represents to the mbgl map. - + Adds the mbgl style layer that this object represents to the mbgl map below the + specified `otherLayer`. + Once a mbgl style layer is added, ownership of the object is transferred to the `mbgl::Map` and this object no longer has an active unique_ptr reference to the `mbgl::style::Layer`. */ -- (void)addToMapView:(MGLMapView *)mapView; +- (void)addToMapView:(MGLMapView *)mapView belowLayer:(nullable MGLStyleLayer *)otherLayer; /** Removes the mbgl style layer that this object represents from the mbgl map. @@ -57,13 +60,6 @@ */ - (void)removeFromMapView:(MGLMapView *)mapView; -/** - Adds the mbgl style layer that this object represents to the mbgl map below the specified `otherLayer`. - - Once a mbgl style layer is added, ownership of the object is transferred to the - `mbgl::Map` and this object no longer has an active unique_ptr reference to the - `mbgl::style::Layer`. - */ -- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer; - @end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLStyleValue.mm b/platform/darwin/src/MGLStyleValue.mm index 43b51d6788..6ced819cd1 100644 --- a/platform/darwin/src/MGLStyleValue.mm +++ b/platform/darwin/src/MGLStyleValue.mm @@ -63,6 +63,10 @@ - (instancetype)initWithBase:(CGFloat)base stops:(NSDictionary *)stops { if (self = [super init]) { + if (!stops.count) + { + [NSException raise:NSInvalidArgumentException format:@"%@ requires at least one stop.", self]; + } _base = base; _stops = stops; } diff --git a/platform/darwin/src/MGLStyle_Private.h b/platform/darwin/src/MGLStyle_Private.h index 002be884e4..23ce8fbee0 100644 --- a/platform/darwin/src/MGLStyle_Private.h +++ b/platform/darwin/src/MGLStyle_Private.h @@ -2,7 +2,12 @@ #import "MGLStyleLayer.h" #import "MGLFillStyleLayer.h" -#import <mbgl/util/default_styles.hpp> + +NS_ASSUME_NONNULL_BEGIN + +@class MGLAttributionInfo; +@class MGLMapView; +@class MGLOpenGLStyleLayer; @interface MGLStyle (Private) @@ -10,6 +15,12 @@ @property (nonatomic, readonly, weak) MGLMapView *mapView; +- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor; + +@property (nonatomic, readonly, strong) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLOpenGLStyleLayer *) *openGLLayers; + - (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration; @end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h index dbb966b4e6..5a216e0354 100644 --- a/platform/darwin/src/MGLSymbolStyleLayer.h +++ b/platform/darwin/src/MGLSymbolStyleLayer.h @@ -113,21 +113,21 @@ typedef NS_ENUM(NSUInteger, MGLTextAnchor) { /** Text justification options. - Values of this type are used in the `textJustify` property of `MGLSymbolStyleLayer`. + Values of this type are used in the `textJustification` property of `MGLSymbolStyleLayer`. */ -typedef NS_ENUM(NSUInteger, MGLTextJustify) { +typedef NS_ENUM(NSUInteger, MGLTextJustification) { /** The text is aligned to the left. */ - MGLTextJustifyLeft, + MGLTextJustificationLeft, /** The text is centered. */ - MGLTextJustifyCenter, + MGLTextJustificationCenter, /** The text is aligned to the right. */ - MGLTextJustifyRight, + MGLTextJustificationRight, }; /** @@ -237,39 +237,45 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-allow-overlap"><code>icon-allow-overlap</code></a> layout property in the Mapbox Style Specification. */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconAllowOverlap; +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconAllowsOverlap; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconAllowOverlap __attribute__((unavailable("Use iconAllowsOverlap instead."))); /** If true, other symbols can be visible even if they collide with the icon. The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-ignore-placement"><code>icon-ignore-placement</code></a> layout property in the Mapbox Style Specification. */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconIgnorePlacement; +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconIgnoresPlacement; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconIgnorePlacement __attribute__((unavailable("Use iconIgnoresPlacement instead."))); /** A string with {tokens} replaced, referencing the data property to pull from. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-image"><code>icon-image</code></a> layout property in the Mapbox Style Specification. */ @property (nonatomic, null_resettable) MGLStyleValue<NSString *> *iconImageName; -/** - If true, the icon may be flipped to prevent it from being rendered upside-down. - - The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value. - - This property is only applied to the style if `iconImage` is non-`nil`, and `iconRotationAlignment` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconRotationAlignmentMap`, and `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored. - */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconKeepUpright; + +@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *iconImage __attribute__((unavailable("Use iconImageName instead."))); /** Offset distance of icon from its anchor. The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing a `CGVector` struct set to 0 from the left and 0 from the top. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconOffset; @@ -278,9 +284,9 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`, and `textField` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`, and `textField` is non-`nil`. Otherwise, it is ignored. */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconOptional; +@property (nonatomic, null_resettable, getter=isIconOptional) MGLStyleValue<NSNumber *> *iconOptional; /** Size of the additional area around the icon bounding box used for detecting symbol collisions. @@ -289,7 +295,7 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `2`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconPadding; @@ -300,16 +306,21 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-rotate"><code>icon-rotate</code></a> layout property in the Mapbox Style Specification. */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconRotate; +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconRotation; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconRotate __attribute__((unavailable("Use iconRotation instead."))); /** In combination with `symbolPlacement`, determines the rotation behavior of icons. The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconRotationAlignmentAuto`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconRotationAlignment; @@ -318,16 +329,21 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-size"><code>icon-size</code></a> layout property in the Mapbox Style Specification. */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconSize; +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconScale; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconSize __attribute__((unavailable("Use iconScale instead."))); /** Scales the icon to fit around the associated text. The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconTextFitNone`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`, and `textField` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`, and `textField` is non-`nil`. Otherwise, it is ignored. */ @property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTextFit; @@ -338,16 +354,81 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `NSEdgeInsetsZero` or `UIEdgeInsetsZero`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`, and `textField` is non-`nil`, and `iconTextFit` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconTextFitBoth`, `MGLIconTextFitWidth`, or `MGLIconTextFitHeight`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`, and `textField` is non-`nil`, and `iconTextFit` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconTextFitBoth`, `MGLIconTextFitWidth`, or `MGLIconTextFitHeight`. Otherwise, it is ignored. */ @property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTextFitPadding; /** + If true, the icon may be flipped to prevent it from being rendered upside-down. + + The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value. + + This property is only applied to the style if `iconImageName` is non-`nil`, and `iconRotationAlignment` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconRotationAlignmentMap`, and `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-keep-upright"><code>icon-keep-upright</code></a> layout property in the Mapbox Style Specification. + */ +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *keepsIconUpright; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconKeepUpright __attribute__((unavailable("Use keepsIconUpright instead."))); + +/** + If true, the text may be flipped vertically to prevent it from being rendered upside-down. + + The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `YES`. Set this property to `nil` to reset it to the default value. + + This property is only applied to the style if `textField` is non-`nil`, and `textRotationAlignment` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLTextRotationAlignmentMap`, and `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-keep-upright"><code>text-keep-upright</code></a> layout property in the Mapbox Style Specification. + */ +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *keepsTextUpright; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textKeepUpright __attribute__((unavailable("Use keepsTextUpright instead."))); + +/** + Maximum angle change between adjacent characters. + + This property is measured in degrees. + + The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `45`. Set this property to `nil` to reset it to the default value. + + This property is only applied to the style if `textField` is non-`nil`, and `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-max-angle"><code>text-max-angle</code></a> layout property in the Mapbox Style Specification. + */ +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumTextAngle; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textMaxAngle __attribute__((unavailable("Use maximumTextAngle instead."))); + +/** + The maximum line width for text wrapping. + + This property is measured in ems. + + The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `10`. Set this property to `nil` to reset it to the default value. + + This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-max-width"><code>text-max-width</code></a> layout property in the Mapbox Style Specification. + */ +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumTextWidth; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textMaxWidth __attribute__((unavailable("Use maximumTextWidth instead."))); + +/** If true, the symbols will not cross tile edges to avoid mutual collisions. Recommended in layers that don't have enough padding in the vector tile to prevent collisions, or if it is a point symbol layer placed after a line symbol layer. The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-symbol-avoid-edges"><code>symbol-avoid-edges</code></a> layout property in the Mapbox Style Specification. */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *symbolAvoidEdges; +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *symbolAvoidsEdges; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *symbolAvoidEdges __attribute__((unavailable("Use symbolAvoidsEdges instead."))); /** Label placement relative to its geometry. @@ -373,8 +454,13 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value. This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-allow-overlap"><code>text-allow-overlap</code></a> layout property in the Mapbox Style Specification. */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textAllowOverlap; +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textAllowsOverlap; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textAllowOverlap __attribute__((unavailable("Use textAllowsOverlap instead."))); /** Part of the text placed closest to the anchor. @@ -407,26 +493,27 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value. This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-ignore-placement"><code>text-ignore-placement</code></a> layout property in the Mapbox Style Specification. */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textIgnorePlacement; +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textIgnoresPlacement; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textIgnorePlacement __attribute__((unavailable("Use textIgnoresPlacement instead."))); /** Text justification options. - The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLTextJustifyCenter`. Set this property to `nil` to reset it to the default value. + The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLTextJustificationCenter`. Set this property to `nil` to reset it to the default value. This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored. - */ -@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textJustify; - -/** - If true, the text may be flipped vertically to prevent it from being rendered upside-down. - - The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `YES`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `textField` is non-`nil`, and `textRotationAlignment` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLTextRotationAlignmentMap`, and `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored. + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-justify"><code>text-justify</code></a> layout property in the Mapbox Style Specification. */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textKeepUpright; +@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textJustification; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textJustify __attribute__((unavailable("Use textJustification instead."))); /** Text tracking amount. @@ -451,28 +538,6 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { @property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textLineHeight; /** - Maximum angle change between adjacent characters. - - This property is measured in degrees. - - The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `45`. Set this property to `nil` to reset it to the default value. - - This property is only applied to the style if `textField` is non-`nil`, and `symbolPlacement` is set to an `MGLStyleValue` object containing an `NSValue` object containing `MGLSymbolPlacementLine`. Otherwise, it is ignored. - */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textMaxAngle; - -/** - The maximum line width for text wrapping. - - This property is measured in ems. - - The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `10`. Set this property to `nil` to reset it to the default value. - - This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored. - */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textMaxWidth; - -/** Offset distance of text from its anchor. This property is measured in ems. @@ -488,9 +553,9 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing `NO`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `textField` is non-`nil`, and `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `textField` is non-`nil`, and `iconImageName` is non-`nil`. Otherwise, it is ignored. */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textOptional; +@property (nonatomic, null_resettable, getter=isTextOptional) MGLStyleValue<NSNumber *> *textOptional; /** Size of the additional area around the text bounding box used for detecting symbol collisions. @@ -520,8 +585,13 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value. This property is only applied to the style if `textField` is non-`nil`. Otherwise, it is ignored. + + This attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-rotate"><code>text-rotate</code></a> layout property in the Mapbox Style Specification. */ -@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textRotate; +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textRotation; + + +@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textRotate __attribute__((unavailable("Use textRotation instead."))); /** In combination with `symbolPlacement`, determines the rotation behavior of the individual glyphs forming the text. @@ -556,20 +626,20 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { #if TARGET_OS_IPHONE /** - The color of the icon. This can only be used with sdf icons. + The tint color to apply to the icon. The `iconImageName` property must be set to a template image. The default value of this property is an `MGLStyleValue` object containing `UIColor.blackColor`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *iconColor; #else /** - The color of the icon. This can only be used with sdf icons. + The tint color to apply to the icon. The `iconImageName` property must be set to a template image. The default value of this property is an `MGLStyleValue` object containing `NSColor.blackColor`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *iconColor; #endif @@ -581,26 +651,26 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconHaloBlur; #if TARGET_OS_IPHONE /** - The color of the icon's halo. Icon halos can only be used with SDF icons. + The color of the icon’s halo. The `iconImageName` property must be set to a template image. The default value of this property is an `MGLStyleValue` object containing `UIColor.clearColor`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *iconHaloColor; #else /** - The color of the icon's halo. Icon halos can only be used with SDF icons. + The color of the icon’s halo. The `iconImageName` property must be set to a template image. The default value of this property is an `MGLStyleValue` object containing `NSColor.clearColor`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @property (nonatomic, null_resettable) MGLStyleValue<MGLColor *> *iconHaloColor; #endif @@ -612,7 +682,7 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `0`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconHaloWidth; @@ -621,7 +691,7 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { The default value of this property is an `MGLStyleValue` object containing an `NSNumber` object containing the float `1`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconOpacity; @@ -632,7 +702,7 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing a `CGVector` struct set to 0 points from the left and 0 points from the top. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`. Otherwise, it is ignored. */ @property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslate; @@ -641,7 +711,7 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslateAnchor) { The default value of this property is an `MGLStyleValue` object containing an `NSValue` object containing `MGLIconTranslateAnchorMap`. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `iconImage` is non-`nil`, and `iconTranslate` is non-`nil`. Otherwise, it is ignored. + This property is only applied to the style if `iconImageName` is non-`nil`, and `iconTranslate` is non-`nil`. Otherwise, it is ignored. */ @property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslateAnchor; diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm index d1d66f8ffb..31c584b473 100644 --- a/platform/darwin/src/MGLSymbolStyleLayer.mm +++ b/platform/darwin/src/MGLSymbolStyleLayer.mm @@ -41,10 +41,10 @@ namespace mbgl { { MGLTextAnchorBottomRight, "bottom-right" }, }); - MBGL_DEFINE_ENUM(MGLTextJustify, { - { MGLTextJustifyLeft, "left" }, - { MGLTextJustifyCenter, "center" }, - { MGLTextJustifyRight, "right" }, + MBGL_DEFINE_ENUM(MGLTextJustification, { + { MGLTextJustificationLeft, "left" }, + { MGLTextJustificationCenter, "center" }, + { MGLTextJustificationRight, "right" }, }); MBGL_DEFINE_ENUM(MGLTextPitchAlignment, { @@ -93,15 +93,26 @@ namespace mbgl { if (self = [super initWithIdentifier:identifier source:source]) { auto layer = std::make_unique<mbgl::style::SymbolLayer>(identifier.UTF8String, source.identifier.UTF8String); _pendingLayer = std::move(layer); - _rawLayer = _pendingLayer.get(); + self.rawLayer = _pendingLayer.get(); } return self; } + +- (mbgl::style::SymbolLayer *)rawLayer +{ + return (mbgl::style::SymbolLayer *)super.rawLayer; +} + +- (void)setRawLayer:(mbgl::style::SymbolLayer *)rawLayer +{ + super.rawLayer = rawLayer; +} + - (NSString *)sourceLayerIdentifier { MGLAssertStyleLayerIsValid(); - auto layerID = _rawLayer->getSourceLayer(); + auto layerID = self.rawLayer->getSourceLayer(); return layerID.empty() ? nil : @(layerID.c_str()); } @@ -109,25 +120,26 @@ namespace mbgl { { MGLAssertStyleLayerIsValid(); - _rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: ""); + self.rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: ""); } - (void)setPredicate:(NSPredicate *)predicate { MGLAssertStyleLayerIsValid(); - _rawLayer->setFilter(predicate.mgl_filter); + self.rawLayer->setFilter(predicate.mgl_filter); } - (NSPredicate *)predicate { MGLAssertStyleLayerIsValid(); - return [NSPredicate mgl_predicateWithFilter:_rawLayer->getFilter()]; + return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()]; } -#pragma mark - Adding to and removing from a map view -- (void)addToMapView:(MGLMapView *)mapView +#pragma mark - Adding to and removing from a map view + +- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer { if (_pendingLayer == nullptr) { [NSException raise:@"MGLRedundantLayerException" @@ -135,11 +147,6 @@ namespace mbgl { "to the style more than once is invalid.", self, mapView.style]; } - [self addToMapView:mapView belowLayer:nil]; -} - -- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer -{ if (otherLayer) { const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String}; mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId); @@ -151,7 +158,7 @@ namespace mbgl { - (void)removeFromMapView:(MGLMapView *)mapView { _pendingLayer = nullptr; - _rawLayer = nullptr; + self.rawLayer = nullptr; auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String); if (!removedLayer) { @@ -166,78 +173,91 @@ namespace mbgl { removedLayer.release(); _pendingLayer = std::unique_ptr<mbgl::style::SymbolLayer>(layer); - _rawLayer = _pendingLayer.get(); + self.rawLayer = _pendingLayer.get(); } #pragma mark - Accessing the Layout Attributes -- (void)setIconAllowOverlap:(MGLStyleValue<NSNumber *> *)iconAllowOverlap { +- (void)setIconAllowsOverlap:(MGLStyleValue<NSNumber *> *)iconAllowsOverlap { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(iconAllowOverlap); - _rawLayer->setIconAllowOverlap(mbglValue); + auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(iconAllowsOverlap); + self.rawLayer->setIconAllowOverlap(mbglValue); } -- (MGLStyleValue<NSNumber *> *)iconAllowOverlap { +- (MGLStyleValue<NSNumber *> *)iconAllowsOverlap { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconAllowOverlap() ?: _rawLayer->getDefaultIconAllowOverlap(); + auto propertyValue = self.rawLayer->getIconAllowOverlap() ?: self.rawLayer->getDefaultIconAllowOverlap(); return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue); } -- (void)setIconIgnorePlacement:(MGLStyleValue<NSNumber *> *)iconIgnorePlacement { + +- (void)setIconAllowOverlap:(MGLStyleValue<NSNumber *> *)iconAllowOverlap { + self.iconAllowsOverlap = iconAllowOverlap; +} + +- (MGLStyleValue<NSNumber *> *)iconAllowOverlap { + return self.iconAllowsOverlap; +} + +- (void)setIconIgnoresPlacement:(MGLStyleValue<NSNumber *> *)iconIgnoresPlacement { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(iconIgnorePlacement); - _rawLayer->setIconIgnorePlacement(mbglValue); + auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(iconIgnoresPlacement); + self.rawLayer->setIconIgnorePlacement(mbglValue); } -- (MGLStyleValue<NSNumber *> *)iconIgnorePlacement { +- (MGLStyleValue<NSNumber *> *)iconIgnoresPlacement { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconIgnorePlacement() ?: _rawLayer->getDefaultIconIgnorePlacement(); + auto propertyValue = self.rawLayer->getIconIgnorePlacement() ?: self.rawLayer->getDefaultIconIgnorePlacement(); return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue); } + +- (void)setIconIgnorePlacement:(MGLStyleValue<NSNumber *> *)iconIgnorePlacement { + self.iconIgnoresPlacement = iconIgnorePlacement; +} + +- (MGLStyleValue<NSNumber *> *)iconIgnorePlacement { + return self.iconIgnoresPlacement; +} + - (void)setIconImageName:(MGLStyleValue<NSString *> *)iconImageName { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(iconImageName); - _rawLayer->setIconImage(mbglValue); + self.rawLayer->setIconImage(mbglValue); } - (MGLStyleValue<NSString *> *)iconImageName { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconImage() ?: _rawLayer->getDefaultIconImage(); + auto propertyValue = self.rawLayer->getIconImage() ?: self.rawLayer->getDefaultIconImage(); return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue); } -- (void)setIconKeepUpright:(MGLStyleValue<NSNumber *> *)iconKeepUpright { - MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(iconKeepUpright); - _rawLayer->setIconKeepUpright(mbglValue); +- (void)setIconImage:(MGLStyleValue<NSString *> *)iconImage { + self.iconImageName = iconImage; } -- (MGLStyleValue<NSNumber *> *)iconKeepUpright { - MGLAssertStyleLayerIsValid(); - - auto propertyValue = _rawLayer->getIconKeepUpright() ?: _rawLayer->getDefaultIconKeepUpright(); - return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue); +- (MGLStyleValue<NSString *> *)iconImage { + return self.iconImageName; } - (void)setIconOffset:(MGLStyleValue<NSValue *> *)iconOffset { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(iconOffset); - _rawLayer->setIconOffset(mbglValue); + self.rawLayer->setIconOffset(mbglValue); } - (MGLStyleValue<NSValue *> *)iconOffset { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconOffset() ?: _rawLayer->getDefaultIconOffset(); + auto propertyValue = self.rawLayer->getIconOffset() ?: self.rawLayer->getDefaultIconOffset(); return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue); } @@ -245,13 +265,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(iconOptional); - _rawLayer->setIconOptional(mbglValue); + self.rawLayer->setIconOptional(mbglValue); } -- (MGLStyleValue<NSNumber *> *)iconOptional { +- (MGLStyleValue<NSNumber *> *)isIconOptional { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconOptional() ?: _rawLayer->getDefaultIconOptional(); + auto propertyValue = self.rawLayer->getIconOptional() ?: self.rawLayer->getDefaultIconOptional(); return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue); } @@ -259,69 +279,87 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(iconPadding); - _rawLayer->setIconPadding(mbglValue); + self.rawLayer->setIconPadding(mbglValue); } - (MGLStyleValue<NSNumber *> *)iconPadding { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconPadding() ?: _rawLayer->getDefaultIconPadding(); + auto propertyValue = self.rawLayer->getIconPadding() ?: self.rawLayer->getDefaultIconPadding(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } -- (void)setIconRotate:(MGLStyleValue<NSNumber *> *)iconRotate { +- (void)setIconRotation:(MGLStyleValue<NSNumber *> *)iconRotation { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(iconRotate); - _rawLayer->setIconRotate(mbglValue); + auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(iconRotation); + self.rawLayer->setIconRotate(mbglValue); } -- (MGLStyleValue<NSNumber *> *)iconRotate { +- (MGLStyleValue<NSNumber *> *)iconRotation { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconRotate() ?: _rawLayer->getDefaultIconRotate(); + auto propertyValue = self.rawLayer->getIconRotate() ?: self.rawLayer->getDefaultIconRotate(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } + +- (void)setIconRotate:(MGLStyleValue<NSNumber *> *)iconRotate { + self.iconRotation = iconRotate; +} + +- (MGLStyleValue<NSNumber *> *)iconRotate { + return self.iconRotation; +} + - (void)setIconRotationAlignment:(MGLStyleValue<NSValue *> *)iconRotationAlignment { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconRotationAlignment>().toEnumPropertyValue(iconRotationAlignment); - _rawLayer->setIconRotationAlignment(mbglValue); + self.rawLayer->setIconRotationAlignment(mbglValue); } - (MGLStyleValue<NSValue *> *)iconRotationAlignment { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconRotationAlignment() ?: _rawLayer->getDefaultIconRotationAlignment(); + auto propertyValue = self.rawLayer->getIconRotationAlignment() ?: self.rawLayer->getDefaultIconRotationAlignment(); return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconRotationAlignment>().toEnumStyleValue(propertyValue); } -- (void)setIconSize:(MGLStyleValue<NSNumber *> *)iconSize { +- (void)setIconScale:(MGLStyleValue<NSNumber *> *)iconScale { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(iconSize); - _rawLayer->setIconSize(mbglValue); + auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(iconScale); + self.rawLayer->setIconSize(mbglValue); } -- (MGLStyleValue<NSNumber *> *)iconSize { +- (MGLStyleValue<NSNumber *> *)iconScale { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconSize() ?: _rawLayer->getDefaultIconSize(); + auto propertyValue = self.rawLayer->getIconSize() ?: self.rawLayer->getDefaultIconSize(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } + +- (void)setIconSize:(MGLStyleValue<NSNumber *> *)iconSize { + self.iconScale = iconSize; +} + +- (MGLStyleValue<NSNumber *> *)iconSize { + return self.iconScale; +} + - (void)setIconTextFit:(MGLStyleValue<NSValue *> *)iconTextFit { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::style::IconTextFitType, NSValue *, mbgl::style::IconTextFitType, MGLIconTextFit>().toEnumPropertyValue(iconTextFit); - _rawLayer->setIconTextFit(mbglValue); + self.rawLayer->setIconTextFit(mbglValue); } - (MGLStyleValue<NSValue *> *)iconTextFit { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconTextFit() ?: _rawLayer->getDefaultIconTextFit(); + auto propertyValue = self.rawLayer->getIconTextFit() ?: self.rawLayer->getDefaultIconTextFit(); return MGLStyleValueTransformer<mbgl::style::IconTextFitType, NSValue *, mbgl::style::IconTextFitType, MGLIconTextFit>().toEnumStyleValue(propertyValue); } @@ -329,41 +367,142 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<std::array<float, 4>, NSValue *>().toPropertyValue(iconTextFitPadding); - _rawLayer->setIconTextFitPadding(mbglValue); + self.rawLayer->setIconTextFitPadding(mbglValue); } - (MGLStyleValue<NSValue *> *)iconTextFitPadding { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconTextFitPadding() ?: _rawLayer->getDefaultIconTextFitPadding(); + auto propertyValue = self.rawLayer->getIconTextFitPadding() ?: self.rawLayer->getDefaultIconTextFitPadding(); return MGLStyleValueTransformer<std::array<float, 4>, NSValue *>().toStyleValue(propertyValue); } -- (void)setSymbolAvoidEdges:(MGLStyleValue<NSNumber *> *)symbolAvoidEdges { +- (void)setKeepsIconUpright:(MGLStyleValue<NSNumber *> *)keepsIconUpright { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(symbolAvoidEdges); - _rawLayer->setSymbolAvoidEdges(mbglValue); + auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(keepsIconUpright); + self.rawLayer->setIconKeepUpright(mbglValue); } -- (MGLStyleValue<NSNumber *> *)symbolAvoidEdges { +- (MGLStyleValue<NSNumber *> *)keepsIconUpright { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getIconKeepUpright() ?: self.rawLayer->getDefaultIconKeepUpright(); + return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue); +} + + +- (void)setIconKeepUpright:(MGLStyleValue<NSNumber *> *)iconKeepUpright { + self.keepsIconUpright = iconKeepUpright; +} + +- (MGLStyleValue<NSNumber *> *)iconKeepUpright { + return self.keepsIconUpright; +} + +- (void)setKeepsTextUpright:(MGLStyleValue<NSNumber *> *)keepsTextUpright { + MGLAssertStyleLayerIsValid(); + + auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(keepsTextUpright); + self.rawLayer->setTextKeepUpright(mbglValue); +} + +- (MGLStyleValue<NSNumber *> *)keepsTextUpright { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getSymbolAvoidEdges() ?: _rawLayer->getDefaultSymbolAvoidEdges(); + auto propertyValue = self.rawLayer->getTextKeepUpright() ?: self.rawLayer->getDefaultTextKeepUpright(); return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue); } + +- (void)setTextKeepUpright:(MGLStyleValue<NSNumber *> *)textKeepUpright { + self.keepsTextUpright = textKeepUpright; +} + +- (MGLStyleValue<NSNumber *> *)textKeepUpright { + return self.keepsTextUpright; +} + +- (void)setMaximumTextAngle:(MGLStyleValue<NSNumber *> *)maximumTextAngle { + MGLAssertStyleLayerIsValid(); + + auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(maximumTextAngle); + self.rawLayer->setTextMaxAngle(mbglValue); +} + +- (MGLStyleValue<NSNumber *> *)maximumTextAngle { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getTextMaxAngle() ?: self.rawLayer->getDefaultTextMaxAngle(); + return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); +} + + +- (void)setTextMaxAngle:(MGLStyleValue<NSNumber *> *)textMaxAngle { + self.maximumTextAngle = textMaxAngle; +} + +- (MGLStyleValue<NSNumber *> *)textMaxAngle { + return self.maximumTextAngle; +} + +- (void)setMaximumTextWidth:(MGLStyleValue<NSNumber *> *)maximumTextWidth { + MGLAssertStyleLayerIsValid(); + + auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(maximumTextWidth); + self.rawLayer->setTextMaxWidth(mbglValue); +} + +- (MGLStyleValue<NSNumber *> *)maximumTextWidth { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getTextMaxWidth() ?: self.rawLayer->getDefaultTextMaxWidth(); + return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); +} + + +- (void)setTextMaxWidth:(MGLStyleValue<NSNumber *> *)textMaxWidth { + self.maximumTextWidth = textMaxWidth; +} + +- (MGLStyleValue<NSNumber *> *)textMaxWidth { + return self.maximumTextWidth; +} + +- (void)setSymbolAvoidsEdges:(MGLStyleValue<NSNumber *> *)symbolAvoidsEdges { + MGLAssertStyleLayerIsValid(); + + auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(symbolAvoidsEdges); + self.rawLayer->setSymbolAvoidEdges(mbglValue); +} + +- (MGLStyleValue<NSNumber *> *)symbolAvoidsEdges { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getSymbolAvoidEdges() ?: self.rawLayer->getDefaultSymbolAvoidEdges(); + return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue); +} + + +- (void)setSymbolAvoidEdges:(MGLStyleValue<NSNumber *> *)symbolAvoidEdges { + self.symbolAvoidsEdges = symbolAvoidEdges; +} + +- (MGLStyleValue<NSNumber *> *)symbolAvoidEdges { + return self.symbolAvoidsEdges; +} + - (void)setSymbolPlacement:(MGLStyleValue<NSValue *> *)symbolPlacement { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::style::SymbolPlacementType, NSValue *, mbgl::style::SymbolPlacementType, MGLSymbolPlacement>().toEnumPropertyValue(symbolPlacement); - _rawLayer->setSymbolPlacement(mbglValue); + self.rawLayer->setSymbolPlacement(mbglValue); } - (MGLStyleValue<NSValue *> *)symbolPlacement { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getSymbolPlacement() ?: _rawLayer->getDefaultSymbolPlacement(); + auto propertyValue = self.rawLayer->getSymbolPlacement() ?: self.rawLayer->getDefaultSymbolPlacement(); return MGLStyleValueTransformer<mbgl::style::SymbolPlacementType, NSValue *, mbgl::style::SymbolPlacementType, MGLSymbolPlacement>().toEnumStyleValue(propertyValue); } @@ -371,41 +510,50 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(symbolSpacing); - _rawLayer->setSymbolSpacing(mbglValue); + self.rawLayer->setSymbolSpacing(mbglValue); } - (MGLStyleValue<NSNumber *> *)symbolSpacing { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getSymbolSpacing() ?: _rawLayer->getDefaultSymbolSpacing(); + auto propertyValue = self.rawLayer->getSymbolSpacing() ?: self.rawLayer->getDefaultSymbolSpacing(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } -- (void)setTextAllowOverlap:(MGLStyleValue<NSNumber *> *)textAllowOverlap { +- (void)setTextAllowsOverlap:(MGLStyleValue<NSNumber *> *)textAllowsOverlap { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(textAllowOverlap); - _rawLayer->setTextAllowOverlap(mbglValue); + auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(textAllowsOverlap); + self.rawLayer->setTextAllowOverlap(mbglValue); } -- (MGLStyleValue<NSNumber *> *)textAllowOverlap { +- (MGLStyleValue<NSNumber *> *)textAllowsOverlap { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextAllowOverlap() ?: _rawLayer->getDefaultTextAllowOverlap(); + auto propertyValue = self.rawLayer->getTextAllowOverlap() ?: self.rawLayer->getDefaultTextAllowOverlap(); return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue); } + +- (void)setTextAllowOverlap:(MGLStyleValue<NSNumber *> *)textAllowOverlap { + self.textAllowsOverlap = textAllowOverlap; +} + +- (MGLStyleValue<NSNumber *> *)textAllowOverlap { + return self.textAllowsOverlap; +} + - (void)setTextAnchor:(MGLStyleValue<NSValue *> *)textAnchor { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::style::TextAnchorType, NSValue *, mbgl::style::TextAnchorType, MGLTextAnchor>().toEnumPropertyValue(textAnchor); - _rawLayer->setTextAnchor(mbglValue); + self.rawLayer->setTextAnchor(mbglValue); } - (MGLStyleValue<NSValue *> *)textAnchor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextAnchor() ?: _rawLayer->getDefaultTextAnchor(); + auto propertyValue = self.rawLayer->getTextAnchor() ?: self.rawLayer->getDefaultTextAnchor(); return MGLStyleValueTransformer<mbgl::style::TextAnchorType, NSValue *, mbgl::style::TextAnchorType, MGLTextAnchor>().toEnumStyleValue(propertyValue); } @@ -413,13 +561,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(textField); - _rawLayer->setTextField(mbglValue); + self.rawLayer->setTextField(mbglValue); } - (MGLStyleValue<NSString *> *)textField { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextField() ?: _rawLayer->getDefaultTextField(); + auto propertyValue = self.rawLayer->getTextField() ?: self.rawLayer->getDefaultTextField(); return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue); } @@ -427,69 +575,73 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toPropertyValue(textFont); - _rawLayer->setTextFont(mbglValue); + self.rawLayer->setTextFont(mbglValue); } - (MGLStyleValue<NSArray<NSString *> *> *)textFont { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextFont() ?: _rawLayer->getDefaultTextFont(); + auto propertyValue = self.rawLayer->getTextFont() ?: self.rawLayer->getDefaultTextFont(); return MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toStyleValue(propertyValue); } -- (void)setTextIgnorePlacement:(MGLStyleValue<NSNumber *> *)textIgnorePlacement { +- (void)setTextIgnoresPlacement:(MGLStyleValue<NSNumber *> *)textIgnoresPlacement { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(textIgnorePlacement); - _rawLayer->setTextIgnorePlacement(mbglValue); + auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(textIgnoresPlacement); + self.rawLayer->setTextIgnorePlacement(mbglValue); } -- (MGLStyleValue<NSNumber *> *)textIgnorePlacement { +- (MGLStyleValue<NSNumber *> *)textIgnoresPlacement { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextIgnorePlacement() ?: _rawLayer->getDefaultTextIgnorePlacement(); + auto propertyValue = self.rawLayer->getTextIgnorePlacement() ?: self.rawLayer->getDefaultTextIgnorePlacement(); return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue); } -- (void)setTextJustify:(MGLStyleValue<NSValue *> *)textJustify { - MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustify>().toEnumPropertyValue(textJustify); - _rawLayer->setTextJustify(mbglValue); +- (void)setTextIgnorePlacement:(MGLStyleValue<NSNumber *> *)textIgnorePlacement { + self.textIgnoresPlacement = textIgnorePlacement; } -- (MGLStyleValue<NSValue *> *)textJustify { +- (MGLStyleValue<NSNumber *> *)textIgnorePlacement { + return self.textIgnoresPlacement; +} + +- (void)setTextJustification:(MGLStyleValue<NSValue *> *)textJustification { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextJustify() ?: _rawLayer->getDefaultTextJustify(); - return MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustify>().toEnumStyleValue(propertyValue); + auto mbglValue = MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toEnumPropertyValue(textJustification); + self.rawLayer->setTextJustify(mbglValue); } -- (void)setTextKeepUpright:(MGLStyleValue<NSNumber *> *)textKeepUpright { +- (MGLStyleValue<NSValue *> *)textJustification { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(textKeepUpright); - _rawLayer->setTextKeepUpright(mbglValue); + auto propertyValue = self.rawLayer->getTextJustify() ?: self.rawLayer->getDefaultTextJustify(); + return MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toEnumStyleValue(propertyValue); } -- (MGLStyleValue<NSNumber *> *)textKeepUpright { - MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextKeepUpright() ?: _rawLayer->getDefaultTextKeepUpright(); - return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue); +- (void)setTextJustify:(MGLStyleValue<NSValue *> *)textJustify { + self.textJustification = textJustify; +} + +- (MGLStyleValue<NSValue *> *)textJustify { + return self.textJustification; } - (void)setTextLetterSpacing:(MGLStyleValue<NSNumber *> *)textLetterSpacing { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textLetterSpacing); - _rawLayer->setTextLetterSpacing(mbglValue); + self.rawLayer->setTextLetterSpacing(mbglValue); } - (MGLStyleValue<NSNumber *> *)textLetterSpacing { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextLetterSpacing() ?: _rawLayer->getDefaultTextLetterSpacing(); + auto propertyValue = self.rawLayer->getTextLetterSpacing() ?: self.rawLayer->getDefaultTextLetterSpacing(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -497,41 +649,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textLineHeight); - _rawLayer->setTextLineHeight(mbglValue); + self.rawLayer->setTextLineHeight(mbglValue); } - (MGLStyleValue<NSNumber *> *)textLineHeight { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextLineHeight() ?: _rawLayer->getDefaultTextLineHeight(); - return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); -} - -- (void)setTextMaxAngle:(MGLStyleValue<NSNumber *> *)textMaxAngle { - MGLAssertStyleLayerIsValid(); - - auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textMaxAngle); - _rawLayer->setTextMaxAngle(mbglValue); -} - -- (MGLStyleValue<NSNumber *> *)textMaxAngle { - MGLAssertStyleLayerIsValid(); - - auto propertyValue = _rawLayer->getTextMaxAngle() ?: _rawLayer->getDefaultTextMaxAngle(); - return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); -} - -- (void)setTextMaxWidth:(MGLStyleValue<NSNumber *> *)textMaxWidth { - MGLAssertStyleLayerIsValid(); - - auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textMaxWidth); - _rawLayer->setTextMaxWidth(mbglValue); -} - -- (MGLStyleValue<NSNumber *> *)textMaxWidth { - MGLAssertStyleLayerIsValid(); - - auto propertyValue = _rawLayer->getTextMaxWidth() ?: _rawLayer->getDefaultTextMaxWidth(); + auto propertyValue = self.rawLayer->getTextLineHeight() ?: self.rawLayer->getDefaultTextLineHeight(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -539,13 +663,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(textOffset); - _rawLayer->setTextOffset(mbglValue); + self.rawLayer->setTextOffset(mbglValue); } - (MGLStyleValue<NSValue *> *)textOffset { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextOffset() ?: _rawLayer->getDefaultTextOffset(); + auto propertyValue = self.rawLayer->getTextOffset() ?: self.rawLayer->getDefaultTextOffset(); return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue); } @@ -553,13 +677,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<bool, NSNumber *>().toPropertyValue(textOptional); - _rawLayer->setTextOptional(mbglValue); + self.rawLayer->setTextOptional(mbglValue); } -- (MGLStyleValue<NSNumber *> *)textOptional { +- (MGLStyleValue<NSNumber *> *)isTextOptional { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextOptional() ?: _rawLayer->getDefaultTextOptional(); + auto propertyValue = self.rawLayer->getTextOptional() ?: self.rawLayer->getDefaultTextOptional(); return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue); } @@ -567,13 +691,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textPadding); - _rawLayer->setTextPadding(mbglValue); + self.rawLayer->setTextPadding(mbglValue); } - (MGLStyleValue<NSNumber *> *)textPadding { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextPadding() ?: _rawLayer->getDefaultTextPadding(); + auto propertyValue = self.rawLayer->getTextPadding() ?: self.rawLayer->getDefaultTextPadding(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -581,41 +705,50 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextPitchAlignment>().toEnumPropertyValue(textPitchAlignment); - _rawLayer->setTextPitchAlignment(mbglValue); + self.rawLayer->setTextPitchAlignment(mbglValue); } - (MGLStyleValue<NSValue *> *)textPitchAlignment { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextPitchAlignment() ?: _rawLayer->getDefaultTextPitchAlignment(); + auto propertyValue = self.rawLayer->getTextPitchAlignment() ?: self.rawLayer->getDefaultTextPitchAlignment(); return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextPitchAlignment>().toEnumStyleValue(propertyValue); } -- (void)setTextRotate:(MGLStyleValue<NSNumber *> *)textRotate { +- (void)setTextRotation:(MGLStyleValue<NSNumber *> *)textRotation { MGLAssertStyleLayerIsValid(); - auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textRotate); - _rawLayer->setTextRotate(mbglValue); + auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textRotation); + self.rawLayer->setTextRotate(mbglValue); } -- (MGLStyleValue<NSNumber *> *)textRotate { +- (MGLStyleValue<NSNumber *> *)textRotation { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextRotate() ?: _rawLayer->getDefaultTextRotate(); + auto propertyValue = self.rawLayer->getTextRotate() ?: self.rawLayer->getDefaultTextRotate(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } + +- (void)setTextRotate:(MGLStyleValue<NSNumber *> *)textRotate { + self.textRotation = textRotate; +} + +- (MGLStyleValue<NSNumber *> *)textRotate { + return self.textRotation; +} + - (void)setTextRotationAlignment:(MGLStyleValue<NSValue *> *)textRotationAlignment { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextRotationAlignment>().toEnumPropertyValue(textRotationAlignment); - _rawLayer->setTextRotationAlignment(mbglValue); + self.rawLayer->setTextRotationAlignment(mbglValue); } - (MGLStyleValue<NSValue *> *)textRotationAlignment { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextRotationAlignment() ?: _rawLayer->getDefaultTextRotationAlignment(); + auto propertyValue = self.rawLayer->getTextRotationAlignment() ?: self.rawLayer->getDefaultTextRotationAlignment(); return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextRotationAlignment>().toEnumStyleValue(propertyValue); } @@ -623,13 +756,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textSize); - _rawLayer->setTextSize(mbglValue); + self.rawLayer->setTextSize(mbglValue); } - (MGLStyleValue<NSNumber *> *)textSize { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextSize() ?: _rawLayer->getDefaultTextSize(); + auto propertyValue = self.rawLayer->getTextSize() ?: self.rawLayer->getDefaultTextSize(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -637,13 +770,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::style::TextTransformType, NSValue *, mbgl::style::TextTransformType, MGLTextTransform>().toEnumPropertyValue(textTransform); - _rawLayer->setTextTransform(mbglValue); + self.rawLayer->setTextTransform(mbglValue); } - (MGLStyleValue<NSValue *> *)textTransform { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextTransform() ?: _rawLayer->getDefaultTextTransform(); + auto propertyValue = self.rawLayer->getTextTransform() ?: self.rawLayer->getDefaultTextTransform(); return MGLStyleValueTransformer<mbgl::style::TextTransformType, NSValue *, mbgl::style::TextTransformType, MGLTextTransform>().toEnumStyleValue(propertyValue); } @@ -653,13 +786,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(iconColor); - _rawLayer->setIconColor(mbglValue); + self.rawLayer->setIconColor(mbglValue); } - (MGLStyleValue<MGLColor *> *)iconColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconColor() ?: _rawLayer->getDefaultIconColor(); + auto propertyValue = self.rawLayer->getIconColor() ?: self.rawLayer->getDefaultIconColor(); return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue); } @@ -667,13 +800,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(iconHaloBlur); - _rawLayer->setIconHaloBlur(mbglValue); + self.rawLayer->setIconHaloBlur(mbglValue); } - (MGLStyleValue<NSNumber *> *)iconHaloBlur { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconHaloBlur() ?: _rawLayer->getDefaultIconHaloBlur(); + auto propertyValue = self.rawLayer->getIconHaloBlur() ?: self.rawLayer->getDefaultIconHaloBlur(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -681,13 +814,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(iconHaloColor); - _rawLayer->setIconHaloColor(mbglValue); + self.rawLayer->setIconHaloColor(mbglValue); } - (MGLStyleValue<MGLColor *> *)iconHaloColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconHaloColor() ?: _rawLayer->getDefaultIconHaloColor(); + auto propertyValue = self.rawLayer->getIconHaloColor() ?: self.rawLayer->getDefaultIconHaloColor(); return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue); } @@ -695,13 +828,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(iconHaloWidth); - _rawLayer->setIconHaloWidth(mbglValue); + self.rawLayer->setIconHaloWidth(mbglValue); } - (MGLStyleValue<NSNumber *> *)iconHaloWidth { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconHaloWidth() ?: _rawLayer->getDefaultIconHaloWidth(); + auto propertyValue = self.rawLayer->getIconHaloWidth() ?: self.rawLayer->getDefaultIconHaloWidth(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -709,13 +842,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(iconOpacity); - _rawLayer->setIconOpacity(mbglValue); + self.rawLayer->setIconOpacity(mbglValue); } - (MGLStyleValue<NSNumber *> *)iconOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconOpacity() ?: _rawLayer->getDefaultIconOpacity(); + auto propertyValue = self.rawLayer->getIconOpacity() ?: self.rawLayer->getDefaultIconOpacity(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -723,13 +856,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(iconTranslate); - _rawLayer->setIconTranslate(mbglValue); + self.rawLayer->setIconTranslate(mbglValue); } - (MGLStyleValue<NSValue *> *)iconTranslate { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconTranslate() ?: _rawLayer->getDefaultIconTranslate(); + auto propertyValue = self.rawLayer->getIconTranslate() ?: self.rawLayer->getDefaultIconTranslate(); return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue); } @@ -737,13 +870,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslateAnchor>().toEnumPropertyValue(iconTranslateAnchor); - _rawLayer->setIconTranslateAnchor(mbglValue); + self.rawLayer->setIconTranslateAnchor(mbglValue); } - (MGLStyleValue<NSValue *> *)iconTranslateAnchor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getIconTranslateAnchor() ?: _rawLayer->getDefaultIconTranslateAnchor(); + auto propertyValue = self.rawLayer->getIconTranslateAnchor() ?: self.rawLayer->getDefaultIconTranslateAnchor(); return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslateAnchor>().toEnumStyleValue(propertyValue); } @@ -751,13 +884,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(textColor); - _rawLayer->setTextColor(mbglValue); + self.rawLayer->setTextColor(mbglValue); } - (MGLStyleValue<MGLColor *> *)textColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextColor() ?: _rawLayer->getDefaultTextColor(); + auto propertyValue = self.rawLayer->getTextColor() ?: self.rawLayer->getDefaultTextColor(); return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue); } @@ -765,13 +898,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textHaloBlur); - _rawLayer->setTextHaloBlur(mbglValue); + self.rawLayer->setTextHaloBlur(mbglValue); } - (MGLStyleValue<NSNumber *> *)textHaloBlur { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextHaloBlur() ?: _rawLayer->getDefaultTextHaloBlur(); + auto propertyValue = self.rawLayer->getTextHaloBlur() ?: self.rawLayer->getDefaultTextHaloBlur(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -779,13 +912,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(textHaloColor); - _rawLayer->setTextHaloColor(mbglValue); + self.rawLayer->setTextHaloColor(mbglValue); } - (MGLStyleValue<MGLColor *> *)textHaloColor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextHaloColor() ?: _rawLayer->getDefaultTextHaloColor(); + auto propertyValue = self.rawLayer->getTextHaloColor() ?: self.rawLayer->getDefaultTextHaloColor(); return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue); } @@ -793,13 +926,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textHaloWidth); - _rawLayer->setTextHaloWidth(mbglValue); + self.rawLayer->setTextHaloWidth(mbglValue); } - (MGLStyleValue<NSNumber *> *)textHaloWidth { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextHaloWidth() ?: _rawLayer->getDefaultTextHaloWidth(); + auto propertyValue = self.rawLayer->getTextHaloWidth() ?: self.rawLayer->getDefaultTextHaloWidth(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -807,13 +940,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textOpacity); - _rawLayer->setTextOpacity(mbglValue); + self.rawLayer->setTextOpacity(mbglValue); } - (MGLStyleValue<NSNumber *> *)textOpacity { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextOpacity() ?: _rawLayer->getDefaultTextOpacity(); + auto propertyValue = self.rawLayer->getTextOpacity() ?: self.rawLayer->getDefaultTextOpacity(); return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue); } @@ -821,13 +954,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(textTranslate); - _rawLayer->setTextTranslate(mbglValue); + self.rawLayer->setTextTranslate(mbglValue); } - (MGLStyleValue<NSValue *> *)textTranslate { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextTranslate() ?: _rawLayer->getDefaultTextTranslate(); + auto propertyValue = self.rawLayer->getTextTranslate() ?: self.rawLayer->getDefaultTextTranslate(); return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue); } @@ -835,13 +968,13 @@ namespace mbgl { MGLAssertStyleLayerIsValid(); auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslateAnchor>().toEnumPropertyValue(textTranslateAnchor); - _rawLayer->setTextTranslateAnchor(mbglValue); + self.rawLayer->setTextTranslateAnchor(mbglValue); } - (MGLStyleValue<NSValue *> *)textTranslateAnchor { MGLAssertStyleLayerIsValid(); - auto propertyValue = _rawLayer->getTextTranslateAnchor() ?: _rawLayer->getDefaultTextTranslateAnchor(); + auto propertyValue = self.rawLayer->getTextTranslateAnchor() ?: self.rawLayer->getDefaultTextTranslateAnchor(); return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslateAnchor>().toEnumStyleValue(propertyValue); } diff --git a/platform/darwin/src/MGLTileSet.h b/platform/darwin/src/MGLTileSet.h deleted file mode 100644 index 08a34338b1..0000000000 --- a/platform/darwin/src/MGLTileSet.h +++ /dev/null @@ -1,78 +0,0 @@ -#import <Foundation/Foundation.h> -#import "MGLTypes.h" - -NS_ASSUME_NONNULL_BEGIN - -/** These constants represent the scheme that the tile URL templates will use. */ -typedef NS_ENUM(NSUInteger, MGLTileSetScheme) { - MGLTileSetSchemeXYZ = 0, - MGLTileSetSchemeTMS -}; - -/** - The `MGLTileSet` class holds the tile URL template strings and associated - configuration for those strings. It can be passed to an `MGLVectorSource` or - `MGLRasterSource` instead of an `NSURL` representing a TileJSON URL to create a - source. - */ -@interface MGLTileSet : NSObject - -/** - An `NSArray` of `NSString` objects that represent the tile templates. - */ -@property (nonatomic, copy) NS_ARRAY_OF(NSString *) *tileURLTemplates; - -/** - An `NSNumber` object containing an integer; specifies the minimum zoom level at - which the source will display tiles. The value should be in the range of 0 to - 22. The default value is 0 and the source will use the default value - if `minimumZoomLevel` is nil. - */ -@property (nonatomic, nullable) NSNumber *minimumZoomLevel; - -/** - An `NSNumber` object containing an integer; specifies the maximum zoom level at - which to display tiles. The value should be in the range of 0 to 22 and greater - than `minimumZoomLevel`. The default value is 22 and the source will use the - default value if `maximumZoomLevel` is nil. - */ -@property (nonatomic, nullable) NSNumber *maximumZoomLevel; - -/** - An `NSString` object that contains an attribution to be displayed when the map - is shown to a user. The default value is `nil`. - */ -@property (nonatomic, copy, nullable) NSString *attribution; - -/** - An `MGLTileSetScheme` value that contains an enumeration (either - `MGLTileSetSchemeXYZ` or `MGLTileSetSchemeTMS`) that influences the y direction - of the tile coordinates. The default is `MGLTileSetSchemeXYZ`. - */ -@property (nonatomic) MGLTileSetScheme scheme; - -/** - Initializes and returns a new tile set object. - - @param tileURLTemplates An `NSArray` of `NSString` objects that represent the - tile templates. - @return The initialized tile set object. - */ -- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates; - -/** - Initializes and returns a new tile set object. - - @param tileURLTemplates An `NSArray` of `NSString` objects that represent the - tile templates. - @param minimumZoomLevel An `NSUInteger`; specifies the minimum zoom level at - which to display tiles. - @param maximumZoomLevel An `NSUInteger`; specifies the maximum zoom level at - which to display tiles. - @return The initialized tile set object. - */ -- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates minimumZoomLevel:(NSUInteger)minimumZoomLevel maximumZoomLevel:(NSUInteger)maximumZoomLevel; - -@end - -NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLTileSet.mm b/platform/darwin/src/MGLTileSet.mm deleted file mode 100644 index f795545eed..0000000000 --- a/platform/darwin/src/MGLTileSet.mm +++ /dev/null @@ -1,93 +0,0 @@ -#import "MGLTileSet.h" - -#include <mbgl/util/tileset.hpp> - -@implementation MGLTileSet - -- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates -{ - if (self = [super init]) - { - _tileURLTemplates = tileURLTemplates; - } - return self; -} - -- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates minimumZoomLevel:(NSUInteger)minimumZoomLevel maximumZoomLevel:(NSUInteger)maximumZoomLevel -{ - if (minimumZoomLevel > maximumZoomLevel) - { - [[NSException exceptionWithName:@"Invalid minimumZoomLevel" - reason:@"minimumZoomLevel must be less than maximumZoomLevel" - userInfo:nil] raise]; - return nil; - } - - if (self = [super init]) - { - _tileURLTemplates = tileURLTemplates; - _minimumZoomLevel = @(minimumZoomLevel); - _maximumZoomLevel = @(maximumZoomLevel); - } - return self; -} - -- (void)setMinimumZoomLevel:(NSNumber *)minimumZoomLevel -{ - if (self.maximumZoomLevel && [minimumZoomLevel integerValue] > [self.maximumZoomLevel integerValue]) - { - [[NSException exceptionWithName:@"Invalid minimumZoomLevel" - reason:@"minimumZoomLevel must be less than maximumZoomLevel" - userInfo:nil] raise]; - return; - } - - _minimumZoomLevel = minimumZoomLevel; -} - -- (void)setMaximumZoomLevel:(NSNumber *)maximumZoomLevel -{ - if (self.maximumZoomLevel && [maximumZoomLevel integerValue] < [self.maximumZoomLevel integerValue]) - { - [[NSException exceptionWithName:@"Invalid minimumZoomLevel" - reason:@"minimumZoomLevel must be less than maximumZoomLevel" - userInfo:nil] raise]; - } - - _maximumZoomLevel = maximumZoomLevel; -} - -- (mbgl::Tileset)mbglTileset -{ - mbgl::Tileset tileset; - - for (NSString *tileURLTemplate in self.tileURLTemplates) - { - tileset.tiles.push_back(tileURLTemplate.UTF8String); - } - - // set the minimum / maximum zoom range to the values specified by this class if they - // were set. otherwise, use the core objects default values - uint8_t minimumZoomLevel = self.minimumZoomLevel ? [self.minimumZoomLevel unsignedIntegerValue] : tileset.zoomRange.min; - uint8_t maximumZoomLevel = self.minimumZoomLevel ? [self.maximumZoomLevel unsignedIntegerValue] : tileset.zoomRange.max; - tileset.zoomRange = mbgl::Range<uint8_t>(minimumZoomLevel, maximumZoomLevel); - - if (self.attribution) - { - tileset.attribution = self.attribution.UTF8String; - } - - if (self.scheme == MGLTileSetSchemeTMS) { - tileset.scheme = mbgl::Tileset::Scheme::TMS; - } - - return tileset; -} - -- (NSString *)description -{ - return [NSString stringWithFormat:@"<%@: %p; tileURLTemplates = %@>", - NSStringFromClass([self class]), (void *)self, self.tileURLTemplates]; -} - -@end diff --git a/platform/darwin/src/MGLTileSet_Private.h b/platform/darwin/src/MGLTileSet_Private.h deleted file mode 100644 index 6a14d428db..0000000000 --- a/platform/darwin/src/MGLTileSet_Private.h +++ /dev/null @@ -1,9 +0,0 @@ -#import "MGLTileSet.h" - -#include <mbgl/util/tileset.hpp> - -@interface MGLTileSet (Private) - -- (mbgl::Tileset)mbglTileset; - -@end
\ No newline at end of file diff --git a/platform/darwin/src/MGLTileSource.h b/platform/darwin/src/MGLTileSource.h new file mode 100644 index 0000000000..caf915637e --- /dev/null +++ b/platform/darwin/src/MGLTileSource.h @@ -0,0 +1,179 @@ +#import <Foundation/Foundation.h> + +#import "MGLSource.h" +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +@class MGLAttributionInfo; + +/** + Options for `MGLTileSource` objects. + */ +typedef NSString *MGLTileSourceOption NS_STRING_ENUM; + +/** + An `NSNumber` object containing an unsigned integer that specifies the minimum + zoom level at which to display tiles from the source. + + The value should be between 0 and 22, inclusive, and less than + `MGLTileSourceOptionMaximumZoomLevel`, if specified. The default value for this + option is 0. + */ +extern const MGLTileSourceOption MGLTileSourceOptionMinimumZoomLevel; + +/** + An `NSNumber` object containing an unsigned integer that specifies the maximum + zoom level at which to display tiles from the source. + + The value should be between 0 and 22, inclusive, and less than + `MGLTileSourceOptionMinimumZoomLevel`, if specified. The default value for this + option is 22. + */ +extern const MGLTileSourceOption MGLTileSourceOptionMaximumZoomLevel; + +#if TARGET_OS_IPHONE +/** + An HTML string defining the buttons to be displayed in an action sheet when the + source is part of a map view’s style and the map view’s attribution button is + pressed. + + By default, no attribution statements are displayed. If the + `MGLTileSourceOptionAttributionInfos` option is specified, this option is + ignored. + */ +extern const MGLTileSourceOption MGLTileSourceOptionAttributionHTMLString; + +/** + An array of `MGLAttributionInfo` objects defining the buttons to be displayed + in an action sheet when the source is part of a map view’s style and the map + view’s attribution button is pressed. + + By default, no attribution statements are displayed. + */ +extern const MGLTileSourceOption MGLTileSourceOptionAttributionInfos; +#else +/** + An HTML string defining the buttons to be displayed in the map view’s + attribution view when the source is part of the map view’s style. + + By default, no attribution statements are displayed. If the + `MGLTileSourceOptionAttributionInfos` option is specified, this option is + ignored. + */ +extern const MGLTileSourceOption MGLTileSourceOptionAttributionHTMLString; + +/** + An array of `MGLAttributionInfo` objects defining the buttons to be displayed + in the map view’s attribution view when the source is part of the map view’s + style. + + By default, no attribution statements are displayed. + */ +extern const MGLTileSourceOption MGLTileSourceOptionAttributionInfos; +#endif + +/** + An `NSNumber` object containing an unsigned integer that specifies the tile + coordinate system for the source’s tile URLs. The integer corresponds to one of + the constants described in `MGLTileCoordinateSystem`. + + The default value for this option is `MGLTileCoordinateSystemXYZ`. + */ +extern const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem; + +/** + Tile coordinate systems that determine how tile coordinates in tile URLs are + interpreted. + */ +typedef NS_ENUM(NSUInteger, MGLTileCoordinateSystem) { + /** + The origin is at the top-left (northwest), and `y` values increase + southwards. + + This tile coordinate system is used by Mapbox and OpenStreetMap tile + servers. + */ + MGLTileCoordinateSystemXYZ = 0, + + /** + The origin is at the bottom-left (southwest), and `y` values increase + northwards. + + This tile coordinate system is used by tile servers that conform to the + <a href="http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification">Tile Map Service Specification</a>. + */ + MGLTileCoordinateSystemTMS +}; + +/** + `MGLTileSource` is a map content source that supplies map tiles to be shown on + the map. The location of and metadata about the tiles are defined either by an + option dictionary or by an external file that conforms to the + <a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>. + A tile source is added to an `MGLStyle` object along with one or more + `MGLRasterStyleLayer` or `MGLVectorStyleLayer` objects. Use a style layer to + control the appearance of content supplied by the tile source. + + Do not create instances of this class directly, and do not create your own + subclasses of this class. Instead, create instances of `MGLRasterSource` and + `MGLVectorSource`. + */ +@interface MGLTileSource : MGLSource + +#pragma mark Initializing a Source + +- (instancetype)init __attribute__((unavailable("Use -initWithIdentifier:configurationURL: or -initWithIdentifier:tileURLTemplates:options: instead."))); +- (instancetype)initWithIdentifier:(NSString *)identifier __attribute__((unavailable("Use -initWithIdentifier:configurationURL: or -initWithIdentifier:tileURLTemplates:options: instead."))); + +/** + Returns a tile source initialized with an identifier and configuration URL. + + After initializing and configuring the source, add it to a map view’s style + using the `-[MGLStyle addSource:]` method. + + The URL may be a full HTTP or HTTPS URL or, for tile sets hosted by Mapbox, a + Mapbox URL indicating a map identifier (`mapbox://<mapid>`). The URL should + point to a JSON file that conforms to the + <a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>. + + @param identifier A string that uniquely identifies the source in the style to + which it is added. + @param configurationURL A URL to a TileJSON configuration file describing the + source’s contents and other metadata. + @return An initialized tile source. + */ +- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL; + +/** + Returns a tile source initialized an identifier, tile URL templates, and + options. + + After initializing and configuring the source, add it to a map view’s style + using the `-[MGLStyle addSource:]` method. + + @param identifier A string that uniquely identifies the source in the style to + which it is added. + @param tileURLTemplates An array of tile URL template strings. + @param options A dictionary containing configuration options. See + `MGLTileSourceOption` for available keys and values. Pass in `nil` to use + the default values. + @return An initialized tile source. + */ +- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options; + +#pragma mark Accessing Attribution Strings + +/** + An array of `MGLAttributionInfo` objects that define the attribution + statements to be displayed when the map is shown to the user. + + By default, this array is empty. If the source is initialized with a + configuration URL, this array is also empty until the configuration JSON file + is loaded. + */ +@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLAttributionInfo *) *attributionInfos; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLTileSource.mm b/platform/darwin/src/MGLTileSource.mm new file mode 100644 index 0000000000..522675bc88 --- /dev/null +++ b/platform/darwin/src/MGLTileSource.mm @@ -0,0 +1,123 @@ +#import "MGLTileSource_Private.h" + +#import "MGLAttributionInfo_Private.h" +#import "NSString+MGLAdditions.h" + +#if TARGET_OS_IPHONE + #import <UIKit/UIKit.h> +#else + #import <Cocoa/Cocoa.h> +#endif + +#include <mbgl/util/tileset.hpp> + +const MGLTileSourceOption MGLTileSourceOptionMinimumZoomLevel = @"MGLTileSourceOptionMinimumZoomLevel"; +const MGLTileSourceOption MGLTileSourceOptionMaximumZoomLevel = @"MGLTileSourceOptionMaximumZoomLevel"; +const MGLTileSourceOption MGLTileSourceOptionAttributionHTMLString = @"MGLTileSourceOptionAttributionHTMLString"; +const MGLTileSourceOption MGLTileSourceOptionAttributionInfos = @"MGLTileSourceOptionAttributionInfos"; +const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem = @"MGLTileSourceOptionTileCoordinateSystem"; + +@implementation MGLTileSource + +- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL { + return [super initWithIdentifier:identifier]; +} + +- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options { + return [super initWithIdentifier:identifier]; +} + +- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos { + return [self attributionInfosWithFontSize:0 linkColor:nil]; +} + +- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor { + return [MGLAttributionInfo attributionInfosFromHTMLString:self.attributionHTMLString + fontSize:fontSize + linkColor:linkColor]; +} + +- (NSString *)attributionHTMLString { + [NSException raise:@"MGLAbstractClassException" + format:@"MGLTileSource is an abstract class"]; + return nil; +} + +@end + +mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTemplates, NS_DICTIONARY_OF(MGLTileSourceOption, id) * _Nullable options) { + mbgl::Tileset tileSet; + + for (NSString *tileURLTemplate in tileURLTemplates) { + tileSet.tiles.push_back(tileURLTemplate.UTF8String); + } + + // set the minimum / maximum zoom range to the values specified by this class if they + // were set. otherwise, use the core objects default values + if (NSNumber *minimumZoomLevel = options[MGLTileSourceOptionMinimumZoomLevel]) { + if (![minimumZoomLevel isKindOfClass:[NSNumber class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLTileSourceOptionMinimumZoomLevel must be set to an NSNumber."]; + } + tileSet.zoomRange.min = minimumZoomLevel.integerValue; + } + if (NSNumber *maximumZoomLevel = options[MGLTileSourceOptionMaximumZoomLevel]) { + if (![maximumZoomLevel isKindOfClass:[NSNumber class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLTileSourceOptionMinimumZoomLevel must be set to an NSNumber."]; + } + tileSet.zoomRange.max = maximumZoomLevel.integerValue; + } + if (tileSet.zoomRange.min > tileSet.zoomRange.max) { + [NSException raise:NSInvalidArgumentException + format:@"MGLTileSourceOptionMinimumZoomLevel must be less than MGLTileSourceOptionMaximumZoomLevel."]; + } + + if (NSString *attribution = options[MGLTileSourceOptionAttributionHTMLString]) { + if (![attribution isKindOfClass:[NSString class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLTileSourceOptionAttributionHTMLString must be set to a string."]; + } + tileSet.attribution = attribution.UTF8String; + } + + if (NSArray *attributionInfos = options[MGLTileSourceOptionAttributionInfos]) { + if (![attributionInfos isKindOfClass:[NSArray class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLTileSourceOptionAttributionInfos must be set to a string."]; + } + + NSAttributedString *attributedString = [MGLAttributionInfo attributedStringForAttributionInfos:attributionInfos]; +#if TARGET_OS_IPHONE + static NSString * const NSExcludedElementsDocumentAttribute = @"ExcludedElements"; +#endif + NSDictionary *documentAttributes = @{ + NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, + NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding), + // The attribution string is meant to be a simple, inline fragment, not a full-fledged, validating document. + NSExcludedElementsDocumentAttribute: @[@"XML", @"DOCTYPE", @"html", @"head", @"meta", @"title", @"style", @"body", @"p"], + }; + NSData *data = [attributedString dataFromRange:attributedString.mgl_wholeRange documentAttributes:documentAttributes error:NULL]; + NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + tileSet.attribution = html.UTF8String; + } + + if (NSNumber *tileCoordinateSystemNumber = options[MGLTileSourceOptionTileCoordinateSystem]) { + if (![tileCoordinateSystemNumber isKindOfClass:[NSValue class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLTileSourceOptionTileCoordinateSystem must be set to an NSValue or NSNumber."]; + } + MGLTileCoordinateSystem tileCoordinateSystem; + [tileCoordinateSystemNumber getValue:&tileCoordinateSystem]; + switch (tileCoordinateSystem) { + case MGLTileCoordinateSystemXYZ: + tileSet.scheme = mbgl::Tileset::Scheme::XYZ; + break; + case MGLTileCoordinateSystemTMS: + tileSet.scheme = mbgl::Tileset::Scheme::TMS; + break; + } + } + + return tileSet; +} diff --git a/platform/darwin/src/MGLTileSource_Private.h b/platform/darwin/src/MGLTileSource_Private.h new file mode 100644 index 0000000000..ca80e3d960 --- /dev/null +++ b/platform/darwin/src/MGLTileSource_Private.h @@ -0,0 +1,36 @@ +#import "MGLTileSource.h" + +#import <CoreGraphics/CoreGraphics.h> + +NS_ASSUME_NONNULL_BEGIN + +namespace mbgl { + class Tileset; +} + +@class MGLAttributionInfo; + +@interface MGLTileSource (Private) + +/** + An HTML string to be displayed as attribution when the map is shown to a user. + + The default value is `nil`. If the source is initialized with a configuration + URL, this property is also `nil` until the configuration JSON file is loaded. + */ +@property (nonatomic, copy, nullable, readonly) NSString *attributionHTMLString; + +/** + A structured representation of the `attribution` property. The default value is + `nil`. + + @param fontSize The default text size in points, or 0 to use the default. + @param linkColor The default link color, or `nil` to use the default. + */ +- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor; + +@end + +mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTemplates, NS_DICTIONARY_OF(MGLTileSourceOption, id) * _Nullable options); + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLVectorSource.h b/platform/darwin/src/MGLVectorSource.h index 6cfab09489..f91a0cbb23 100644 --- a/platform/darwin/src/MGLVectorSource.h +++ b/platform/darwin/src/MGLVectorSource.h @@ -1,68 +1,35 @@ -#import "MGLSource.h" -#import "MGLTypes.h" - -@class MGLTileSet; +#import "MGLTileSource.h" NS_ASSUME_NONNULL_BEGIN /** - A vector tile source. Tiles must be in Mapbox Vector Tile format. - - @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-vector">The - style specification.</a> - */ -@interface MGLVectorSource : MGLSource - -#pragma mark Initializing a Source - -/** - Returns a vector source initialized with an identifier and TileJSON URL. + `MGLVectorSource` is a map content source that supplies tiled vector data in + <a href="https://www.mapbox.com/vector-tiles/">Mapbox Vector Tile</a> format to + be shown on the map. The location of and metadata about the tiles are defined + either by an option dictionary or by an external file that conforms to the + <a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>. + A vector source is added to an `MGLStyle` object along with one or more + `MGLVectorStyleLayer` objects. A vector style layer defines the appearance of + any content supplied by the vector source. - After initializing and configuring the source, add it to a map view’s style - using the `-[MGLStyle addSource:]` method. + Each + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-vector"><code>vector</code></a> + source defined by the style JSON file is represented at runtime by an + `MGLVectorSource` object that you can use to initialize new style layers. You + can also add and remove sources dynamically using methods such as + `-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`. - @param identifier A string that uniquely identifies the source in the style to - which it is added. - @param url A URL to a TileJSON configuration file describing the source’s - contents and other metadata. - @return An initialized vector source. + Within each vector tile, each geometric coordinate must lie between + −1 × <var>extent</var> and + (<var>extent</var> × 2) − 1, inclusive. Any vector style + layer initialized with a vector source must have a non-`nil` value in its + `sourceLayerIdentifier` property. */ -- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url NS_DESIGNATED_INITIALIZER; - -/** - Returns a vector source initialized an identifier and tile set. +@interface MGLVectorSource : MGLTileSource - After initializing and configuring the source, add it to a map view’s style - using the `-[MGLStyle addSource:]` method. - - @param identifier A string that uniquely identifies the source in the style to - which it is added. - @param tileSet A tile set describing the source’s contents and other metadata. - @return An initialized vector source. - */ -- (instancetype)initWithIdentifier:(NSString *)identifier tileSet:(MGLTileSet *)tileSet NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL NS_DESIGNATED_INITIALIZER; -#pragma mark Accessing a Source’s Content - -/** - A URL to a TileJSON configuration file describing the source’s contents and - other metadata. - - The URL may be a full HTTP or HTTPS URL or a Mapbox URL indicating the tile - set’s map ID (`mapbox://<mapid>`). - - If the receiver was initialized using `-initWithIdentifier:tileSet:`, this - property is set to `nil`. - */ -@property (nonatomic, readonly, copy) NSURL *URL; - -/** - A tile set describing the source’s contents and other metadata. - - If the receiver was initialized using `-initWithIdentifier:URL:`, this property - is set to `nil`. - */ -@property (nonatomic, readonly, nullable) MGLTileSet *tileSet; +- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options NS_DESIGNATED_INITIALIZER; @end diff --git a/platform/darwin/src/MGLVectorSource.mm b/platform/darwin/src/MGLVectorSource.mm index ab68d45ba1..0eea8dd18c 100644 --- a/platform/darwin/src/MGLVectorSource.mm +++ b/platform/darwin/src/MGLVectorSource.mm @@ -1,64 +1,50 @@ -#import "MGLVectorSource.h" +#import "MGLVectorSource_Private.h" #import "MGLMapView_Private.h" #import "MGLSource_Private.h" -#import "MGLTileSet_Private.h" +#import "MGLTileSource_Private.h" #import "NSURL+MGLAdditions.h" #include <mbgl/style/sources/vector_source.hpp> @interface MGLVectorSource () +- (instancetype)initWithRawSource:(mbgl::style::VectorSource *)rawSource NS_DESIGNATED_INITIALIZER; + @property (nonatomic) mbgl::style::VectorSource *rawSource; @end -@implementation MGLVectorSource -{ +@implementation MGLVectorSource { std::unique_ptr<mbgl::style::VectorSource> _pendingSource; } -- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url -{ - if (self = [super initWithIdentifier:identifier]) - { - _URL = url; - [self commonInit]; +- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL { + if (self = [super initWithIdentifier:identifier configurationURL:configurationURL]) { + auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String, + configurationURL.mgl_URLByStandardizingScheme.absoluteString.UTF8String); + _pendingSource = std::move(source); + self.rawSource = _pendingSource.get(); } return self; } -- (instancetype)initWithIdentifier:(NSString *)identifier tileSet:(MGLTileSet *)tileSet -{ - if (self = [super initWithIdentifier:identifier]) - { - _tileSet = tileSet; - [self commonInit]; +- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options { + if (self = [super initWithIdentifier:identifier tileURLTemplates:tileURLTemplates options:options]) { + mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options); + + auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String, tileSet); + _pendingSource = std::move(source); + self.rawSource = _pendingSource.get(); } return self; } -- (void)commonInit -{ - std::unique_ptr<mbgl::style::VectorSource> source; - - if (self.URL) - { - source = std::make_unique<mbgl::style::VectorSource>(self.identifier.UTF8String, - self.URL.mgl_URLByStandardizingScheme.absoluteString.UTF8String); - } - else - { - source = std::make_unique<mbgl::style::VectorSource>(self.identifier.UTF8String, - self.tileSet.mbglTileset); - } - - _pendingSource = std::move(source); - self.rawSource = _pendingSource.get(); +- (instancetype)initWithRawSource:(mbgl::style::VectorSource *)rawSource { + return [super initWithRawSource:rawSource]; } -- (void)addToMapView:(MGLMapView *)mapView -{ +- (void)addToMapView:(MGLMapView *)mapView { if (_pendingSource == nullptr) { [NSException raise:@"MGLRedundantSourceException" format:@"This instance %@ was already added to %@. Adding the same source instance " \ @@ -68,18 +54,24 @@ mapView.mbglMap->addSource(std::move(_pendingSource)); } -- (void)removeFromMapView:(MGLMapView *)mapView -{ +- (void)removeFromMapView:(MGLMapView *)mapView { auto removedSource = mapView.mbglMap->removeSource(self.identifier.UTF8String); _pendingSource = std::move(reinterpret_cast<std::unique_ptr<mbgl::style::VectorSource> &>(removedSource)); self.rawSource = _pendingSource.get(); } -- (NSString *)description -{ - return [NSString stringWithFormat:@"<%@: %p; identifier = %@; URL = %@; tileSet = %@>", - NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, self.tileSet]; +- (mbgl::style::VectorSource *)rawSource { + return (mbgl::style::VectorSource *)super.rawSource; +} + +- (void)setRawSource:(mbgl::style::VectorSource *)rawSource { + super.rawSource = rawSource; +} + +- (NSString *)attributionHTMLString { + auto attribution = self.rawSource->getAttribution(); + return attribution ? @(attribution->c_str()) : nil; } @end diff --git a/platform/darwin/src/MGLVectorSource_Private.h b/platform/darwin/src/MGLVectorSource_Private.h new file mode 100644 index 0000000000..12fcd82012 --- /dev/null +++ b/platform/darwin/src/MGLVectorSource_Private.h @@ -0,0 +1,17 @@ +#import "MGLVectorSource.h" + +NS_ASSUME_NONNULL_BEGIN + +namespace mbgl { + namespace style { + class VectorSource; + } +} + +@interface MGLVectorSource (Private) + +- (instancetype)initWithRawSource:(mbgl::style::VectorSource *)rawSource; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLVectorStyleLayer.h b/platform/darwin/src/MGLVectorStyleLayer.h index e2a755083f..1197d76807 100644 --- a/platform/darwin/src/MGLVectorStyleLayer.h +++ b/platform/darwin/src/MGLVectorStyleLayer.h @@ -6,7 +6,7 @@ NS_ASSUME_NONNULL_BEGIN /** `MGLVectorStyleLayer` is an abstract superclass for style layers whose content - is defined by an `MGLGeoJSONSource` or `MGLVectorSource` object. + is defined by an `MGLShapeSource` or `MGLVectorSource` object. Do not create instances of this class directly, and do not create your own subclasses of this class. Instead, create instances of the following concrete @@ -122,6 +122,12 @@ NS_ASSUME_NONNULL_BEGIN value specified in the predicate. Also, operator modifiers `c`, `d`, and the combined `cd` for case and diacritic insensitivity are unsupported for comparison and aggregate operators that are used in the predicate. + + It is possible to create expressions that contain special characters in the + predicate format syntax. This includes the `$` in the `$id` and `$type` special + style attributes and also `hyphen-minus` and `tag:subtag`. However, you must use + `%K` in the format string to represent these variables: + `@"%K == 'LineString'", @"$type"`. */ @property (nonatomic, nullable) NSPredicate *predicate; diff --git a/platform/darwin/src/NSArray+MGLAdditions.h b/platform/darwin/src/NSArray+MGLAdditions.h index 6871f15486..eb1cfb7c47 100644 --- a/platform/darwin/src/NSArray+MGLAdditions.h +++ b/platform/darwin/src/NSArray+MGLAdditions.h @@ -6,4 +6,7 @@ - (std::vector<mbgl::Value>)mgl_vector; +/** Returns a string resulting from inserting a separator between each attributed string in the array */ +- (NSAttributedString *)mgl_attributedComponentsJoinedByString:(NSString *)separator; + @end diff --git a/platform/darwin/src/NSArray+MGLAdditions.mm b/platform/darwin/src/NSArray+MGLAdditions.mm index 976eda704f..b2799c46e1 100644 --- a/platform/darwin/src/NSArray+MGLAdditions.mm +++ b/platform/darwin/src/NSArray+MGLAdditions.mm @@ -23,4 +23,19 @@ return vector; } +- (NSAttributedString *)mgl_attributedComponentsJoinedByString:(NSString *)separator { + NSAttributedString *attributedSeparator = [[NSAttributedString alloc] initWithString:separator]; + NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init]; + BOOL isSubsequentItem = NO; + for (NSAttributedString *component in self) { + NSAssert([component isKindOfClass:[NSAttributedString class]], @"Items in array must be attributed strings."); + if (isSubsequentItem) { + [attributedString appendAttributedString:attributedSeparator]; + } + isSubsequentItem = YES; + [attributedString appendAttributedString:component]; + } + return attributedString; +} + @end diff --git a/platform/darwin/src/NSString+MGLAdditions.h b/platform/darwin/src/NSString+MGLAdditions.h index 5b549affd5..45fea25588 100644 --- a/platform/darwin/src/NSString+MGLAdditions.h +++ b/platform/darwin/src/NSString+MGLAdditions.h @@ -4,9 +4,22 @@ NS_ASSUME_NONNULL_BEGIN @interface NSString (MGLAdditions) +/** Returns the range spanning the entire receiver. */ +- (NSRange)mgl_wholeRange; + /** Returns the receiver if non-empty or nil if empty. */ - (nullable NSString *)mgl_stringOrNilIfEmpty; @end +@interface NSAttributedString (MGLAdditions) + +/** Returns the range spanning the entire receiver. */ +- (NSRange)mgl_wholeRange; + +/** Returns a copy of the receiver with leading and trailing members of the given set removed. */ +- (NSAttributedString *)mgl_attributedStringByTrimmingCharactersInSet:(NSCharacterSet *)set; + +@end + NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/NSString+MGLAdditions.m b/platform/darwin/src/NSString+MGLAdditions.m index 969886651b..04a65dc5e2 100644 --- a/platform/darwin/src/NSString+MGLAdditions.m +++ b/platform/darwin/src/NSString+MGLAdditions.m @@ -2,9 +2,30 @@ @implementation NSString (MGLAdditions) -- (nullable NSString *)mgl_stringOrNilIfEmpty -{ +- (NSRange)mgl_wholeRange { + return NSMakeRange(0, self.length); +} + +- (nullable NSString *)mgl_stringOrNilIfEmpty { return self.length ? self : nil; } @end + +@implementation NSAttributedString (MGLAdditions) + +- (NSRange)mgl_wholeRange { + return NSMakeRange(0, self.length); +} + +- (NSAttributedString *)mgl_attributedStringByTrimmingCharactersInSet:(NSCharacterSet *)set { + NSScanner *scanner = [NSScanner scannerWithString:self.string]; + scanner.charactersToBeSkipped = nil; + NSString *prefix; + [scanner scanCharactersFromSet:set intoString:&prefix]; + + NSString *trimmedString = [self.string stringByTrimmingCharactersInSet:set]; + return [self attributedSubstringFromRange:NSMakeRange(prefix.length, trimmedString.length)]; +} + +@end diff --git a/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h b/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h index 8aa07b2a0c..3387ce8188 100644 --- a/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h +++ b/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.h @@ -98,17 +98,17 @@ NS_ASSUME_NONNULL_BEGIN @property (readonly) MGLTextAnchor MGLTextAnchorValue; /** - Creates a new value object containing the given `MGLTextJustify` enumeration. + Creates a new value object containing the given `MGLTextJustification` enumeration. @param type The value for the new object. @return A new value object that contains the style enumeration type. */ -+ (instancetype)valueWithMGLTextJustify:(MGLTextJustify)textJustify; ++ (instancetype)valueWithMGLTextJustification:(MGLTextJustification)textJustification; /** - The `MGLTextJustify` enumeration representation of the value. + The `MGLTextJustification` enumeration representation of the value. */ -@property (readonly) MGLTextJustify MGLTextJustifyValue; +@property (readonly) MGLTextJustification MGLTextJustificationValue; /** Creates a new value object containing the given `MGLTextPitchAlignment` enumeration. diff --git a/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm b/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm index 89f0c07a5a..db91408c5a 100644 --- a/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm +++ b/platform/darwin/src/NSValue+MGLStyleEnumAttributeAdditions.mm @@ -65,12 +65,12 @@ return value; } -+ (NSValue *)valueWithMGLTextJustify:(MGLTextJustify)textJustify { - return [NSValue value:&textJustify withObjCType:@encode(MGLTextJustify)]; ++ (NSValue *)valueWithMGLTextJustification:(MGLTextJustification)textJustification { + return [NSValue value:&textJustification withObjCType:@encode(MGLTextJustification)]; } -- (MGLTextJustify)MGLTextJustifyValue { - MGLTextJustify value; +- (MGLTextJustification)MGLTextJustificationValue { + MGLTextJustification value; [self getValue:&value]; return value; } |