summaryrefslogtreecommitdiff
path: root/platform/darwin
diff options
context:
space:
mode:
Diffstat (limited to 'platform/darwin')
-rw-r--r--platform/darwin/docs/guides/Tile URL Templates.md.ejs109
-rw-r--r--platform/darwin/scripts/generate-style-code.js13
-rw-r--r--platform/darwin/src/MGLAttributionInfo.mm31
-rw-r--r--platform/darwin/src/MGLAttributionInfo_Private.h18
-rw-r--r--platform/darwin/src/MGLFillExtrusionStyleLayer.h2
-rw-r--r--platform/darwin/src/MGLGeometry_Private.h64
-rw-r--r--platform/darwin/src/MGLLight.h125
-rw-r--r--platform/darwin/src/MGLLight.mm113
-rw-r--r--platform/darwin/src/MGLLight_Private.h23
-rw-r--r--platform/darwin/src/MGLOfflineStorage.mm14
-rw-r--r--platform/darwin/src/MGLPolygon.mm20
-rw-r--r--platform/darwin/src/MGLPolyline.mm65
-rw-r--r--platform/darwin/src/MGLRasterSource.h91
-rw-r--r--platform/darwin/src/MGLStyle.h9
-rw-r--r--platform/darwin/src/MGLStyle.mm17
-rw-r--r--platform/darwin/src/MGLStyleValue.h6
-rw-r--r--platform/darwin/src/MGLStyleValue.mm6
-rw-r--r--platform/darwin/src/MGLStyleValue_Private.h14
-rw-r--r--platform/darwin/src/MGLTypes.h1
-rw-r--r--platform/darwin/src/MGLVectorSource.h91
-rw-r--r--platform/darwin/src/NSBundle+MGLAdditions.h4
-rw-r--r--platform/darwin/src/NSBundle+MGLAdditions.m33
-rw-r--r--platform/darwin/src/NSValue+MGLAdditions.h29
-rw-r--r--platform/darwin/src/NSValue+MGLAdditions.m23
-rw-r--r--platform/darwin/src/NSValue+MGLStyleAttributeAdditions.h1
-rw-r--r--platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm15
-rw-r--r--platform/darwin/test/MGLAttributionInfoTests.m12
-rw-r--r--platform/darwin/test/MGLCodingTests.m119
-rw-r--r--platform/darwin/test/MGLDocumentationExampleTests.swift2
-rw-r--r--platform/darwin/test/MGLLightTest.mm217
30 files changed, 1064 insertions, 223 deletions
diff --git a/platform/darwin/docs/guides/Tile URL Templates.md.ejs b/platform/darwin/docs/guides/Tile URL Templates.md.ejs
new file mode 100644
index 0000000000..78fb297138
--- /dev/null
+++ b/platform/darwin/docs/guides/Tile URL Templates.md.ejs
@@ -0,0 +1,109 @@
+<%
+ const os = locals.os;
+ const iOS = os === 'iOS';
+ //const macOS = os === 'macOS';
+ //const cocoaPrefix = iOS ? 'UI' : 'NS';
+-%>
+<!--
+ This file is generated.
+ Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
+-->
+# Tile URL Templates
+
+`MGLTileSource` objects, specifically `MGLRasterSource` and `MGLVectorSource`
+objects, can be created using an initializer that accepts an array of tile URL
+templates. Tile URL templates are strings that specify the URLs of the vector
+tiles or raster tile images to load. A template resembles an absolute URL, but
+with any number of placeholder strings that the source evaluates based on the
+tile it needs to load. For example:
+
+* `http://www.example.com/tiles/{z}/{x}/{y}.pbf` could be
+ evaluated as `http://www.example.com/tiles/14/6/9.pbf`.
+* `http://www.example.com/tiles/{z}/{x}/{y}{ratio}.png` could be
+ evaluated as `http://www.example.com/tiles/14/6/9@2x.png`.
+
+Tile URL templates are also used to define tilesets in TileJSON manifests or
+[`raster`](https://www.mapbox.com/mapbox-gl-js/style-spec/#sources-raster-tiles)
+and
+[`vector`](https://www.mapbox.com/mapbox-gl-js/style-spec/#sources-vector-tiles)
+sources in style JSON files. See the
+[TileJSON specification](https://github.com/mapbox/tilejson-spec/tree/master/2.2.0)
+for information about tile URL templates in the context of a TileJSON or style
+JSON file.
+
+Tile sources support the following placeholder strings in tile URL templates,
+all of which are optional:
+
+<table>
+<thead>
+<tr><th>Placeholder string</th><th>Description</th></tr>
+</thead>
+<tbody>
+<tr>
+ <td><code>{x}</code></td>
+ <td>The index of the tile along the map’s x axis according to Spherical
+ Mercator projection. If the value is 0, the tile’s left edge corresponds
+ to the 180th meridian west. If the value is 2<sup><var>z</var></sup>−1,
+ the tile’s right edge corresponds to the 180th meridian east.</td>
+</tr>
+<tr>
+ <td><code>{y}</code></td>
+ <td>The index of the tile along the map’s y axis according to Spherical
+ Mercator projection. If the value is 0, the tile’s tile edge corresponds
+ to arctan(sinh(π)), or approximately 85.0511 degrees north. If the value
+ is 2<sup><var>z</var></sup>−1, the tile’s bottom edge corresponds to
+ −arctan(sinh(π)), or approximately 85.0511 degrees south. The y axis is
+ inverted if the <code>options</code> parameter contains
+ <code>MGLTileSourceOptionTileCoordinateSystem</code> with a value of
+ <code>MGLTileCoordinateSystemTMS</code>.</td>
+</tr>
+<tr>
+ <td><code>{z}</code></td>
+ <td>The tile’s zoom level. At zoom level 0, each tile covers the entire
+ world map; at zoom level 1, it covers ¼ of the world; at zoom level 2,
+ <sup>1</sup>⁄<sub>16</sub> of the world, and so on. For tiles loaded by
+ a <code>MGLRasterSource</code> object, whether the tile zoom level
+ matches the map’s current zoom level depends on the value of the
+ source’s tile size as specified in the
+ <code>MGLTileSourceOptionTileSize</code> key of the <code>options</code>
+ parameter.</td>
+</tr>
+<tr>
+ <td><code>{bbox-epsg-3857}</code></td>
+ <td>The tile’s bounding box, expressed as a comma-separated list of the
+ tile’s western, southern, eastern, and northern extents according to
+ Spherical Mercator (EPSG:3857) projection. The bounding box is typically
+ used with map services conforming to the
+ <a href="http://www.opengeospatial.org/standards/wms">Web Map Service</a>
+ protocol.</td>
+</tr>
+<tr>
+ <td><code>{quadkey}</code></td>
+ <td>A quadkey indicating both the tile’s location and its zoom level. The
+ quadkey is typically used with
+ <a href="https://msdn.microsoft.com/en-us/library/bb259689.aspx">Bing Maps</a>.
+ </td>
+</tr>
+<tr>
+ <td><code>{ratio}</code></td>
+ <td>A suffix indicating the resolution of the tile image. The suffix is the
+ empty string for standard resolution displays and <code>@2x</code> for
+<% if (iOS) { -%>
+ Retina displays, including displays for which <code>UIScreen.scale</code>
+ is 3.
+<% } else { -%>
+ Retina displays.
+<% } -%>
+ </td>
+</tr>
+<tr>
+ <td><code>{prefix}</code></td>
+ <td>Two hexadecimal digits chosen such that each visible tile has a
+ different prefix. The prefix is typically used for domain sharding.</td>
+</tr>
+</tbody>
+</table>
+
+For more information about the `{x}`, `{y}`, and `{z}` placeholder strings,
+consult the
+[OpenStreetMap Wiki](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames).
diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js
index 330a8f1d03..7efc8d441c 100644
--- a/platform/darwin/scripts/generate-style-code.js
+++ b/platform/darwin/scripts/generate-style-code.js
@@ -522,8 +522,9 @@ global.setSourceLayer = function() {
const layerH = ejs.compile(fs.readFileSync('platform/darwin/src/MGLStyleLayer.h.ejs', 'utf8'), { strict: true });
const layerM = ejs.compile(fs.readFileSync('platform/darwin/src/MGLStyleLayer.mm.ejs', 'utf8'), { strict: true});
const testLayers = ejs.compile(fs.readFileSync('platform/darwin/test/MGLStyleLayerTests.mm.ejs', 'utf8'), { strict: true});
-const guideMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/For Style Authors.md.ejs', 'utf8'), { strict: true });
+const forStyleAuthorsMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/For Style Authors.md.ejs', 'utf8'), { strict: true });
const ddsGuideMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs', 'utf8'), { strict: true });
+const templatesMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/Tile URL Templates.md.ejs', 'utf8'), { strict: true });
const layers = _(spec.layer.type.values).map((value, layerType) => {
const layoutProperties = Object.keys(spec[`layout_${layerType}`]).reduce((memo, name) => {
@@ -635,12 +636,12 @@ global.guideExample = function (guide, exampleId, os) {
return '```swift\n' + example + '\n```';
};
-fs.writeFileSync(`platform/ios/docs/guides/For Style Authors.md`, guideMD({
+fs.writeFileSync(`platform/ios/docs/guides/For Style Authors.md`, forStyleAuthorsMD({
os: 'iOS',
renamedProperties: renamedPropertiesByLayerType,
layers: layers,
}));
-fs.writeFileSync(`platform/macos/docs/guides/For Style Authors.md`, guideMD({
+fs.writeFileSync(`platform/macos/docs/guides/For Style Authors.md`, forStyleAuthorsMD({
os: 'macOS',
renamedProperties: renamedPropertiesByLayerType,
layers: layers,
@@ -651,3 +652,9 @@ fs.writeFileSync(`platform/ios/docs/guides/Using Style Functions at Runtime.md`,
fs.writeFileSync(`platform/macos/docs/guides/Using Style Functions at Runtime.md`, ddsGuideMD({
os: 'macOS',
}));
+fs.writeFileSync(`platform/ios/docs/guides/Tile URL Templates.md`, templatesMD({
+ os: 'iOS',
+}));
+fs.writeFileSync(`platform/macos/docs/guides/Tile URL Templates.md`, templatesMD({
+ os: 'macOS',
+}));
diff --git a/platform/darwin/src/MGLAttributionInfo.mm b/platform/darwin/src/MGLAttributionInfo.mm
index 7583244491..770aeb25e7 100644
--- a/platform/darwin/src/MGLAttributionInfo.mm
+++ b/platform/darwin/src/MGLAttributionInfo.mm
@@ -6,8 +6,10 @@
#import <Cocoa/Cocoa.h>
#endif
+#import "MGLAccountManager.h"
#import "MGLMapCamera.h"
#import "NSArray+MGLAdditions.h"
+#import "NSBundle+MGLAdditions.h"
#import "NSString+MGLAdditions.h"
#include <string>
@@ -126,13 +128,34 @@
}
- (nullable NSURL *)feedbackURLAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel {
+ return [self feedbackURLForStyleURL:nil atCenterCoordinate:centerCoordinate zoomLevel:zoomLevel direction:0 pitch:0];
+}
+
+- (nullable NSURL *)feedbackURLForStyleURL:(nullable NSURL *)styleURL atCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction pitch:(CGFloat)pitch {
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)];
+
+ NSURLComponents *components = [NSURLComponents componentsWithString:@"https://www.mapbox.com/feedback/"];
+ components.fragment = [NSString stringWithFormat:@"/%.5f/%.5f/%.2f/%.1f/%i",
+ centerCoordinate.longitude, centerCoordinate.latitude, zoomLevel,
+ direction, (int)round(pitch)];
+
+ NSURLQueryItem *referrerQueryItem = [NSURLQueryItem queryItemWithName:@"referrer"
+ value:[NSBundle mgl_applicationBundleIdentifier]];
+ NSMutableArray<NSURLQueryItem *> *queryItems = [NSMutableArray arrayWithObject:referrerQueryItem];
+ if ([styleURL.scheme isEqualToString:@"mapbox"] && [styleURL.host isEqualToString:@"styles"]) {
+ NSArray<NSString *> *stylePathComponents = styleURL.pathComponents;
+ if (stylePathComponents.count >= 3) {
+ [queryItems addObjectsFromArray:@[
+ [NSURLQueryItem queryItemWithName:@"owner" value:stylePathComponents[1]],
+ [NSURLQueryItem queryItemWithName:@"id" value:stylePathComponents[2]],
+ [NSURLQueryItem queryItemWithName:@"access_token" value:[MGLAccountManager accessToken]],
+ ]];
+ }
+ }
+ components.queryItems = queryItems;
+
return components.URL;
}
diff --git a/platform/darwin/src/MGLAttributionInfo_Private.h b/platform/darwin/src/MGLAttributionInfo_Private.h
index 08bc6bfc4d..c639752ac3 100644
--- a/platform/darwin/src/MGLAttributionInfo_Private.h
+++ b/platform/darwin/src/MGLAttributionInfo_Private.h
@@ -20,6 +20,24 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSAttributedString *)attributedStringForAttributionInfos:(NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos;
+/**
+ Returns a copy of the `URL` property modified to account for the given style
+ URL, center coordinate, and zoom level.
+
+ @param styleURL The map’s style URL.
+ @param centerCoordinate The map’s center coordinate.
+ @param zoomLevel The map’s zoom level. See the `MGLMapView.zoomLevel` property
+ for more information.
+ @param direction The heading of the map, measured in degrees clockwise from
+ true north.
+ @param pitch Pitch toward the horizon measured in degrees, with 0 degrees
+ resulting in a two-dimensional map.
+ @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 *)feedbackURLForStyleURL:(nullable NSURL *)styleURL atCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction pitch:(CGFloat)pitch;
+
@end
@interface NSMutableArray (MGLAttributionInfoAdditions)
diff --git a/platform/darwin/src/MGLFillExtrusionStyleLayer.h b/platform/darwin/src/MGLFillExtrusionStyleLayer.h
index 84f6bedde4..c4fb9aa77e 100644
--- a/platform/darwin/src/MGLFillExtrusionStyleLayer.h
+++ b/platform/darwin/src/MGLFillExtrusionStyleLayer.h
@@ -46,7 +46,7 @@ typedef NS_ENUM(NSUInteger, MGLFillExtrusionTranslationAnchor) {
layer.sourceLayerIdentifier = "building"
layer.fillExtrusionHeight = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "height", options: nil)
layer.fillExtrusionBase = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "min_height", options: nil)
- layer.predicate = NSPredicate(format: "extrude == TRUE")
+ layer.predicate = NSPredicate(format: "extrude == 'true'")
mapView.style?.addLayer(layer)
```
*/
diff --git a/platform/darwin/src/MGLGeometry_Private.h b/platform/darwin/src/MGLGeometry_Private.h
index 3e029e8ee0..7ad8314a79 100644
--- a/platform/darwin/src/MGLGeometry_Private.h
+++ b/platform/darwin/src/MGLGeometry_Private.h
@@ -8,6 +8,26 @@
#import <mbgl/util/geo.hpp>
#import <mbgl/util/geometry.hpp>
+typedef double MGLLocationRadians;
+typedef double MGLRadianDistance;
+typedef double MGLRadianDirection;
+
+/** Defines the coordinate by a `MGLRadianCoordinate2D`. */
+typedef struct MGLRadianCoordinate2D {
+ MGLLocationRadians latitude;
+ MGLLocationRadians longitude;
+} MGLRadianCoordinate2D;
+
+/**
+ Creates a new `MGLRadianCoordinate2D` from the given latitudinal and longitudinal.
+ */
+NS_INLINE MGLRadianCoordinate2D MGLRadianCoordinate2DMake(MGLLocationRadians latitude, MGLLocationRadians longitude) {
+ MGLRadianCoordinate2D radianCoordinate;
+ radianCoordinate.latitude = latitude;
+ radianCoordinate.longitude = longitude;
+ return radianCoordinate;
+}
+
/// Returns the smallest rectangle that contains both the given rectangle and
/// the given point.
CGRect MGLExtendRect(CGRect rect, CGPoint point);
@@ -18,6 +38,10 @@ NS_INLINE mbgl::Point<double> MGLPointFromLocationCoordinate2D(CLLocationCoordin
return mbgl::Point<double>(coordinate.longitude, coordinate.latitude);
}
+NS_INLINE CLLocationCoordinate2D MGLLocationCoordinate2DFromPoint(mbgl::Point<double> point) {
+ return CLLocationCoordinate2DMake(point.y, point.x);
+}
+
NS_INLINE CLLocationCoordinate2D MGLLocationCoordinate2DFromLatLng(mbgl::LatLng latLng) {
return CLLocationCoordinate2DMake(latLng.latitude(), latLng.longitude());
}
@@ -59,3 +83,43 @@ CLLocationDistance MGLAltitudeForZoomLevel(double zoomLevel, CGFloat pitch, CLLo
@param size The size of the viewport.
@return A zero-based zoom level. */
double MGLZoomLevelForAltitude(CLLocationDistance altitude, CGFloat pitch, CLLocationDegrees latitude, CGSize size);
+
+/** Returns MGLRadianCoordinate2D, converted from CLLocationCoordinate2D. */
+NS_INLINE MGLRadianCoordinate2D MGLRadianCoordinateFromLocationCoordinate(CLLocationCoordinate2D locationCoordinate) {
+ return MGLRadianCoordinate2DMake(MGLRadiansFromDegrees(locationCoordinate.latitude),
+ MGLRadiansFromDegrees(locationCoordinate.longitude));
+}
+
+/*
+ Returns the distance in radians given two coordinates.
+ */
+NS_INLINE MGLRadianDistance MGLDistanceBetweenRadianCoordinates(MGLRadianCoordinate2D from, MGLRadianCoordinate2D to)
+{
+ double a = pow(sin((to.latitude - from.latitude) / 2), 2)
+ + pow(sin((to.longitude - from.longitude) / 2), 2) * cos(from.latitude) * cos(to.latitude);
+
+ return 2 * atan2(sqrt(a), sqrt(1 - a));
+}
+
+/*
+ Returns direction in radians given two coordinates.
+ */
+NS_INLINE MGLRadianDirection MGLRadianCoordinatesDirection(MGLRadianCoordinate2D from, MGLRadianCoordinate2D to) {
+ double a = sin(to.longitude - from.longitude) * cos(to.latitude);
+ double b = cos(from.latitude) * sin(to.latitude)
+ - sin(from.latitude) * cos(to.latitude) * cos(to.longitude - from.longitude);
+ return atan2(a, b);
+}
+
+/*
+ Returns coordinate at a given distance and direction away from coordinate.
+ */
+NS_INLINE MGLRadianCoordinate2D MGLRadianCoordinateAtDistanceFacingDirection(MGLRadianCoordinate2D coordinate,
+ MGLRadianDistance distance,
+ MGLRadianDirection direction) {
+ double otherLatitude = asin(sin(coordinate.latitude) * cos(distance)
+ + cos(coordinate.latitude) * sin(distance) * cos(direction));
+ double otherLongitude = coordinate.longitude + atan2(sin(direction) * sin(distance) * cos(coordinate.latitude),
+ cos(distance) - sin(coordinate.latitude) * sin(otherLatitude));
+ return MGLRadianCoordinate2DMake(otherLatitude, otherLongitude);
+}
diff --git a/platform/darwin/src/MGLLight.h b/platform/darwin/src/MGLLight.h
new file mode 100644
index 0000000000..ef9811bd33
--- /dev/null
+++ b/platform/darwin/src/MGLLight.h
@@ -0,0 +1,125 @@
+#import <CoreLocation/CoreLocation.h>
+
+#import "MGLFoundation.h"
+#import "MGLStyleValue.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+/** Options to specify extruded geometries are lit relative to the map or viewport. */
+typedef NS_ENUM(NSUInteger, MGLLightAnchor) {
+ /** The position of the light source is aligned to the rotation of the map. */
+ MGLLightAnchorMap,
+ /** The position of the light source is aligned to the rotation of the viewport. */
+ MGLLightAnchorViewport
+};
+
+/**
+ A structure containing information about the position of the light source
+ relative to lit geometries.
+ */
+typedef struct MGLSphericalPosition {
+ /** Distance from the center of the base of an object to its light. */
+ CLLocationDistance radial;
+ /** Position of the light relative to 0° (0° when `MGLLight.anchor` is set to viewport corresponds
+ to the top of the viewport, or 0° when `MGLLight.anchor` is set to map corresponds to due north,
+ and degrees proceed clockwise). */
+ CLLocationDirection azimuthal;
+ /** Indicates the height of the light (from 0°, directly above, to 180°, directly below). */
+ CLLocationDirection polar;
+} MGLSphericalPosition;
+
+/**
+ Creates a new `MGLSphericalPosition` from the given radial, azimuthal, polar.
+
+ @param radial The radial coordinate.
+ @param azimuthal The azimuthal angle.
+ @param polar The polar angle.
+
+ @return Returns a `MGLSphericalPosition` struct containing the position attributes.
+ */
+NS_INLINE MGLSphericalPosition MGLSphericalPositionMake(CLLocationDistance radial, CLLocationDirection azimuthal, CLLocationDirection polar) {
+ MGLSphericalPosition position;
+ position.radial = radial;
+ position.azimuthal = azimuthal;
+ position.polar = polar;
+
+ return position;
+}
+
+/**
+ An `MGLLight` object represents the light source for extruded geometries in `MGLStyle`.
+ */
+MGL_EXPORT
+@interface MGLLight : NSObject
+
+/**
+ `anchor` Whether extruded geometries are lit relative to the map or viewport.
+
+ This property corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-js/style-spec/#light-anchor"><code>anchor</code></a>
+ light property in the Mapbox Style Specification.
+ */
+@property (nonatomic) MGLStyleValue<NSValue *> *anchor;
+
+/**
+ Values describing animated transitions to `anchor` property.
+ */
+@property (nonatomic) MGLTransition anchorTransition;
+
+
+/**
+ Position of the light source relative to lit (extruded) geometries.
+
+ This property corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-js/style-spec/#light-position"><code>position</code></a>
+ light property in the Mapbox Style Specification.
+ */
+@property (nonatomic) MGLStyleValue<NSValue *> *position;
+
+/**
+ Values describing animated transitions to `position` property.
+ */
+@property (nonatomic) MGLTransition positionTransiton;
+
+
+#if TARGET_OS_IPHONE
+/**
+ Color tint for lighting extruded geometries.
+
+ This property corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-js/style-spec/#light-color"><code>color</code></a>
+ light property in the Mapbox Style Specification.
+ */
+@property (nonatomic) MGLStyleValue<UIColor *> *color;
+#else
+
+/**
+ Color tint for lighting extruded geometries.
+ */
+@property (nonatomic) MGLStyleValue<NSColor *> *color;
+#endif
+
+/**
+ Values describing animated transitions to `color` property.
+ */
+@property (nonatomic) MGLTransition colorTransiton;
+
+
+/**
+ Intensity of lighting (on a scale from 0 to 1). Higher numbers will present as more extreme contrast.
+
+ This property corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-js/style-spec/#light-intensity"><code>intensity</code></a>
+ light property in the Mapbox Style Specification.
+ */
+@property(nonatomic) MGLStyleValue<NSNumber *> *intensity;
+
+/**
+ Values describing animated transitions to `intensity` property.
+ */
+@property (nonatomic) MGLTransition intensityTransition;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLLight.mm b/platform/darwin/src/MGLLight.mm
new file mode 100644
index 0000000000..262fad3b07
--- /dev/null
+++ b/platform/darwin/src/MGLLight.mm
@@ -0,0 +1,113 @@
+#import "MGLLight.h"
+
+#import "MGLTypes.h"
+#import "NSDate+MGLAdditions.h"
+#import "MGLStyleValue_Private.h"
+#import "NSValue+MGLAdditions.h"
+
+#import <mbgl/style/light.hpp>
+#import <mbgl/style/types.hpp>
+
+namespace mbgl {
+
+ MBGL_DEFINE_ENUM(MGLLightAnchor, {
+ { MGLLightAnchorMap, "map" },
+ { MGLLightAnchorViewport, "viewport" },
+ });
+
+}
+
+NS_INLINE MGLTransition MGLTransitionFromOptions(const mbgl::style::TransitionOptions& options) {
+ MGLTransition transition;
+ transition.duration = MGLTimeIntervalFromDuration(options.duration.value_or(mbgl::Duration::zero()));
+ transition.delay = MGLTimeIntervalFromDuration(options.delay.value_or(mbgl::Duration::zero()));
+
+ return transition;
+}
+
+NS_INLINE mbgl::style::TransitionOptions MGLOptionsFromTransition(MGLTransition transition) {
+ mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
+ return options;
+}
+
+@interface MGLLight()
+
+@end
+
+@implementation MGLLight
+
+- (instancetype)initWithMBGLLight:(const mbgl::style::Light *)mbglLight
+{
+ if (self = [super init]) {
+ auto anchor = mbglLight->getAnchor();
+ MGLStyleValue<NSValue *> *anchorStyleValue;
+ if (anchor.isUndefined()) {
+ mbgl::style::PropertyValue<mbgl::style::LightAnchorType> defaultAnchor = mbglLight->getDefaultAnchor();
+ anchorStyleValue = MGLStyleValueTransformer<mbgl::style::LightAnchorType, NSValue *, mbgl::style::LightAnchorType, MGLLightAnchor>().toEnumStyleValue(defaultAnchor);
+ } else {
+ anchorStyleValue = MGLStyleValueTransformer<mbgl::style::LightAnchorType, NSValue *, mbgl::style::LightAnchorType, MGLLightAnchor>().toEnumStyleValue(anchor);
+ }
+
+ _anchor = anchorStyleValue;
+
+ _anchorTransition = MGLTransitionFromOptions(mbglLight->getAnchorTransition());
+
+ auto positionValue = mbglLight->getPosition();
+ if (positionValue.isUndefined()) {
+ _position = MGLStyleValueTransformer<mbgl::style::Position, NSValue *>().toStyleValue(mbglLight->getDefaultPosition());
+ } else {
+ _position = MGLStyleValueTransformer<mbgl::style::Position, NSValue *>().toStyleValue(positionValue);
+ }
+
+ _positionTransiton = MGLTransitionFromOptions(mbglLight->getPositionTransition());
+
+ auto colorValue = mbglLight->getColor();
+ if (colorValue.isUndefined()) {
+ _color = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(mbglLight->getDefaultColor());
+ } else {
+ _color = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(colorValue);
+ }
+
+ _colorTransiton = MGLTransitionFromOptions(mbglLight->getColorTransition());
+
+ auto intensityValue = mbglLight->getIntensity();
+ if (intensityValue.isUndefined()) {
+ _intensity = MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(mbglLight->getDefaultIntensity());
+ } else {
+ _intensity = MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(intensityValue);
+ }
+
+ _intensityTransition = MGLTransitionFromOptions(mbglLight->getIntensityTransition());
+ }
+
+ return self;
+}
+
+- (mbgl::style::Light)mbglLight
+{
+ mbgl::style::Light mbglLight;
+
+ auto anchor = MGLStyleValueTransformer<mbgl::style::LightAnchorType, NSValue *, mbgl::style::LightAnchorType, MGLLightAnchor>().toEnumPropertyValue(self.anchor);
+ mbglLight.setAnchor(anchor);
+
+ mbglLight.setAnchorTransition(MGLOptionsFromTransition(self.anchorTransition));
+
+ auto position = MGLStyleValueTransformer<mbgl::style::Position, NSValue *>().toInterpolatablePropertyValue(self.position);
+ mbglLight.setPosition(position);
+
+ mbglLight.setPositionTransition(MGLOptionsFromTransition(self.positionTransiton));
+
+ auto color = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toInterpolatablePropertyValue(self.color);
+ mbglLight.setColor(color);
+
+ mbglLight.setColorTransition(MGLOptionsFromTransition(self.colorTransiton));
+
+ auto intensity = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(self.intensity);
+ mbglLight.setIntensity(intensity);
+
+ mbglLight.setIntensityTransition(MGLOptionsFromTransition(self.intensityTransition));
+
+ return mbglLight;
+}
+
+@end
diff --git a/platform/darwin/src/MGLLight_Private.h b/platform/darwin/src/MGLLight_Private.h
new file mode 100644
index 0000000000..dbc29c1eff
--- /dev/null
+++ b/platform/darwin/src/MGLLight_Private.h
@@ -0,0 +1,23 @@
+#import <Foundation/Foundation.h>
+
+#import "MGLLight.h"
+
+namespace mbgl {
+ namespace style {
+ class Light;
+ }
+}
+
+@interface MGLLight (Private)
+
+/**
+ Initializes and returns a `MGLLight` associated with a style's light.
+ */
+- (instancetype)initWithMBGLLight:(const mbgl::style::Light *)mbglLight;
+
+/**
+ Returns an `mbgl::style::Light` representation of the `MGLLight`.
+ */
+- (mbgl::style::Light)mbglLight;
+
+@end
diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm
index 195ef3c36a..81774ad3cb 100644
--- a/platform/darwin/src/MGLOfflineStorage.mm
+++ b/platform/darwin/src/MGLOfflineStorage.mm
@@ -7,6 +7,7 @@
#import "MGLOfflinePack_Private.h"
#import "MGLOfflineRegion_Private.h"
#import "MGLTilePyramidOfflineRegion.h"
+#import "NSBundle+MGLAdditions.h"
#import "NSValue+MGLAdditions.h"
#include <mbgl/util/string.hpp>
@@ -132,7 +133,7 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
appropriateForURL:nil
create:YES
error:nil];
- NSString *bundleIdentifier = [self bundleIdentifier];
+ NSString *bundleIdentifier = [NSBundle mgl_applicationBundleIdentifier];
if (!bundleIdentifier) {
// There’s no main bundle identifier when running in a unit test bundle.
bundleIdentifier = [NSBundle bundleForClass:self].bundleIdentifier;
@@ -166,7 +167,7 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
NSString *legacyCachePath = [legacyPaths.firstObject stringByAppendingPathComponent:MGLOfflineStorageFileName3_2_0_beta_1];
#elif TARGET_OS_MAC
// ~/Library/Caches/tld.app.bundle.id/offline.db
- NSString *bundleIdentifier = [self bundleIdentifier];
+ NSString *bundleIdentifier = [NSBundle mgl_applicationBundleIdentifier];
NSURL *legacyCacheDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
@@ -219,15 +220,6 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
return self;
}
-+ (NSString *)bundleIdentifier {
- NSString *bundleIdentifier = [NSBundle mainBundle].bundleIdentifier;
- if (!bundleIdentifier) {
- // There’s no main bundle identifier when running in a unit test bundle.
- bundleIdentifier = [NSBundle bundleForClass:self].bundleIdentifier;
- }
- return bundleIdentifier;
-}
-
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[MGLNetworkConfiguration sharedManager] removeObserver:self forKeyPath:@"apiBaseURL"];
diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm
index ceafe873bf..d966ff13ce 100644
--- a/platform/darwin/src/MGLPolygon.mm
+++ b/platform/darwin/src/MGLPolygon.mm
@@ -6,6 +6,7 @@
#import "MGLPolygon+MGLAdditions.h"
#import <mbgl/util/geojson.hpp>
+#import <mapbox/polylabel.hpp>
@implementation MGLPolygon
@@ -54,6 +55,13 @@
return [super hash] + [[self geoJSONDictionary] hash];
}
+- (CLLocationCoordinate2D)coordinate {
+ // pole of inaccessibility
+ auto poi = mapbox::polylabel([self polygon]);
+
+ return MGLLocationCoordinate2DFromPoint(poi);
+}
+
- (mbgl::LinearRing<double>)ring {
NSUInteger count = self.pointCount;
CLLocationCoordinate2D *coordinates = self.coordinates;
@@ -155,11 +163,17 @@
return hash;
}
+- (CLLocationCoordinate2D)coordinate {
+ MGLPolygon *firstPolygon = self.polygons.firstObject;
+
+ return firstPolygon.coordinate;
+}
+
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
}
-- (mbgl::Geometry<double>)geometryObject {
+- (mbgl::MultiPolygon<double>)multiPolygon {
mbgl::MultiPolygon<double> multiPolygon;
multiPolygon.reserve(self.polygons.count);
for (MGLPolygon *polygon in self.polygons) {
@@ -173,6 +187,10 @@
return multiPolygon;
}
+- (mbgl::Geometry<double>)geometryObject {
+ return [self multiPolygon];
+}
+
- (NSDictionary *)geoJSONDictionary {
NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.polygons.count];
for (MGLPolygonFeature *feature in self.polygons) {
diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm
index ae4fbe61de..fd75dc2795 100644
--- a/platform/darwin/src/MGLPolyline.mm
+++ b/platform/darwin/src/MGLPolyline.mm
@@ -6,6 +6,7 @@
#import "MGLPolyline+MGLAdditions.h"
#import <mbgl/util/geojson.hpp>
+#import <mapbox/polylabel.hpp>
@implementation MGLPolyline
@@ -52,6 +53,61 @@
return self == other || ([other isKindOfClass:[MGLPolyline class]] && [super isEqual:other]);
}
+- (CLLocationCoordinate2D)coordinate {
+ NSUInteger count = self.pointCount;
+ NSAssert(count > 0, @"Polyline must have coordinates");
+
+ CLLocationCoordinate2D *coordinates = self.coordinates;
+ CLLocationDistance middle = [self length] / 2.0;
+ CLLocationDistance traveled = 0.0;
+
+ if (count > 1 || middle > traveled) {
+ for (NSUInteger i = 0; i < count; i++) {
+
+ MGLRadianCoordinate2D from = MGLRadianCoordinateFromLocationCoordinate(coordinates[i]);
+ MGLRadianCoordinate2D to = MGLRadianCoordinateFromLocationCoordinate(coordinates[i + 1]);
+
+ if (traveled >= middle) {
+ double overshoot = middle - traveled;
+ if (overshoot == 0) {
+ return coordinates[i];
+ }
+ to = MGLRadianCoordinateFromLocationCoordinate(coordinates[i - 1]);
+ CLLocationDirection direction = [self direction:from to:to] - 180;
+ MGLRadianCoordinate2D otherCoordinate = MGLRadianCoordinateAtDistanceFacingDirection(from,
+ overshoot/mbgl::util::EARTH_RADIUS_M,
+ MGLRadiansFromDegrees(direction));
+ return CLLocationCoordinate2DMake(MGLDegreesFromRadians(otherCoordinate.latitude),
+ MGLDegreesFromRadians(otherCoordinate.longitude));
+ }
+
+ traveled += (MGLDistanceBetweenRadianCoordinates(from, to) * mbgl::util::EARTH_RADIUS_M);
+
+ }
+ }
+
+ return coordinates[count - 1];
+}
+
+- (CLLocationDistance)length
+{
+ CLLocationDistance length = 0.0;
+
+ NSUInteger count = self.pointCount;
+ CLLocationCoordinate2D *coordinates = self.coordinates;
+
+ for (NSUInteger i = 0; i < count - 1; i++) {
+ length += (MGLDistanceBetweenRadianCoordinates(MGLRadianCoordinateFromLocationCoordinate(coordinates[i]), MGLRadianCoordinateFromLocationCoordinate(coordinates[i + 1])) * mbgl::util::EARTH_RADIUS_M);
+ }
+
+ return length;
+}
+
+- (CLLocationDirection)direction:(MGLRadianCoordinate2D)from to:(MGLRadianCoordinate2D)to
+{
+ return MGLDegreesFromRadians(MGLRadianCoordinatesDirection(from, to));
+}
+
@end
@interface MGLMultiPolyline ()
@@ -114,6 +170,15 @@
return hash;
}
+- (CLLocationCoordinate2D)coordinate {
+ MGLPolyline *polyline = self.polylines.firstObject;
+ CLLocationCoordinate2D *coordinates = polyline.coordinates;
+ NSAssert([polyline pointCount] > 0, @"Polyline must have coordinates");
+ CLLocationCoordinate2D firstCoordinate = coordinates[0];
+
+ return firstCoordinate;
+}
+
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
}
diff --git a/platform/darwin/src/MGLRasterSource.h b/platform/darwin/src/MGLRasterSource.h
index 519784f4f1..4f4b7c96c3 100644
--- a/platform/darwin/src/MGLRasterSource.h
+++ b/platform/darwin/src/MGLRasterSource.h
@@ -108,96 +108,13 @@ MGL_EXPORT
Returns a raster source initialized an identifier, tile URL templates, and
options.
+ Tile URL templates are strings that specify the URLs of the raster tile images
+ to load. See the “<a href="../tile-url-templates.html">Tile URL Templates</a>”
+ guide for information about the format of a tile URL template.
+
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
- #### Tile URL templates
-
- Tile URL templates are strings that specify the URLs of the tile images to
- load. Each template resembles an absolute URL, but with any number of
- placeholder strings that the source evaluates based on the tile it needs to
- load. For example:
-
- <ul>
- <li><code>http://www.example.com/tiles/{z}/{x}/{y}.pbf</code> could be
- evaluated as <code>http://www.example.com/tiles/14/6/9.pbf</code>.</li>
- <li><code>http://www.example.com/tiles/{z}/{x}/{y}{ratio}.png</code> could be
- evaluated as <code>http://www.example.com/tiles/14/6/9@2x.png</code>.</li>
- </ul>
-
- Tile sources support the following placeholder strings in tile URL templates,
- all of which are optional:
-
- <table>
- <thead>
- <tr><th>Placeholder string</th><th>Description</th></tr>
- </thead>
- <tbody>
- <tr>
- <td><code>{x}</code></td>
- <td>The index of the tile along the map’s x axis according to Spherical
- Mercator projection. If the value is 0, the tile’s left edge corresponds
- to the 180th meridian west. If the value is 2<sup><var>z</var></sup>−1,
- the tile’s right edge corresponds to the 180th meridian east.</td>
- </tr>
- <tr>
- <td><code>{y}</code></td>
- <td>The index of the tile along the map’s y axis according to Spherical
- Mercator projection. If the value is 0, the tile’s tile edge corresponds
- to arctan(sinh(π)), or approximately 85.0511 degrees north. If the value
- is 2<sup><var>z</var></sup>−1, the tile’s bottom edge corresponds to
- −arctan(sinh(π)), or approximately 85.0511 degrees south. The y axis is
- inverted if the <code>options</code> parameter contains
- <code>MGLTileSourceOptionTileCoordinateSystem</code> with a value of
- <code>MGLTileCoordinateSystemTMS</code>.</td>
- </tr>
- <tr>
- <td><code>{z}</code></td>
- <td>The tile’s zoom level. At zoom level 0, each tile covers the entire
- world map; at zoom level 1, it covers ¼ of the world; at zoom level 2,
- <sup>1</sup>⁄<sub>16</sub> of the world, and so on. For tiles loaded by
- a <code>MGLRasterSource</code> object, whether the tile zoom level
- matches the map’s current zoom level depends on the value of the
- source’s tile size as specified in the
- <code>MGLTileSourceOptionTileSize</code> key of the
- <code>options</code> parameter.</td>
- </tr>
- <tr>
- <td><code>{bbox-epsg-3857}</code></td>
- <td>The tile’s bounding box, expressed as a comma-separated list of the
- tile’s western, southern, eastern, and northern extents according to
- Spherical Mercator (EPSG:3857) projection. The bounding box is typically
- used with map services conforming to the
- <a href="http://www.opengeospatial.org/standards/wms">Web Map Service</a>
- protocol.</td>
- </tr>
- <tr>
- <td><code>{quadkey}</code></td>
- <td>A quadkey indicating both the tile’s location and its zoom level. The
- quadkey is typically used with
- <a href="https://msdn.microsoft.com/en-us/library/bb259689.aspx">Bing Maps</a>.
- </td>
- </tr>
- <tr>
- <td><code>{ratio}</code></td>
- <td>A suffix indicating the resolution of the tile image. The suffix is the
- empty string for standard resolution displays and <code>@2x</code> for
- Retina displays, including displays for which
- <code>NSScreen.backingScaleFactor</code> or <code>UIScreen.scale</code>
- is 3.</td>
- </tr>
- <tr>
- <td><code>{prefix}</code></td>
- <td>Two hexadecimal digits chosen such that each visible tile has a
- different prefix. The prefix is typically used for domain sharding.</td>
- </tr>
- </tbody>
- </table>
-
- For more information about the `{x}`, `{y}`, and `{z}` placeholder strings,
- consult the
- <a href="https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames">OpenStreetMap Wiki</a>.
-
@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. Only the first
diff --git a/platform/darwin/src/MGLStyle.h b/platform/darwin/src/MGLStyle.h
index ccec863236..6fb4a6cc6b 100644
--- a/platform/darwin/src/MGLStyle.h
+++ b/platform/darwin/src/MGLStyle.h
@@ -6,6 +6,7 @@
#import "MGLTypes.h"
@class MGLSource;
+@class MGLLight;
NS_ASSUME_NONNULL_BEGIN
@@ -548,6 +549,14 @@ MGL_EXPORT
*/
- (void)removeImageForName:(NSString *)name;
+
+#pragma mark Managing the Style's Light
+
+/**
+ Provides global light source for the style.
+ */
+@property (nonatomic, strong) MGLLight *light;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index 5f26b4fed2..2e6f2bc29a 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -14,6 +14,7 @@
#import "MGLStyle_Private.h"
#import "MGLStyleLayer_Private.h"
#import "MGLSource_Private.h"
+#import "MGLLight_Private.h"
#import "NSDate+MGLAdditions.h"
@@ -28,6 +29,7 @@
#include <mbgl/map/map.hpp>
#include <mbgl/util/default_styles.hpp>
#include <mbgl/style/image.hpp>
+#include <mbgl/style/light.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/fill_extrusion_layer.hpp>
#include <mbgl/style/layers/line_layer.hpp>
@@ -556,6 +558,21 @@ static NSURL *MGLStyleURL_emerald;
return transition;
}
+#pragma mark Style light
+
+- (void)setLight:(MGLLight *)light
+{
+ std::unique_ptr<mbgl::style::Light> mbglLight = std::make_unique<mbgl::style::Light>([light mbglLight]);
+ self.mapView.mbglMap->setLight(std::move(mbglLight));
+}
+
+- (MGLLight *)light
+{
+ auto mbglLight = self.mapView.mbglMap->getLight();
+ MGLLight *light = [[MGLLight alloc] initWithMBGLLight:mbglLight];
+ return light;
+}
+
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; name = %@, URL = %@>",
diff --git a/platform/darwin/src/MGLStyleValue.h b/platform/darwin/src/MGLStyleValue.h
index 70074c8a13..2bb3aca4f4 100644
--- a/platform/darwin/src/MGLStyleValue.h
+++ b/platform/darwin/src/MGLStyleValue.h
@@ -75,9 +75,9 @@ typedef NS_ENUM(NSUInteger, MGLInterpolationMode) {
*/
MGLInterpolationModeCategorical,
/**
- Values between two stops are not interpolated. Instead, values are set to their
- input value. Use identity interpolation mode to show attribute values that can be
- used as style values.
+ Values between two stops are not interpolated. Instead, for any given feature, the
+ style value matches a value in that feature’s attributes dictionary. Use identity
+ interpolation mode to show attribute values that can be used as style values.
*/
MGLInterpolationModeIdentity
};
diff --git a/platform/darwin/src/MGLStyleValue.mm b/platform/darwin/src/MGLStyleValue.mm
index 33b6babadf..4dd6b550d8 100644
--- a/platform/darwin/src/MGLStyleValue.mm
+++ b/platform/darwin/src/MGLStyleValue.mm
@@ -128,7 +128,7 @@ const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue = @"MGLStyleFunc
return {};
}
- if (self == [super init]) {
+ if (self = [super init]) {
self.interpolationMode = interpolationMode;
self.stops = stops;
@@ -181,7 +181,7 @@ const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue = @"MGLStyleFunc
}
- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
- if (self == [super init]) {
+ if (self = [super init]) {
self.interpolationMode = interpolationMode;
self.stops = stops;
_attributeName = attributeName;
@@ -251,7 +251,7 @@ const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue = @"MGLStyleFunc
}
- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
- if (self == [super init]) {
+ if (self = [super init]) {
self.interpolationMode = interpolationMode;
self.stops = stops;
_attributeName = attributeName;
diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h
index 263b54d7e5..2155c657bd 100644
--- a/platform/darwin/src/MGLStyleValue_Private.h
+++ b/platform/darwin/src/MGLStyleValue_Private.h
@@ -3,11 +3,13 @@
#import "MGLStyleValue.h"
#import "NSValue+MGLStyleAttributeAdditions.h"
+#import "NSValue+MGLAdditions.h"
#import "MGLTypes.h"
#import "MGLConversion.h"
#include <mbgl/style/conversion/data_driven_property_value.hpp>
#include <mbgl/style/conversion.hpp>
+#import <mbgl/style/types.hpp>
#import <mbgl/util/enum.hpp>
@@ -415,6 +417,12 @@ private: // Private utilities for converting from mgl to mbgl values
mbglValue.push_back(mbglElement);
}
}
+
+ void getMBGLValue(NSValue *rawValue, mbgl::style::Position &mbglValue) {
+ auto spherical = rawValue.mgl_lightPositionArrayValue;
+ mbgl::style::Position position(spherical);
+ mbglValue = position;
+ }
// Enumerations
template <typename MBGLEnum = MBGLType,
@@ -473,6 +481,12 @@ private: // Private utilities for converting from mbgl to mgl values
}
return array;
}
+
+ static NSValue *toMGLRawStyleValue(const mbgl::style::Position &mbglStopValue) {
+ std::array<float, 3> spherical = mbglStopValue.getSpherical();
+ MGLSphericalPosition position = MGLSphericalPositionMake(spherical[0], spherical[1], spherical[2]);
+ return [NSValue valueWithMGLSphericalPosition:position];
+ }
// Enumerations
template <typename MBGLEnum = MBGLType, typename MGLEnum = ObjCEnum>
diff --git a/platform/darwin/src/MGLTypes.h b/platform/darwin/src/MGLTypes.h
index c06fd8b0e7..16f510b5a6 100644
--- a/platform/darwin/src/MGLTypes.h
+++ b/platform/darwin/src/MGLTypes.h
@@ -1,4 +1,5 @@
#import <Foundation/Foundation.h>
+#import <CoreGraphics/CoreGraphics.h>
#import "MGLFoundation.h"
diff --git a/platform/darwin/src/MGLVectorSource.h b/platform/darwin/src/MGLVectorSource.h
index a48434f7a3..968be3c0e0 100644
--- a/platform/darwin/src/MGLVectorSource.h
+++ b/platform/darwin/src/MGLVectorSource.h
@@ -74,96 +74,13 @@ MGL_EXPORT
Returns a vector source initialized an identifier, tile URL templates, and
options.
+ Tile URL templates are strings that specify the URLs of the vector tiles to
+ load. See the “<a href="../tile-url-templates.html">Tile URL Templates</a>”
+ guide for information about the format of a tile URL template.
+
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
- #### Tile URL templates
-
- Tile URL templates are strings that specify the URLs of the tile images to
- load. Each template resembles an absolute URL, but with any number of
- placeholder strings that the source evaluates based on the tile it needs to
- load. For example:
-
- <ul>
- <li><code>http://www.example.com/tiles/{z}/{x}/{y}.pbf</code> could be
- evaluated as <code>http://www.example.com/tiles/14/6/9.pbf</code>.</li>
- <li><code>http://www.example.com/tiles/{z}/{x}/{y}{ratio}.png</code> could be
- evaluated as <code>http://www.example.com/tiles/14/6/9@2x.png</code>.</li>
- </ul>
-
- Tile sources support the following placeholder strings in tile URL templates,
- all of which are optional:
-
- <table>
- <thead>
- <tr><th>Placeholder string</th><th>Description</th></tr>
- </thead>
- <tbody>
- <tr>
- <td><code>{x}</code></td>
- <td>The index of the tile along the map’s x axis according to Spherical
- Mercator projection. If the value is 0, the tile’s left edge corresponds
- to the 180th meridian west. If the value is 2<sup><var>z</var></sup>−1,
- the tile’s right edge corresponds to the 180th meridian east.</td>
- </tr>
- <tr>
- <td><code>{y}</code></td>
- <td>The index of the tile along the map’s y axis according to Spherical
- Mercator projection. If the value is 0, the tile’s tile edge corresponds
- to arctan(sinh(π)), or approximately 85.0511 degrees north. If the value
- is 2<sup><var>z</var></sup>−1, the tile’s bottom edge corresponds to
- −arctan(sinh(π)), or approximately 85.0511 degrees south. The y axis is
- inverted if the <code>options</code> parameter contains
- <code>MGLTileSourceOptionTileCoordinateSystem</code> with a value of
- <code>MGLTileCoordinateSystemTMS</code>.</td>
- </tr>
- <tr>
- <td><code>{z}</code></td>
- <td>The tile’s zoom level. At zoom level 0, each tile covers the entire
- world map; at zoom level 1, it covers ¼ of the world; at zoom level 2,
- <sup>1</sup>⁄<sub>16</sub> of the world, and so on. For tiles loaded by
- a <code>MGLRasterSource</code> object, whether the tile zoom level
- matches the map’s current zoom level depends on the value of the
- source’s tile size as specified in the
- <code>MGLTileSourceOptionTileSize</code> key of the
- <code>options</code> parameter.</td>
- </tr>
- <tr>
- <td><code>{bbox-epsg-3857}</code></td>
- <td>The tile’s bounding box, expressed as a comma-separated list of the
- tile’s western, southern, eastern, and northern extents according to
- Spherical Mercator (EPSG:3857) projection. The bounding box is typically
- used with map services conforming to the
- <a href="http://www.opengeospatial.org/standards/wms">Web Map Service</a>
- protocol.</td>
- </tr>
- <tr>
- <td><code>{quadkey}</code></td>
- <td>A quadkey indicating both the tile’s location and its zoom level. The
- quadkey is typically used with
- <a href="https://msdn.microsoft.com/en-us/library/bb259689.aspx">Bing Maps</a>.
- </td>
- </tr>
- <tr>
- <td><code>{ratio}</code></td>
- <td>A suffix indicating the resolution of the tile image. The suffix is the
- empty string for standard resolution displays and <code>@2x</code> for
- Retina displays, including displays for which
- <code>NSScreen.backingScaleFactor</code> or <code>UIScreen.scale</code>
- is 3.</td>
- </tr>
- <tr>
- <td><code>{prefix}</code></td>
- <td>Two hexadecimal digits chosen such that each visible tile has a
- different prefix. The prefix is typically used for domain sharding.</td>
- </tr>
- </tbody>
- </table>
-
- For more information about the `{x}`, `{y}`, and `{z}` placeholder strings,
- consult the
- <a href="https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames">OpenStreetMap Wiki</a>.
-
@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. Only the first
diff --git a/platform/darwin/src/NSBundle+MGLAdditions.h b/platform/darwin/src/NSBundle+MGLAdditions.h
index 1fc9e8b896..ad5e9d5369 100644
--- a/platform/darwin/src/NSBundle+MGLAdditions.h
+++ b/platform/darwin/src/NSBundle+MGLAdditions.h
@@ -36,9 +36,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (nullable NS_DICTIONARY_OF(NSString *, id) *)mgl_frameworkInfoDictionary;
-/// The relative path to the directory containing the SDK’s resource files, or
-/// `nil` if the files are located directly within the bundle’s root directory.
-@property (readonly, copy, nullable) NSString *mgl_resourcesDirectory;
++ (nullable NSString *)mgl_applicationBundleIdentifier;
@end
diff --git a/platform/darwin/src/NSBundle+MGLAdditions.m b/platform/darwin/src/NSBundle+MGLAdditions.m
index 76d9cc0db7..f383a50300 100644
--- a/platform/darwin/src/NSBundle+MGLAdditions.m
+++ b/platform/darwin/src/NSBundle+MGLAdditions.m
@@ -6,12 +6,19 @@
+ (instancetype)mgl_frameworkBundle {
NSBundle *bundle = [self bundleForClass:[MGLAccountManager class]];
- if (![bundle.infoDictionary[@"CFBundlePackageType"] isEqualToString:@"FMWK"] && !bundle.mgl_resourcesDirectory) {
+
+ if (![bundle.infoDictionary[@"CFBundlePackageType"] isEqualToString:@"FMWK"]) {
// For static frameworks, the bundle is the containing application
- // bundle but the resources are still in the framework bundle.
- bundle = [NSBundle bundleWithPath:[bundle.privateFrameworksPath
- stringByAppendingPathComponent:@"Mapbox.framework"]];
+ // bundle but the resources are in Mapbox.bundle.
+ NSString *bundlePath = [bundle pathForResource:@"Mapbox" ofType:@"bundle"];
+ if (bundlePath) {
+ bundle = [self bundleWithPath:bundlePath];
+ } else {
+ [NSException raise:@"MGLBundleNotFoundException" format:
+ @"The Mapbox framework bundle could not be found. If using the Mapbox iOS SDK as a static framework, make sure that Mapbox.bundle is copied into the root of the app bundle."];
+ }
}
+
return bundle;
}
@@ -21,18 +28,16 @@
+ (nullable NS_DICTIONARY_OF(NSString *, id) *)mgl_frameworkInfoDictionary {
NSBundle *bundle = self.mgl_frameworkBundle;
- if (bundle.mgl_resourcesDirectory) {
- NSString *infoPlistPath = [bundle pathForResource:@"Info"
- ofType:@"plist"
- inDirectory:bundle.mgl_resourcesDirectory];
- return [NSDictionary dictionaryWithContentsOfFile:infoPlistPath];
- } else {
- return bundle.infoDictionary;
- }
+ return bundle.infoDictionary;
}
-- (NSString *)mgl_resourcesDirectory {
- return [self pathForResource:@"Mapbox" ofType:@"bundle"] ? @"Mapbox.bundle" : nil;
++ (nullable NSString *)mgl_applicationBundleIdentifier {
+ NSString *bundleIdentifier = [NSBundle mainBundle].bundleIdentifier;
+ if (!bundleIdentifier) {
+ // There’s no main bundle identifier when running in a unit test bundle.
+ bundleIdentifier = [NSBundle bundleForClass:[MGLAccountManager class]].bundleIdentifier;
+ }
+ return bundleIdentifier;
}
@end
diff --git a/platform/darwin/src/NSValue+MGLAdditions.h b/platform/darwin/src/NSValue+MGLAdditions.h
index e6755021d0..0aaa2a337a 100644
--- a/platform/darwin/src/NSValue+MGLAdditions.h
+++ b/platform/darwin/src/NSValue+MGLAdditions.h
@@ -1,6 +1,7 @@
#import <Foundation/Foundation.h>
#import "MGLGeometry.h"
+#import "MGLLight.h"
#import "MGLOfflinePack.h"
#import "MGLTypes.h"
@@ -87,6 +88,34 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (readonly) MGLTransition MGLTransitionValue;
+/**
+ Creates a new value object containing the given `MGLSphericalPosition`
+ structure.
+
+ @param lightPosition The value for the new object.
+ @return A new value object that contains the light position information.
+ */
++ (instancetype)valueWithMGLSphericalPosition:(MGLSphericalPosition)lightPosition;
+
+/**
+ The `MGLSphericalPosition` structure representation of the value.
+ */
+@property (readonly) MGLSphericalPosition MGLSphericalPositionValue;
+
+/**
+ Creates a new value object containing the given `MGLLightAnchor`
+ enum.
+
+ @param lightAnchor The value for the new object.
+ @return A new value object that contains the light anchor information.
+ */
++ (NSValue *)valueWithMGLLightAnchor:(MGLLightAnchor)lightAnchor;
+
+/**
+ The `MGLLightAnchor` enum representation of the value.
+ */
+@property (readonly) MGLLightAnchor MGLLightAnchorValue;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/NSValue+MGLAdditions.m b/platform/darwin/src/NSValue+MGLAdditions.m
index a95ef23941..ef894f0eb4 100644
--- a/platform/darwin/src/NSValue+MGLAdditions.m
+++ b/platform/darwin/src/NSValue+MGLAdditions.m
@@ -58,4 +58,27 @@
return transition;
}
++ (NSValue *)valueWithMGLSphericalPosition:(MGLSphericalPosition)lightPosition
+{
+ return [NSValue value:&lightPosition withObjCType:@encode(MGLSphericalPosition)];
+}
+
+- (MGLSphericalPosition)MGLSphericalPositionValue
+{
+ MGLSphericalPosition lightPosition;
+ [self getValue:&lightPosition];
+ return lightPosition;
+}
+
++ (NSValue *)valueWithMGLLightAnchor:(MGLLightAnchor)lightAnchor {
+ return [NSValue value:&lightAnchor withObjCType:@encode(MGLLightAnchor)];
+}
+
+- (MGLLightAnchor)MGLLightAnchorValue
+{
+ MGLLightAnchor achorType;
+ [self getValue:&achorType];
+ return achorType;
+}
+
@end
diff --git a/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.h b/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.h
index 60c1ee4075..0f1e511694 100644
--- a/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.h
+++ b/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.h
@@ -9,5 +9,6 @@
- (std::array<float, 2>)mgl_offsetArrayValue;
- (std::array<float, 4>)mgl_paddingArrayValue;
+- (std::array<float, 3>)mgl_lightPositionArrayValue;
@end
diff --git a/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm b/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm
index e66145aec1..a41950b6b3 100644
--- a/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm
+++ b/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm
@@ -1,5 +1,5 @@
#import "NSValue+MGLStyleAttributeAdditions.h"
-
+#import "MGLLight.h"
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#define MGLEdgeInsets UIEdgeInsets
@@ -61,4 +61,17 @@
};
}
+- (std::array<float, 3>)mgl_lightPositionArrayValue
+{
+ NSAssert(strcmp(self.objCType, @encode(MGLSphericalPosition)) == 0, @"Value does not represent an MGLSphericalPosition");
+ MGLSphericalPosition lightPosition;
+ [self getValue:&lightPosition];
+ // Style specification defines padding in clockwise order: top, right, bottom, left.
+ return {
+ static_cast<float>(lightPosition.radial),
+ static_cast<float>(lightPosition.azimuthal),
+ static_cast<float>(lightPosition.polar),
+ };
+}
+
@end
diff --git a/platform/darwin/test/MGLAttributionInfoTests.m b/platform/darwin/test/MGLAttributionInfoTests.m
index e258671c09..ed4927d44b 100644
--- a/platform/darwin/test/MGLAttributionInfoTests.m
+++ b/platform/darwin/test/MGLAttributionInfoTests.m
@@ -46,8 +46,18 @@
XCTAssertEqualObjects(infos[3].title.string, @"Improve this map");
XCTAssertEqualObjects(infos[3].URL, [NSURL URLWithString:@"https://www.mapbox.com/map-feedback/"]);
XCTAssertTrue(infos[3].feedbackLink);
+ NSURL *styleURL = [MGLStyle satelliteStreetsStyleURLWithVersion:99];
+#if TARGET_OS_IPHONE
+ XCTAssertEqualObjects([infos[3] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14],
+ [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.sdk.ios#/77.63680/12.98108/14.00/0.0/0"]);
+ XCTAssertEqualObjects([infos[3] feedbackURLForStyleURL:styleURL atCenterCoordinate:mapbox zoomLevel:3.14159 direction:90.9 pitch:12.5],
+ [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.sdk.ios&owner=mapbox&id=satellite-streets-v99&access_token#/77.63680/12.98108/3.14/90.9/13"]);
+#else
XCTAssertEqualObjects([infos[3] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14],
- [NSURL URLWithString:@"https://www.mapbox.com/map-feedback/#/77.63680/12.98108/15"]);
+ [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.MapboxGL#/77.63680/12.98108/14.00/0.0/0"]);
+ XCTAssertEqualObjects([infos[3] feedbackURLForStyleURL:styleURL atCenterCoordinate:mapbox zoomLevel:3.14159 direction:90.9 pitch:12.5],
+ [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.MapboxGL&owner=mapbox&id=satellite-streets-v99&access_token#/77.63680/12.98108/3.14/90.9/13"]);
+#endif
}
- (void)testStyle {
diff --git a/platform/darwin/test/MGLCodingTests.m b/platform/darwin/test/MGLCodingTests.m
index ff0d674ad1..ac61672b76 100644
--- a/platform/darwin/test/MGLCodingTests.m
+++ b/platform/darwin/test/MGLCodingTests.m
@@ -66,12 +66,54 @@
[unarchivedPolyline replaceCoordinatesInRange:NSMakeRange(0, 1) withCoordinates:otherCoordinates];
XCTAssertNotEqualObjects(polyline, unarchivedPolyline);
+
+ CLLocationCoordinate2D multiLineCoordinates[] = {
+ CLLocationCoordinate2DMake(51.000000, 0.000000),
+ CLLocationCoordinate2DMake(51.000000, 1.000000),
+ CLLocationCoordinate2DMake(51.000000, 2.000000),
+ };
+
+ NSUInteger multiLineCoordinatesCount = sizeof(multiLineCoordinates) / sizeof(CLLocationCoordinate2D);
+ MGLPolyline *multiLine = [MGLPolyline polylineWithCoordinates:multiLineCoordinates count:multiLineCoordinatesCount];
+ CLLocationCoordinate2D multiLineCenter = CLLocationCoordinate2DMake(51.000000, 1.000000);
+
+ XCTAssertEqual([multiLine coordinate].latitude, multiLineCenter.latitude);
+ XCTAssertEqual([multiLine coordinate].longitude, multiLineCenter.longitude);
+
+ CLLocationCoordinate2D segmentCoordinates[] = {
+ CLLocationCoordinate2DMake(35.040390, -85.311477),
+ CLLocationCoordinate2DMake(35.040390, -85.209510),
+ };
+
+ NSUInteger segmentCoordinatesCount = sizeof(segmentCoordinates) / sizeof(CLLocationCoordinate2D);
+ MGLPolyline *segmentLine = [MGLPolyline polylineWithCoordinates:segmentCoordinates count:segmentCoordinatesCount];
+ CLLocationCoordinate2D segmentCenter = CLLocationCoordinate2DMake(35.0404006631, -85.2604935);
+
+ XCTAssertEqualWithAccuracy([segmentLine coordinate].latitude, segmentCenter.latitude, 0.0001);
+ XCTAssertEqualWithAccuracy([segmentLine coordinate].longitude, segmentCenter.longitude, 0.0001);
+
+ CLLocationCoordinate2D sfToBerkeleyCoordinates[] = {
+ CLLocationCoordinate2DMake(37.782440, -122.397111),
+ CLLocationCoordinate2DMake(37.818384, -122.352994),
+ CLLocationCoordinate2DMake(37.831401, -122.274545),
+ CLLocationCoordinate2DMake(37.862172, -122.262700),
+ };
+
+ NSUInteger sfToBerkeleyCoordinatesCount = sizeof(sfToBerkeleyCoordinates) / sizeof(CLLocationCoordinate2D);
+ MGLPolyline *sfToBerkeleyLine = [MGLPolyline polylineWithCoordinates:sfToBerkeleyCoordinates count:sfToBerkeleyCoordinatesCount];
+ CLLocationCoordinate2D sfToBerkeleyCenter = CLLocationCoordinate2DMake(37.8230575118,-122.324867587);
+
+ XCTAssertEqualWithAccuracy([sfToBerkeleyLine coordinate].latitude, sfToBerkeleyCenter.latitude, 0.0001);
+ XCTAssertEqualWithAccuracy([sfToBerkeleyLine coordinate].longitude, sfToBerkeleyCenter.longitude, 0.0001);
+
}
- (void)testPolygon {
CLLocationCoordinate2D coordinates[] = {
- CLLocationCoordinate2DMake(0.664482398, 1.8865675),
- CLLocationCoordinate2DMake(2.13224687, 3.9984632)
+ CLLocationCoordinate2DMake(35.090745, -85.300259),
+ CLLocationCoordinate2DMake(35.092035, -85.298885),
+ CLLocationCoordinate2DMake(35.090639, -85.297416),
+ CLLocationCoordinate2DMake(35.089112, -85.298928)
};
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
@@ -84,8 +126,24 @@
[NSKeyedArchiver archiveRootObject:polygon toFile:filePath];
MGLPolygon *unarchivedPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+ [unarchivedPolygon coordinate];
XCTAssertEqualObjects(polygon, unarchivedPolygon);
+
+ CLLocationCoordinate2D squareCoordinates[] = {
+ CLLocationCoordinate2DMake(100.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 1.0),
+ CLLocationCoordinate2DMake(100.0, 1.0),
+ };
+
+ NSUInteger squareCoordinatesCount = sizeof(squareCoordinates) / sizeof(CLLocationCoordinate2D);
+ MGLPolygon *squarePolygon = [MGLPolygon polygonWithCoordinates:squareCoordinates count:squareCoordinatesCount];
+ CLLocationCoordinate2D squareCenter = CLLocationCoordinate2DMake(100.5, 0.5);
+
+ XCTAssertEqual([squarePolygon coordinate].latitude, squareCenter.latitude);
+ XCTAssertEqual([squarePolygon coordinate].longitude, squareCenter.longitude);
+
}
- (void)testPolygonWithInteriorPolygons {
@@ -169,6 +227,11 @@
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
MGLPointCollection *pointCollection = [MGLPointCollection pointCollectionWithCoordinates:coordinates count:numberOfCoordinates];
+ CLLocationCoordinate2D pointsCenter = CLLocationCoordinate2DMake(0, 1);
+
+ XCTAssertEqual([pointCollection coordinate].latitude, pointsCenter.latitude);
+ XCTAssertEqual([pointCollection coordinate].longitude, pointsCenter.longitude);
+
NSString *filePath = [self temporaryFilePathForClass:[MGLPointCollection class]];
[NSKeyedArchiver archiveRootObject:pointCollection toFile:filePath];
@@ -218,6 +281,30 @@
CLLocationCoordinate2DMake(20, 21),
CLLocationCoordinate2DMake(30, 31),
};
+
+ CLLocationCoordinate2D line1[] = {
+ CLLocationCoordinate2DMake(100, 40),
+ CLLocationCoordinate2DMake(105, 45),
+ CLLocationCoordinate2DMake(110, 55)
+ };
+
+ CLLocationCoordinate2D line2[] = {
+ CLLocationCoordinate2DMake(105, 40),
+ CLLocationCoordinate2DMake(110, 45),
+ CLLocationCoordinate2DMake(115, 55)
+ };
+
+ NSUInteger road1CoordinatesCount = sizeof(line1) / sizeof(CLLocationCoordinate2D);
+ NSUInteger road2CoordinatesCount = sizeof(line2) / sizeof(CLLocationCoordinate2D);
+
+ MGLPolyline *road1Polyline = [MGLPolyline polylineWithCoordinates:line1 count:road1CoordinatesCount];
+ MGLPolyline *road2Polyline = [MGLPolyline polylineWithCoordinates:line1 count:road2CoordinatesCount];
+
+ MGLMultiPolyline *roads = [MGLMultiPolyline multiPolylineWithPolylines:@[road1Polyline, road2Polyline]];
+ CLLocationCoordinate2D roadCenter = CLLocationCoordinate2DMake(100, 40);
+
+ XCTAssertEqual([roads coordinate].latitude, roadCenter.latitude);
+ XCTAssertEqual([roads coordinate].longitude, roadCenter.longitude);
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
@@ -248,6 +335,31 @@
CLLocationCoordinate2DMake(20, 21),
CLLocationCoordinate2DMake(30, 31),
};
+
+ CLLocationCoordinate2D outerSquare[] = {
+ CLLocationCoordinate2DMake(100.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 1.0),
+ CLLocationCoordinate2DMake(100.0, 1.0),
+ };
+
+ CLLocationCoordinate2D innerSquare[] = {
+ CLLocationCoordinate2DMake(100.35, 0.35),
+ CLLocationCoordinate2DMake(100.65, 0.35),
+ CLLocationCoordinate2DMake(100.65, 0.65),
+ CLLocationCoordinate2DMake(100.35, 0.65),
+ };
+
+ NSUInteger outerCoordinatesCount = sizeof(outerSquare) / sizeof(CLLocationCoordinate2D);
+ NSUInteger innerCoordinatesCount = sizeof(innerSquare) / sizeof(CLLocationCoordinate2D);
+
+ MGLPolygon *innerPolygonSquare = [MGLPolygon polygonWithCoordinates:innerSquare count:innerCoordinatesCount];
+ MGLPolygon *outerPolygonSquare = [MGLPolygon polygonWithCoordinates:outerSquare count:outerCoordinatesCount interiorPolygons:@[innerPolygonSquare]];
+ MGLMultiPolygon *squares = [MGLMultiPolygon multiPolygonWithPolygons:@[outerPolygonSquare, innerPolygonSquare]];
+ CLLocationCoordinate2D squareCenter = CLLocationCoordinate2DMake(100.5, 0.5);
+
+ XCTAssertEqual([squares coordinate].latitude, squareCenter.latitude);
+ XCTAssertEqual([squares coordinate].longitude, squareCenter.longitude);
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
@@ -265,9 +377,10 @@
MGLMultiPolygon *unarchivedMultiPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
MGLMultiPolygon *anotherMultiPolygon = [MGLMultiPolygon multiPolygonWithPolygons:[polygons subarrayWithRange:NSMakeRange(0, polygons.count/2)]];
-
+
XCTAssertEqualObjects(multiPolygon, unarchivedMultiPolygon);
XCTAssertNotEqualObjects(anotherMultiPolygon, unarchivedMultiPolygon);
+
}
- (void)testShapeCollection {
diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift
index 6d2dc597a9..48e6b17f44 100644
--- a/platform/darwin/test/MGLDocumentationExampleTests.swift
+++ b/platform/darwin/test/MGLDocumentationExampleTests.swift
@@ -168,7 +168,7 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
layer.sourceLayerIdentifier = "building"
layer.fillExtrusionHeight = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "height", options: nil)
layer.fillExtrusionBase = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "min_height", options: nil)
- layer.predicate = NSPredicate(format: "extrude == TRUE")
+ layer.predicate = NSPredicate(format: "extrude == 'true'")
mapView.style?.addLayer(layer)
//#-end-example-code
diff --git a/platform/darwin/test/MGLLightTest.mm b/platform/darwin/test/MGLLightTest.mm
new file mode 100644
index 0000000000..2c3d1c7bd1
--- /dev/null
+++ b/platform/darwin/test/MGLLightTest.mm
@@ -0,0 +1,217 @@
+#import <XCTest/XCTest.h>
+#import <Mapbox/Mapbox.h>
+
+#import "MGLLight_Private.h"
+
+#import "../../darwin/src/NSDate+MGLAdditions.h"
+
+#import <mbgl/style/light.hpp>
+#import <mbgl/style/types.hpp>
+#include <mbgl/style/transition_options.hpp>
+
+@interface MGLLightTest : XCTestCase
+
+@end
+
+@implementation MGLLightTest
+
+- (void)testProperties {
+
+ MGLTransition defaultTransition = MGLTransitionMake(0, 0);
+ MGLTransition transition = MGLTransitionMake(6, 3);
+ mbgl::style::TransitionOptions transitionOptions { { MGLDurationFromTimeInterval(6) }, { MGLDurationFromTimeInterval(3) } };
+
+ // anchor
+ {
+ mbgl::style::Light light;
+ MGLLight *mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
+
+ NSAssert([mglLight.anchor isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.anchor isn’t a MGLConstantStyleValue.");
+ NSValue *anchorValue = ((MGLConstantStyleValue *)mglLight.anchor).rawValue;
+ XCTAssertEqual(anchorValue.MGLLightAnchorValue, MGLLightAnchorViewport);
+ XCTAssertEqual(mglLight.anchorTransition.delay, defaultTransition.delay);
+ XCTAssertEqual(mglLight.anchorTransition.duration, defaultTransition.duration);
+
+ auto lightFromMGLlight = [mglLight mbglLight];
+
+ XCTAssertEqual(light.getDefaultAnchor(), lightFromMGLlight.getAnchor().asConstant());
+ auto anchorTransition = lightFromMGLlight.getAnchorTransition();
+ XCTAssert(anchorTransition.delay && MGLTimeIntervalFromDuration(*anchorTransition.delay) == defaultTransition.delay);
+ XCTAssert(anchorTransition.duration && MGLTimeIntervalFromDuration(*anchorTransition.duration) == defaultTransition.duration);
+
+ MGLStyleValue<NSValue *> *anchorStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLightAnchor:MGLLightAnchorMap]];
+ mglLight.anchor = anchorStyleValue;
+ mglLight.anchorTransition = transition;
+ NSAssert([mglLight.anchor isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.anchor isn’t a MGLConstantStyleValue.");
+ anchorValue = ((MGLConstantStyleValue *)mglLight.anchor).rawValue;
+
+ XCTAssertEqual(anchorValue.MGLLightAnchorValue, MGLLightAnchorMap);
+ XCTAssertEqual(mglLight.anchorTransition.delay, transition.delay);
+ XCTAssertEqual(mglLight.anchorTransition.duration, transition.duration);
+
+ mbgl::style::PropertyValue<mbgl::style::LightAnchorType> anchorProperty = { mbgl::style::LightAnchorType::Map };
+ light.setAnchor(anchorProperty);
+ light.setAnchorTransition(transitionOptions);
+
+ lightFromMGLlight = [mglLight mbglLight];
+
+ XCTAssertEqual(light.getAnchor().asConstant(), lightFromMGLlight.getAnchor().asConstant());
+ anchorTransition = lightFromMGLlight.getAnchorTransition();
+ XCTAssert(anchorTransition.delay && MGLTimeIntervalFromDuration(*anchorTransition.delay) == transition.delay);
+ XCTAssert(anchorTransition.duration && MGLTimeIntervalFromDuration(*anchorTransition.duration) == transition.duration);
+
+ }
+
+ // position
+ {
+ mbgl::style::Light light;
+ MGLLight *mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
+ NSAssert([mglLight.position isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.position isn’t a MGLConstantStyleValue.");
+ NSValue *positionValue = ((MGLConstantStyleValue *)mglLight.position).rawValue;
+ auto positionArray = light.getDefaultPosition().getSpherical();
+ MGLSphericalPosition defaultPosition = MGLSphericalPositionMake(positionArray[0], positionArray[1], positionArray[2]);
+
+ XCTAssert(defaultPosition.radial == positionValue.MGLSphericalPositionValue.radial);
+ XCTAssert(defaultPosition.azimuthal == positionValue.MGLSphericalPositionValue.azimuthal);
+ XCTAssert(defaultPosition.polar == positionValue.MGLSphericalPositionValue.polar);
+ XCTAssertEqual(mglLight.positionTransiton.delay, defaultTransition.delay);
+ XCTAssertEqual(mglLight.positionTransiton.duration, defaultTransition.duration);
+
+ auto lightFromMGLlight = [mglLight mbglLight];
+
+ XCTAssertEqual(positionArray, lightFromMGLlight.getPosition().asConstant().getSpherical());
+ auto positionTransition = lightFromMGLlight.getPositionTransition();
+ XCTAssert(positionTransition.delay && MGLTimeIntervalFromDuration(*positionTransition.delay) == defaultTransition.delay);
+ XCTAssert(positionTransition.duration && MGLTimeIntervalFromDuration(*positionTransition.duration) == defaultTransition.duration);
+
+ defaultPosition = MGLSphericalPositionMake(6, 180, 90);
+ MGLStyleValue<NSValue *> *positionStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLSphericalPosition:defaultPosition]];
+ mglLight.position = positionStyleValue;
+ mglLight.positionTransiton = transition;
+
+ NSAssert([mglLight.position isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.position isn’t a MGLConstantStyleValue.");
+ positionValue = ((MGLConstantStyleValue *)mglLight.position).rawValue;
+
+ XCTAssert(defaultPosition.radial == positionValue.MGLSphericalPositionValue.radial);
+ XCTAssert(defaultPosition.azimuthal == positionValue.MGLSphericalPositionValue.azimuthal);
+ XCTAssert(defaultPosition.polar == positionValue.MGLSphericalPositionValue.polar);
+ XCTAssertEqual(mglLight.positionTransiton.delay, transition.delay);
+ XCTAssertEqual(mglLight.positionTransiton.duration, transition.duration);
+
+ lightFromMGLlight = [mglLight mbglLight];
+
+ positionArray = { { 6, 180, 90 } };
+ mbgl::style::Position position = { positionArray };
+ mbgl::style::PropertyValue<mbgl::style::Position> positionProperty = { position };
+ light.setPosition(positionProperty);
+ light.setPositionTransition(transitionOptions);
+
+ XCTAssertEqual(positionArray, lightFromMGLlight.getPosition().asConstant().getSpherical());
+ positionTransition = lightFromMGLlight.getPositionTransition();
+ XCTAssert(positionTransition.delay && MGLTimeIntervalFromDuration(*positionTransition.delay) == transition.delay);
+ XCTAssert(positionTransition.duration && MGLTimeIntervalFromDuration(*positionTransition.duration) == transition.duration);
+
+ }
+
+ // color
+ {
+ mbgl::style::Light light;
+ MGLLight *mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
+ NSAssert([mglLight.color isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.color isn’t a MGLConstantStyleValue.");
+ MGLColor *colorValue = ((MGLConstantStyleValue *)mglLight.color).rawValue;
+ auto color = light.getDefaultColor();
+ const CGFloat *colorComponents = CGColorGetComponents(colorValue.CGColor);
+
+ XCTAssert(color.r == colorComponents[0] && color.g == colorComponents[1] && color.b == colorComponents[2] &&
+ color.a == colorComponents[3]);
+ XCTAssertEqual(mglLight.colorTransiton.delay, defaultTransition.delay);
+ XCTAssertEqual(mglLight.colorTransiton.duration, defaultTransition.duration);
+
+ auto lightFromMGLlight = [mglLight mbglLight];
+
+ XCTAssertEqual(color, lightFromMGLlight.getColor().asConstant());
+ auto colorTransition = lightFromMGLlight.getColorTransition();
+ XCTAssert(colorTransition.delay && MGLTimeIntervalFromDuration(*colorTransition.delay) == defaultTransition.delay);
+ XCTAssert(colorTransition.duration && MGLTimeIntervalFromDuration(*colorTransition.duration) == defaultTransition.duration);
+
+ MGLStyleValue<MGLColor *> *colorStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor blackColor]];
+ mglLight.color = colorStyleValue;
+ mglLight.colorTransiton = transition;
+
+ NSAssert([mglLight.color isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.color isn’t a MGLConstantStyleValue.");
+ colorValue = ((MGLConstantStyleValue *)mglLight.color).rawValue;
+
+ XCTAssertEqual([MGLColor blackColor], colorValue);
+ XCTAssertEqual(mglLight.colorTransiton.delay, transition.delay);
+ XCTAssertEqual(mglLight.colorTransiton.duration, transition.duration);
+
+ mbgl::style::PropertyValue<mbgl::Color> colorProperty = { { 0, 0, 0, 1 } };
+ light.setColor(colorProperty);
+ light.setColorTransition(transitionOptions);
+
+ lightFromMGLlight = [mglLight mbglLight];
+
+ colorComponents = CGColorGetComponents(colorValue.CGColor);
+ color = lightFromMGLlight.getColor().asConstant();
+ XCTAssertEqual(light.getColor().asConstant(),lightFromMGLlight.getColor().asConstant());
+ colorTransition = lightFromMGLlight.getColorTransition();
+ XCTAssert(colorTransition.delay && MGLTimeIntervalFromDuration(*colorTransition.delay) == transition.delay);
+ XCTAssert(colorTransition.duration && MGLTimeIntervalFromDuration(*colorTransition.duration) == transition.duration);
+ }
+
+ // intensity
+ {
+ mbgl::style::Light light;
+ MGLLight *mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
+ NSAssert([mglLight.intensity isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.intensity isn’t a MGLConstantStyleValue.");
+ NSNumber *intensityNumber = ((MGLConstantStyleValue *)mglLight.intensity).rawValue;
+ auto intensity = light.getDefaultIntensity();
+
+ XCTAssert(intensityNumber.floatValue == intensity);
+ XCTAssertEqual(mglLight.intensityTransition.delay, defaultTransition.delay);
+ XCTAssertEqual(mglLight.intensityTransition.duration, defaultTransition.duration);
+
+ auto lightFromMGLlight = [mglLight mbglLight];
+
+ XCTAssertEqual(intensity, lightFromMGLlight.getIntensity().asConstant());
+ auto intensityTransition = lightFromMGLlight.getIntensityTransition();
+ XCTAssert(intensityTransition.delay && MGLTimeIntervalFromDuration(*intensityTransition.delay) == defaultTransition.delay);
+ XCTAssert(intensityTransition.duration && MGLTimeIntervalFromDuration(*intensityTransition.duration) == defaultTransition.duration);
+
+ NSNumber *intensityValue = @0.4;
+ MGLStyleValue<NSNumber *> *intensityStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:intensityValue];
+ mglLight.intensity = intensityStyleValue;
+ mglLight.intensityTransition = transition;
+
+ NSAssert([mglLight.intensity isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.intensity isn’t a MGLConstantStyleValue.");
+ intensityNumber = ((MGLConstantStyleValue *)mglLight.intensity).rawValue;
+ XCTAssert(intensityNumber.floatValue == intensityValue.floatValue);
+ XCTAssertEqual(mglLight.intensityTransition.delay, transition.delay);
+ XCTAssertEqual(mglLight.intensityTransition.duration, transition.duration);
+
+ mbgl::style::PropertyValue<float> intensityProperty = { 0.4 };
+ light.setIntensity(intensityProperty);
+ light.setIntensityTransition(transitionOptions);
+
+ lightFromMGLlight = [mglLight mbglLight];
+
+ XCTAssertEqual(light.getIntensity().asConstant(), lightFromMGLlight.getIntensity().asConstant());
+ intensityTransition = lightFromMGLlight.getIntensityTransition();
+ XCTAssert(intensityTransition.delay && MGLTimeIntervalFromDuration(*intensityTransition.delay) == transition.delay);
+ XCTAssert(intensityTransition.duration && MGLTimeIntervalFromDuration(*intensityTransition.duration) == transition.duration);
+
+ }
+
+}
+
+- (void)testValueAdditions {
+ MGLSphericalPosition position = MGLSphericalPositionMake(1.15, 210, 30);
+
+ XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.radial, position.radial);
+ XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.azimuthal, position.azimuthal);
+ XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.polar, position.polar);
+ XCTAssertEqual([NSValue valueWithMGLLightAnchor:MGLLightAnchorMap].MGLLightAnchorValue, MGLLightAnchorMap);
+ XCTAssertEqual([NSValue valueWithMGLLightAnchor:MGLLightAnchorViewport].MGLLightAnchorValue, MGLLightAnchorViewport);
+}
+
+@end