summaryrefslogtreecommitdiff
path: root/platform/darwin
diff options
context:
space:
mode:
authorFabian Guerra <fabian.guerra@mapbox.com>2017-08-28 12:43:29 -0400
committerFabian Guerra <fabian.guerra@mapbox.com>2017-08-28 12:43:29 -0400
commitacfe485302d4356ace93b1ca4a0dcbb9554e08a5 (patch)
tree6a8f18343cd1856be59d4de06a00034b27e95816 /platform/darwin
parentc6ab20e5c69c3705422e49c3511faf3e5ab79b05 (diff)
parent001988fba1e6eb2f6db2acdb68f26d583c48f53a (diff)
downloadqtlocation-mapboxgl-acfe485302d4356ace93b1ca4a0dcbb9554e08a5.tar.gz
Merge tag 'ios-v3.6.2' into master
# Conflicts: # cmake/core-files.cmake # include/mbgl/renderer/renderer_backend.hpp # platform/android/CHANGELOG.md # platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java # platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java # platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java # platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java # platform/android/dependencies.gradle # platform/darwin/src/MGLStyle.mm # platform/ios/CHANGELOG.md # platform/ios/app/Info.plist # platform/ios/app/MBXViewController.m # platform/ios/ios.xcodeproj/project.pbxproj # platform/macos/CHANGELOG.md # src/mbgl/gl/attribute.cpp # src/mbgl/gl/attribute.hpp # src/mbgl/gl/context.hpp # src/mbgl/gl/types.hpp # src/mbgl/gl/value.cpp # src/mbgl/gl/value.hpp # src/mbgl/map/backend_scope.cpp # src/mbgl/programs/attributes.hpp # src/mbgl/programs/program.hpp # src/mbgl/programs/segment.cpp # src/mbgl/programs/segment.hpp # src/mbgl/programs/symbol_program.hpp # src/mbgl/programs/uniforms.hpp # src/mbgl/renderer/buckets/symbol_bucket.hpp # src/mbgl/renderer/painter.cpp # src/mbgl/renderer/painter.hpp # src/mbgl/renderer/painter_background.cpp # src/mbgl/renderer/painter_circle.cpp # src/mbgl/renderer/painter_clipping.cpp # src/mbgl/renderer/painter_debug.cpp # src/mbgl/renderer/painter_fill.cpp # src/mbgl/renderer/painter_fill_extrusion.cpp # src/mbgl/renderer/painter_line.cpp # src/mbgl/renderer/painter_raster.cpp # src/mbgl/renderer/painter_symbol.cpp # src/mbgl/shaders/line.cpp # src/mbgl/shaders/line_pattern.cpp # test/renderer/backend_scope.test.cpp
Diffstat (limited to 'platform/darwin')
-rw-r--r--platform/darwin/docs/guides/Working with GeoJSON Data.md6
-rw-r--r--platform/darwin/resources/fr.lproj/Foundation.strings291
-rw-r--r--platform/darwin/src/MGLFeature.h14
-rw-r--r--platform/darwin/src/MGLFeature.mm49
-rw-r--r--platform/darwin/src/MGLPolygon.mm10
-rw-r--r--platform/darwin/src/MGLPolyline.h14
-rw-r--r--platform/darwin/src/MGLPolyline.mm10
-rw-r--r--platform/darwin/src/MGLShapeSource.mm4
-rw-r--r--platform/darwin/src/MGLSource.mm27
-rw-r--r--platform/darwin/src/MGLSource_Private.h25
-rw-r--r--platform/darwin/src/MGLStyle.h15
-rw-r--r--platform/darwin/src/MGLStyle.mm151
-rw-r--r--platform/darwin/src/MGLVectorSource+MGLAdditions.h15
-rw-r--r--platform/darwin/src/MGLVectorSource+MGLAdditions.m53
-rw-r--r--platform/darwin/src/MGLVectorSource.mm4
-rw-r--r--platform/darwin/test/MGLDocumentationExampleTests.swift12
16 files changed, 656 insertions, 44 deletions
diff --git a/platform/darwin/docs/guides/Working with GeoJSON Data.md b/platform/darwin/docs/guides/Working with GeoJSON Data.md
index 57aaa3855d..f3b3dc0918 100644
--- a/platform/darwin/docs/guides/Working with GeoJSON Data.md
+++ b/platform/darwin/docs/guides/Working with GeoJSON Data.md
@@ -81,8 +81,10 @@ Linear ring | `MGLPolygon.coordinates`, `MGLPolygon.interiorPolygons`
A `Feature` object in GeoJSON corresponds to an instance of an `MGLShape`
subclass conforming to the `MGLFeature` protocol. There is a distinct
`MGLFeature`-conforming class for each type of geometry that a GeoJSON feature
-can contain. This allows features to be used as shapes where convenient. For
-example, some features can be added to a map view as annotations.
+can contain. This allows features to be used as raw shapes where convenient. For
+example, some features can be added to a map view as annotations. Note that
+identifiers and attributes will not be available for feature querying when a
+feature is used as an annotation.
In contrast to the GeoJSON standard, it is possible for `MGLShape` subclasses
other than `MGLPointAnnotation` to straddle the antimeridian.
diff --git a/platform/darwin/resources/fr.lproj/Foundation.strings b/platform/darwin/resources/fr.lproj/Foundation.strings
new file mode 100644
index 0000000000..d2f6c1f6df
--- /dev/null
+++ b/platform/darwin/resources/fr.lproj/Foundation.strings
@@ -0,0 +1,291 @@
+/* Clock position format, long: {hours} o’clock */
+"CLOCK_FMT_LONG" = "%@ heures";
+
+/* Clock position format, medium: {hours} o’clock */
+"CLOCK_FMT_MEDIUM" = "%@ heures";
+
+/* Clock position format, short: {hours}:00 */
+"CLOCK_FMT_SHORT" = "%@h 00";
+
+/* East, long */
+"COMPASS_E_LONG" = "est";
+
+/* East, short */
+"COMPASS_E_SHORT" = "E";
+
+/* East by north, long */
+"COMPASS_EbN_LONG" = "est par nord";
+
+/* East by north, short */
+"COMPASS_EbN_SHORT" = "EpN";
+
+/* East by south, long */
+"COMPASS_EbS_LONG" = "est par sud";
+
+/* East by south, short */
+"COMPASS_EbS_SHORT" = "EpS";
+
+/* East-northeast, long */
+"COMPASS_ENE_LONG" = "est-nord-est";
+
+/* East-northeast, short */
+"COMPASS_ENE_SHORT" = "ENE";
+
+/* East-southeast, long */
+"COMPASS_ESE_LONG" = "est-sud-est";
+
+/* East-southeast, short */
+"COMPASS_ESE_SHORT" = "ESE";
+
+/* North, long */
+"COMPASS_N_LONG" = "nord";
+
+/* North, short */
+"COMPASS_N_SHORT" = "N";
+
+/* North by east, long */
+"COMPASS_NbE_LONG" = "nord par est";
+
+/* North by east, short */
+"COMPASS_NbE_SHORT" = "NpE";
+
+/* North by west, long */
+"COMPASS_NbW_LONG" = "nord par ouest";
+
+/* North by west, short */
+"COMPASS_NbW_SHORT" = "NpO";
+
+/* Northeast, long */
+"COMPASS_NE_LONG" = "nord-est";
+
+/* Northeast, short */
+"COMPASS_NE_SHORT" = "NE";
+
+/* Northeast by east, long */
+"COMPASS_NEbE_LONG" = "nord-est par est";
+
+/* Northeast by east, short */
+"COMPASS_NEbE_SHORT" = "NEpE";
+
+/* Northeast by north, long */
+"COMPASS_NEbN_LONG" = "nord-est par nord";
+
+/* Northeast by north, short */
+"COMPASS_NEbN_SHORT" = "NEpN";
+
+/* North-northeast, long */
+"COMPASS_NNE_LONG" = "nord-nord-est";
+
+/* North-northeast, short */
+"COMPASS_NNE_SHORT" = "NNE";
+
+/* North-northwest, long */
+"COMPASS_NNW_LONG" = "nord-nord-ouest";
+
+/* North-northwest, short */
+"COMPASS_NNW_SHORT" = "NNO";
+
+/* Northwest, long */
+"COMPASS_NW_LONG" = "nord-ouest";
+
+/* Northwest, short */
+"COMPASS_NW_SHORT" = "NO";
+
+/* Northwest by north, long */
+"COMPASS_NWbN_LONG" = "nord-ouest par nord";
+
+/* Northwest by north, short */
+"COMPASS_NWbN_SHORT" = "NOpN";
+
+/* Northwest by west, long */
+"COMPASS_NWbW_LONG" = "nord-ouest par ouest";
+
+/* Northwest by west, short */
+"COMPASS_NWbW_SHORT" = "NOpO";
+
+/* South, long */
+"COMPASS_S_LONG" = "sud";
+
+/* South, short */
+"COMPASS_S_SHORT" = "S";
+
+/* South by east, long */
+"COMPASS_SbE_LONG" = "sud par est";
+
+/* South by east, short */
+"COMPASS_SbE_SHORT" = "SpE";
+
+/* South by west, long */
+"COMPASS_SbW_LONG" = "sud par ouest";
+
+/* South by west, short */
+"COMPASS_SbW_SHORT" = "SpO";
+
+/* Southeast, long */
+"COMPASS_SE_LONG" = "sud-est";
+
+/* Southeast, short */
+"COMPASS_SE_SHORT" = "SE";
+
+/* Southeast by east, long */
+"COMPASS_SEbE_LONG" = "sud-est par est";
+
+/* Southeast by east, short */
+"COMPASS_SEbE_SHORT" = "SEpE";
+
+/* Southeast by south, long */
+"COMPASS_SEbS_LONG" = "sud-est par sud";
+
+/* Southeast by south, short */
+"COMPASS_SEbS_SHORT" = "SEpS";
+
+/* South-southeast, long */
+"COMPASS_SSE_LONG" = "sud-sud-est";
+
+/* South-southeast, short */
+"COMPASS_SSE_SHORT" = "SSE";
+
+/* South-southwest, long */
+"COMPASS_SSW_LONG" = "sud-sud-ouest";
+
+/* South-southwest, short */
+"COMPASS_SSW_SHORT" = "SSO";
+
+/* Southwest, long */
+"COMPASS_SW_LONG" = "sud-ouest";
+
+/* Southwest, short */
+"COMPASS_SW_SHORT" = "SO";
+
+/* Southwest by south, long */
+"COMPASS_SWbS_LONG" = "sud-ouest par sud";
+
+/* Southwest by south, short */
+"COMPASS_SWbS_SHORT" = "SOpS";
+
+/* Southwest by west, long */
+"COMPASS_SWbW_LONG" = "sud-ouest par ouest";
+
+/* Southwest by west, short */
+"COMPASS_SWbW_SHORT" = "SOpO";
+
+/* West, long */
+"COMPASS_W_LONG" = "ouest";
+
+/* West, short */
+"COMPASS_W_SHORT" = "O";
+
+/* West by north, long */
+"COMPASS_WbN_LONG" = "ouest par nord";
+
+/* West by north, short */
+"COMPASS_WbN_SHORT" = "OpN";
+
+/* West by south, long */
+"COMPASS_WbS_LONG" = "ouest par sud";
+
+/* West by south, short */
+"COMPASS_WbS_SHORT" = "OpS";
+
+/* West-northwest, long */
+"COMPASS_WNW_LONG" = "ouest-nord-ouest";
+
+/* West-northwest, short */
+"COMPASS_WNW_SHORT" = "ONO";
+
+/* West-southwest, long */
+"COMPASS_WSW_LONG" = "ouest-sud-ouest";
+
+/* West-southwest, short */
+"COMPASS_WSW_SHORT" = "OSO";
+
+/* Degrees format, long */
+"COORD_DEG_LONG" = "%d degré(s)";
+
+/* Degrees format, medium: {degrees} */
+"COORD_DEG_MEDIUM" = "%d°";
+
+/* Degrees format, short: {degrees} */
+"COORD_DEG_SHORT" = "%d°";
+
+/* Coordinate format, long: {degrees}{minutes} */
+"COORD_DM_LONG" = "%1$@ et %2$@";
+
+/* Coordinate format, medium: {degrees}{minutes} */
+"COORD_DM_MEDIUM" = "%1$@%2$@";
+
+/* Coordinate format, short: {degrees}{minutes} */
+"COORD_DM_SHORT" = "%1$@%2$@";
+
+/* Coordinate format, long: {degrees}{minutes}{seconds} */
+"COORD_DMS_LONG" = "%1$@, %2$@ et %3$@";
+
+/* Coordinate format, medium: {degrees}{minutes}{seconds} */
+"COORD_DMS_MEDIUM" = "%1$@%2$@%3$@";
+
+/* Coordinate format, short: {degrees}{minutes}{seconds} */
+"COORD_DMS_SHORT" = "%1$@%2$@%3$@";
+
+/* East longitude format, long: {longitude} */
+"COORD_E_LONG" = "%@ est";
+
+/* East longitude format, medium: {longitude} */
+"COORD_E_MEDIUM" = "%@ est";
+
+/* East longitude format, short: {longitude} */
+"COORD_E_SHORT" = "%@E";
+
+/* Coordinate pair format, long: {latitude}, {longitude} */
+"COORD_FMT_LONG" = "%1$@, %2$@";
+
+/* Coordinate pair format, medium: {latitude}, {longitude} */
+"COORD_FMT_MEDIUM" = "%1$@, %2$@";
+
+/* Coordinate pair format, short: {latitude}, {longitude} */
+"COORD_FMT_SHORT" = "%1$@, %2$@";
+
+/* Minutes format, long */
+"COORD_MIN_LONG" = "%d minute(s)";
+
+/* Minutes format, medium: {minutes} */
+"COORD_MIN_MEDIUM" = "%d′";
+
+/* Minutes format, short: {minutes} */
+"COORD_MIN_SHORT" = "%d′";
+
+/* North latitude format, long: {latitude} */
+"COORD_N_LONG" = "%@ nord";
+
+/* North latitude format, medium: {latitude} */
+"COORD_N_MEDIUM" = "%@ nord";
+
+/* North latitude format, short: {latitude} */
+"COORD_N_SHORT" = "%@N";
+
+/* South latitude format, long: {latitude} */
+"COORD_S_LONG" = "%@ sud";
+
+/* South latitude format, medium: {latitude} */
+"COORD_S_MEDIUM" = "%@ sud";
+
+/* South latitude format, short: {latitude} */
+"COORD_S_SHORT" = "%@S";
+
+/* Seconds format, long */
+"COORD_SEC_LONG" = "%d seconde(s)";
+
+/* Seconds format, medium: {seconds} */
+"COORD_SEC_MEDIUM" = "%d″";
+
+/* Seconds format, short: {seconds} */
+"COORD_SEC_SHORT" = "%d″";
+
+/* West longitude format, long: {longitude} */
+"COORD_W_LONG" = "%@ ouest";
+
+/* West longitude format, medium: {longitude} */
+"COORD_W_MEDIUM" = "%@ ouest";
+
+/* West longitude format, short: {longitude} */
+"COORD_W_SHORT" = "%@O";
+
diff --git a/platform/darwin/src/MGLFeature.h b/platform/darwin/src/MGLFeature.h
index 491c89b608..a13821cf96 100644
--- a/platform/darwin/src/MGLFeature.h
+++ b/platform/darwin/src/MGLFeature.h
@@ -18,15 +18,23 @@ NS_ASSUME_NONNULL_BEGIN
You can add custom data to display on the map by creating feature objects and
adding them to an `MGLShapeSource` using the
`-[MGLShapeSource initWithIdentifier:shape:options:]` method or
- `MGLShapeSource.shape` property. Similarly, you can add `MGLPointFeature`,
- `MGLPolylineFeature`, and `MGLPolygonFeature` objects to the map as annotations
- using `-[MGLMapView addAnnotations:]` and related methods.
+ `MGLShapeSource.shape` property.
In addition to adding data to the map, you can also extract data from the map:
`-[MGLMapView visibleFeaturesAtPoint:]` and related methods return feature
objects that correspond to features in the source. This enables you to inspect
the properties of features in vector tiles loaded by `MGLVectorSource` objects.
You also reuse these feature objects as overlay annotations.
+
+ While it is possible to add `MGLFeature`-conforming objects to the map as
+ annotations using `-[MGLMapView addAnnotations:]` and related methods, doing so
+ has trade-offs:
+
+ - Features added as annotations will not have `identifier` or `attributes`
+ properties when used with feature querying.
+
+ - Features added as annotations become interactive. Taps and selection can be
+ handled in `-[MGLMapViewDelegate mapView:didSelectAnnotation:]`.
*/
@protocol MGLFeature <MGLAnnotation>
diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm
index e169ee19bb..84f1a1ff25 100644
--- a/platform/darwin/src/MGLFeature.mm
+++ b/platform/darwin/src/MGLFeature.mm
@@ -42,6 +42,15 @@ MGL_DEFINE_FEATURE_IS_EQUAL();
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}
+- (NSString *)description
+{
+ return [NSString stringWithFormat:@"<%@: %p; identifier = %@, coordinate = %f, %f, attributes = %@>",
+ NSStringFromClass([self class]), (void *)self,
+ self.identifier ? [NSString stringWithFormat:@"\"%@\"", self.identifier] : self.identifier,
+ self.coordinate.latitude, self.coordinate.longitude,
+ self.attributes.count ? self.attributes : @"none"];
+}
+
@end
@interface MGLPolylineFeature ()
@@ -68,6 +77,16 @@ MGL_DEFINE_FEATURE_IS_EQUAL();
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}
+- (NSString *)description
+{
+ return [NSString stringWithFormat:@"<%@: %p; identifier = %@, count = %lu, bounds = %@, attributes = %@>",
+ NSStringFromClass([self class]), (void *)self,
+ self.identifier ? [NSString stringWithFormat:@"\"%@\"", self.identifier] : self.identifier,
+ (unsigned long)[self pointCount],
+ MGLStringFromCoordinateBounds(self.overlayBounds),
+ self.attributes.count ? self.attributes : @"none"];
+}
+
@end
@interface MGLPolygonFeature ()
@@ -94,6 +113,16 @@ MGL_DEFINE_FEATURE_IS_EQUAL();
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}
+- (NSString *)description
+{
+ return [NSString stringWithFormat:@"<%@: %p; identifier = %@, count = %lu, bounds = %@, attributes = %@>",
+ NSStringFromClass([self class]), (void *)self,
+ self.identifier ? [NSString stringWithFormat:@"\"%@\"", self.identifier] : self.identifier,
+ (unsigned long)[self pointCount],
+ MGLStringFromCoordinateBounds(self.overlayBounds),
+ self.attributes.count ? self.attributes : @"none"];
+}
+
@end
@interface MGLPointCollectionFeature ()
@@ -146,6 +175,16 @@ MGL_DEFINE_FEATURE_IS_EQUAL();
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}
+- (NSString *)description
+{
+ return [NSString stringWithFormat:@"<%@: %p; identifier = %@, count = %lu, bounds = %@, attributes = %@>",
+ NSStringFromClass([self class]), (void *)self,
+ self.identifier ? [NSString stringWithFormat:@"\"%@\"", self.identifier] : self.identifier,
+ (unsigned long)self.polylines.count,
+ MGLStringFromCoordinateBounds(self.overlayBounds),
+ self.attributes.count ? self.attributes : @"none"];
+}
+
@end
@interface MGLMultiPolygonFeature ()
@@ -172,6 +211,16 @@ MGL_DEFINE_FEATURE_IS_EQUAL();
return mbglFeature({[self geometryObject]}, identifier, self.attributes);
}
+- (NSString *)description
+{
+ return [NSString stringWithFormat:@"<%@: %p; identifier = %@, count = %lu, bounds = %@, attributes = %@>",
+ NSStringFromClass([self class]), (void *)self,
+ self.identifier ? [NSString stringWithFormat:@"\"%@\"", self.identifier] : self.identifier,
+ (unsigned long)self.polygons.count,
+ MGLStringFromCoordinateBounds(self.overlayBounds),
+ self.attributes.count ? self.attributes : @"none"];
+}
+
@end
@interface MGLShapeCollectionFeature ()
diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm
index d966ff13ce..e7843224e9 100644
--- a/platform/darwin/src/MGLPolygon.mm
+++ b/platform/darwin/src/MGLPolygon.mm
@@ -200,4 +200,14 @@
@"coordinates": coordinates};
}
+- (NSString *)description
+{
+ return [NSString stringWithFormat:@"<%@: %p; title = %@, subtitle: = %@, count = %lu; bounds = %@>",
+ NSStringFromClass([self class]), (void *)self,
+ self.title ? [NSString stringWithFormat:@"\"%@\"", self.title] : self.title,
+ self.subtitle ? [NSString stringWithFormat:@"\"%@\"", self.subtitle] : self.subtitle,
+ (unsigned long)self.polygons.count,
+ MGLStringFromCoordinateBounds(self.overlayBounds)];
+}
+
@end
diff --git a/platform/darwin/src/MGLPolyline.h b/platform/darwin/src/MGLPolyline.h
index b3db0fd39f..e46baa91cc 100644
--- a/platform/darwin/src/MGLPolyline.h
+++ b/platform/darwin/src/MGLPolyline.h
@@ -33,8 +33,18 @@ NS_ASSUME_NONNULL_BEGIN
`MGLPolygon` object. To group multiple polylines together in one shape, use an
`MGLMultiPolyline` or `MGLShapeCollection` object.
- To make the polyline straddle the antimeridian, specify some longitudes less
- than −180 degrees or greater than 180 degrees.
+ To make the polyline go across the antimeridian or international date line,
+ specify some longitudes less than −180 degrees or greater than 180 degrees.
+ For example, a polyline that stretches from Tokyo to San Francisco would have
+ coordinates of (35.68476, -220.24257) and (37.78428, -122.41310).
+
+ ```swift
+ let coordinates = [
+ CLLocationCoordinate2D(latitude: 35.68476, longitude: -220.24257),
+ CLLocationCoordinate2D(latitude: 37.78428, longitude: -122.41310)
+ ]
+ let polyline = MGLPolyline(coordinates: coordinates, count: UInt(coordinates.count))
+ ```
A polyline is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.4">LineString</a>
diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm
index fd75dc2795..0e371a4dda 100644
--- a/platform/darwin/src/MGLPolyline.mm
+++ b/platform/darwin/src/MGLPolyline.mm
@@ -201,4 +201,14 @@
@"coordinates": coordinates};
}
+- (NSString *)description
+{
+ return [NSString stringWithFormat:@"<%@: %p; title = %@, subtitle: = %@, count = %lu; bounds = %@>",
+ NSStringFromClass([self class]), (void *)self,
+ self.title ? [NSString stringWithFormat:@"\"%@\"", self.title] : self.title,
+ self.subtitle ? [NSString stringWithFormat:@"\"%@\"", self.subtitle] : self.subtitle,
+ (unsigned long)self.polylines.count,
+ MGLStringFromCoordinateBounds(self.overlayBounds)];
+}
+
@end
diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm
index f02fc98ded..571cbdcc62 100644
--- a/platform/darwin/src/MGLShapeSource.mm
+++ b/platform/darwin/src/MGLShapeSource.mm
@@ -98,8 +98,8 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh
}
std::vector<mbgl::Feature> features;
- if (self.style) {
- features = self.style.mapView.renderer->querySourceFeatures(self.rawSource->getID(), { {}, optionalFilter });
+ if (self.mapView) {
+ features = self.mapView.renderer->querySourceFeatures(self.rawSource->getID(), { {}, optionalFilter });
}
return MGLFeaturesFromMBGLFeatures(features);
}
diff --git a/platform/darwin/src/MGLSource.mm b/platform/darwin/src/MGLSource.mm
index ee012f4d66..6d57e14e8c 100644
--- a/platform/darwin/src/MGLSource.mm
+++ b/platform/darwin/src/MGLSource.mm
@@ -1,7 +1,9 @@
#import "MGLSource_Private.h"
#import "MGLStyle_Private.h"
+#import "MGLMapView_Private.h"
#include <mbgl/style/style.hpp>
+#include <mbgl/map/map.hpp>
#include <mbgl/style/source.hpp>
@interface MGLSource ()
@@ -10,7 +12,7 @@
// special internal source types like mbgl::AnnotationSource.
@property (nonatomic, readonly) mbgl::style::Source *rawSource;
-@property (nonatomic, readonly, weak) MGLStyle *style;
+@property (nonatomic, readonly, weak) MGLMapView *mapView;
@end
@@ -27,37 +29,38 @@
return self;
}
-- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource {
+- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource mapView:(MGLMapView *)mapView {
NSString *identifier = @(rawSource->getID().c_str());
if (self = [self initWithIdentifier:identifier]) {
_rawSource = rawSource;
_rawSource->peer = SourceWrapper { self };
+ _mapView = mapView;
}
return self;
}
- (instancetype)initWithPendingSource:(std::unique_ptr<mbgl::style::Source>)pendingSource {
- if (self = [self initWithRawSource:pendingSource.get()]) {
+ if (self = [self initWithRawSource:pendingSource.get() mapView:nil]) {
_pendingSource = std::move(pendingSource);
}
return self;
}
-- (void)addToStyle:(MGLStyle *)style {
+- (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, style];
+ "to the style more than once is invalid.", self, mapView.style];
}
-
- _style = style;
- style.rawStyle->addSource(std::move(_pendingSource));
+
+ _mapView = mapView;
+ _mapView.style.rawStyle->addSource(std::move(_pendingSource));
}
-- (void)removeFromStyle:(MGLStyle *)style {
- if (self.rawSource == style.rawStyle->getSource(self.identifier.UTF8String)) {
- _pendingSource = style.rawStyle->removeSource(self.identifier.UTF8String);
- _style = nil;
+- (void)removeFromMapView:(MGLMapView *)mapView {
+ if (self.rawSource == mapView.style.rawStyle->getSource(self.identifier.UTF8String)) {
+ _pendingSource = mapView.style.rawStyle->removeSource(self.identifier.UTF8String);
+ _mapView = nil;
}
}
diff --git a/platform/darwin/src/MGLSource_Private.h b/platform/darwin/src/MGLSource_Private.h
index ba78973279..d7d1f66641 100644
--- a/platform/darwin/src/MGLSource_Private.h
+++ b/platform/darwin/src/MGLSource_Private.h
@@ -18,7 +18,7 @@ struct SourceWrapper {
__weak MGLSource *source;
};
-@class MGLStyle;
+@class MGLMapView;
@interface MGLSource (Private)
@@ -26,7 +26,7 @@ struct SourceWrapper {
Initializes and returns a source with a raw pointer to the backing store,
associated with a style.
*/
-- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource;
+- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource mapView:(nullable MGLMapView *)mapView;
/**
Initializes and returns a source with an owning pointer to the backing store,
@@ -44,33 +44,30 @@ struct SourceWrapper {
@property (nonatomic, readonly) mbgl::style::Source *rawSource;
/**
- The style which currently contains the source.
-
- If the source is not currently part of a style, this property is
+ The map view whose style currently contains the source.
+ If the source is not currently part of any map view’s style, this property is
set to `nil`.
*/
-@property (nonatomic, readonly, weak) MGLStyle *style;
+@property (nonatomic, readonly, weak) MGLMapView *mapView;
/**
- Adds the mbgl source that this object represents to the style.
-
+ Adds the mbgl source that this object represents to the mbgl map.
Once a mbgl source is added, ownership of the object is transferred to the
- `mbgl::Style` and this object no longer has an active unique_ptr reference to the
+ `mbgl::Map` and this object no longer has an active unique_ptr reference to the
`mbgl::Source`. If this object's mbgl source is in that state, the mbgl source
can still be changed but the changes will not be visible until the `MGLSource`
- is added back to the style via `-[MGLStyle addSource:]` and styled with a
+ is added back to the map via `-[MGLStyle addSource:]` and styled with a
`MGLLayer`.
*/
-- (void)addToStyle:(MGLStyle *)style;
+- (void)addToMapView:(MGLMapView *)mapView;
/**
- Removes the mbgl source that this object represents from the style.
-
+ Removes the mbgl source that this object represents from the mbgl map.
When a mbgl source is removed, ownership of the object is transferred back
to the `MGLSource` instance and the unique_ptr reference is valid again. It is
safe to add the source back to the style after it is removed.
*/
-- (void)removeFromStyle:(MGLStyle *)style;
+- (void)removeFromMapView:(MGLMapView *)mapView;
@end
diff --git a/platform/darwin/src/MGLStyle.h b/platform/darwin/src/MGLStyle.h
index 6fb4a6cc6b..98be70be9c 100644
--- a/platform/darwin/src/MGLStyle.h
+++ b/platform/darwin/src/MGLStyle.h
@@ -557,6 +557,21 @@ MGL_EXPORT
*/
@property (nonatomic, strong) MGLLight *light;
+#pragma mark Localizing Map Content
+
+/**
+ A Boolean value that determines whether the style attempts to localize labels in
+ the style into the system’s preferred language.
+
+ When this property is enabled, the style automatically modifies the text property
+ of any symbol style layer whose source is the
+ <a href="https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview">Mapbox
+ Streets source</a>. On iOS, the user can set the system’s preferred language in
+ Settings, General Settings, Language & Region. On macOS, the user can set the
+ system’s preferred language in the Language & Region pane of System Preferences.
+ */
+@property (nonatomic) BOOL localizesLabels;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index 2365641f02..94f199fd21 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -17,6 +17,7 @@
#import "MGLLight_Private.h"
#import "MGLTileSource_Private.h"
#import "MGLVectorSource.h"
+#import "MGLVectorSource+MGLAdditions.h"
#import "MGLRasterSource.h"
#import "MGLShapeSource.h"
#import "MGLImageSource.h"
@@ -49,12 +50,35 @@
#import "NSImage+MGLAdditions.h"
#endif
+/**
+ Model class for localization changes.
+ */
+@interface MGLTextLanguage: NSObject
+@property (strong, nonatomic) NSString *originalTextField;
+@property (strong, nonatomic) NSString *updatedTextField;
+
+- (instancetype)initWithTextLanguage:(NSString *)originalTextField updatedTextField:(NSString *)updatedTextField;
+
+@end
+
+@implementation MGLTextLanguage
+- (instancetype)initWithTextLanguage:(NSString *)originalTextField updatedTextField:(NSString *)updatedTextField
+{
+ if (self = [super init]) {
+ _originalTextField = originalTextField;
+ _updatedTextField = updatedTextField;
+ }
+ return self;
+}
+@end
+
@interface MGLStyle()
@property (nonatomic, readonly, weak) MGLMapView *mapView;
@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
@property (readonly, copy, nullable) NSURL *URL;
@property (nonatomic, readwrite, strong) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLOpenGLStyleLayer *) *openGLLayers;
+@property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, NS_DICTIONARY_OF(NSObject *, MGLTextLanguage *) *) *localizedLayersByIdentifier;
@end
@@ -119,6 +143,7 @@ static NSURL *MGLStyleURL_emerald;
_mapView = mapView;
_rawStyle = rawStyle;
_openGLLayers = [NSMutableDictionary dictionary];
+ _localizedLayersByIdentifier = [NSMutableDictionary dictionary];
}
return self;
}
@@ -164,6 +189,7 @@ static NSURL *MGLStyleURL_emerald;
- (MGLSource *)sourceWithIdentifier:(NSString *)identifier
{
auto rawSource = self.rawStyle->getSource(identifier.UTF8String);
+
return rawSource ? [self sourceFromMBGLSource:rawSource] : nil;
}
@@ -175,15 +201,15 @@ static NSURL *MGLStyleURL_emerald;
// TODO: Fill in options specific to the respective source classes
// https://github.com/mapbox/mapbox-gl-native/issues/6584
if (auto vectorSource = rawSource->as<mbgl::style::VectorSource>()) {
- return [[MGLVectorSource alloc] initWithRawSource:vectorSource];
+ return [[MGLVectorSource alloc] initWithRawSource:vectorSource mapView:self.mapView];
} else if (auto geoJSONSource = rawSource->as<mbgl::style::GeoJSONSource>()) {
- return [[MGLShapeSource alloc] initWithRawSource:geoJSONSource];
+ return [[MGLShapeSource alloc] initWithRawSource:geoJSONSource mapView:self.mapView];
} else if (auto rasterSource = rawSource->as<mbgl::style::RasterSource>()) {
- return [[MGLRasterSource alloc] initWithRawSource:rasterSource];
+ return [[MGLRasterSource alloc] initWithRawSource:rasterSource mapView:self.mapView];
} else if (auto imageSource = rawSource->as<mbgl::style::ImageSource>()) {
- return [[MGLImageSource alloc] initWithRawSource:imageSource];
+ return [[MGLImageSource alloc] initWithRawSource:imageSource mapView:self.mapView];
} else {
- return [[MGLSource alloc] initWithRawSource:rawSource];
+ return [[MGLSource alloc] initWithRawSource:rawSource mapView:self.mapView];
}
}
@@ -197,7 +223,7 @@ static NSURL *MGLStyleURL_emerald;
}
try {
- [source addToStyle:self];
+ [source addToMapView:self.mapView];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantSourceIdentifierException" format:@"%s", err.what()];
}
@@ -211,7 +237,7 @@ static NSURL *MGLStyleURL_emerald;
@"Make sure the source was created as a member of a concrete subclass of MGLSource.",
source];
}
- [source removeFromStyle:self];
+ [source removeFromMapView:self.mapView];
}
- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
@@ -585,4 +611,115 @@ static NSURL *MGLStyleURL_emerald;
self.URL ? [NSString stringWithFormat:@"\"%@\"", self.URL] : self.URL];
}
+#pragma mark Style language preferences
+
+- (void)setLocalizesLabels:(BOOL)localizesLabels
+{
+ if (_localizesLabels != localizesLabels) {
+ _localizesLabels = localizesLabels;
+ } else {
+ return;
+ }
+
+ if (_localizesLabels) {
+ NSString *preferredLanguage = [MGLVectorSource preferredMapboxStreetsLanguage];
+ NSMutableDictionary *localizedKeysByKeyBySourceIdentifier = [NSMutableDictionary dictionary];
+ for (MGLSymbolStyleLayer *layer in self.layers) {
+ if (![layer isKindOfClass:[MGLSymbolStyleLayer class]]) {
+ continue;
+ }
+
+ MGLVectorSource *source = (MGLVectorSource *)[self sourceWithIdentifier:layer.sourceIdentifier];
+ if (![source isKindOfClass:[MGLVectorSource class]] || !source.mapboxStreets) {
+ continue;
+ }
+
+ NSDictionary *localizedKeysByKey = localizedKeysByKeyBySourceIdentifier[layer.sourceIdentifier];
+ if (!localizedKeysByKey) {
+ localizedKeysByKey = localizedKeysByKeyBySourceIdentifier[layer.sourceIdentifier] = [source localizedKeysByKeyForPreferredLanguage:preferredLanguage];
+ }
+
+ NSString *(^stringByLocalizingString)(NSString *) = ^ NSString * (NSString *string) {
+ NSMutableString *localizedString = string.mutableCopy;
+ [localizedKeysByKey enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull localizedKey, BOOL * _Nonnull stop) {
+ NSAssert([key isKindOfClass:[NSString class]], @"key is not a string");
+ NSAssert([localizedKey isKindOfClass:[NSString class]], @"localizedKey is not a string");
+ [localizedString replaceOccurrencesOfString:[NSString stringWithFormat:@"{%@}", key]
+ withString:[NSString stringWithFormat:@"{%@}", localizedKey]
+ options:0
+ range:NSMakeRange(0, localizedString.length)];
+ }];
+ return localizedString;
+ };
+
+ if ([layer.text isKindOfClass:[MGLConstantStyleValue class]]) {
+ NSString *textField = [(MGLConstantStyleValue<NSString *> *)layer.text rawValue];
+ NSString *localizingString = stringByLocalizingString(textField);
+ if (![textField isEqualToString:localizingString]) {
+ MGLTextLanguage *textLanguage = [[MGLTextLanguage alloc] initWithTextLanguage:textField
+ updatedTextField:localizingString];
+ [self.localizedLayersByIdentifier setObject:@{ textField : textLanguage } forKey:layer.identifier];
+ layer.text = [MGLStyleValue<NSString *> valueWithRawValue:localizingString];
+ }
+ }
+ else if ([layer.text isKindOfClass:[MGLCameraStyleFunction class]]) {
+ MGLCameraStyleFunction *function = (MGLCameraStyleFunction<NSString *> *)layer.text;
+ NSMutableDictionary *stops = function.stops.mutableCopy;
+ NSMutableDictionary *cameraStops = [NSMutableDictionary dictionary];
+ [stops enumerateKeysAndObjectsUsingBlock:^(NSNumber *zoomLevel, MGLConstantStyleValue<NSString *> *stop, BOOL *done) {
+ NSString *textField = stop.rawValue;
+ NSString *localizingString = stringByLocalizingString(textField);
+ if (![textField isEqualToString:localizingString]) {
+ MGLTextLanguage *textLanguage = [[MGLTextLanguage alloc] initWithTextLanguage:textField
+ updatedTextField:localizingString];
+ [cameraStops setObject:textLanguage forKey:zoomLevel];
+ stops[zoomLevel] = [MGLStyleValue<NSString *> valueWithRawValue:localizingString];
+ }
+
+ }];
+ if (cameraStops.count > 0) {
+ [self.localizedLayersByIdentifier setObject:cameraStops forKey:layer.identifier];
+ }
+ function.stops = stops;
+ layer.text = function;
+ }
+ }
+ } else {
+
+ [self.localizedLayersByIdentifier enumerateKeysAndObjectsUsingBlock:^(NSString *identifier, NSDictionary<NSObject *, MGLTextLanguage *> *textFields, BOOL *done) {
+ MGLSymbolStyleLayer *layer = (MGLSymbolStyleLayer *)[self.mapView.style layerWithIdentifier:identifier];
+
+ if ([layer.text isKindOfClass:[MGLConstantStyleValue class]]) {
+ NSString *textField = [(MGLConstantStyleValue<NSString *> *)layer.text rawValue];
+ [textFields enumerateKeysAndObjectsUsingBlock:^(NSObject *originalLanguage, MGLTextLanguage *textLanguage, BOOL *done) {
+ if ([textLanguage.updatedTextField isEqualToString:textField]) {
+ layer.text = [MGLStyleValue<NSString *> valueWithRawValue:textLanguage.originalTextField];
+ }
+ }];
+
+ }
+ else if ([layer.text isKindOfClass:[MGLCameraStyleFunction class]]) {
+ MGLCameraStyleFunction *function = (MGLCameraStyleFunction<NSString *> *)layer.text;
+ NSMutableDictionary *stops = function.stops.mutableCopy;
+ [textFields enumerateKeysAndObjectsUsingBlock:^(NSObject *zoomKey, MGLTextLanguage *textLanguage, BOOL *done) {
+ if ([zoomKey isKindOfClass:[NSNumber class]]) {
+ NSNumber *zoomLevel = (NSNumber*)zoomKey;
+ MGLConstantStyleValue<NSString *> *stop = [stops objectForKey:zoomLevel];
+ NSString *textField = stop.rawValue;
+ if ([textLanguage.updatedTextField isEqualToString:textField]) {
+ stops[zoomLevel] = [MGLStyleValue<NSString *> valueWithRawValue:textLanguage.originalTextField];
+ }
+ }
+ }];
+
+ function.stops = stops;
+ layer.text = function;
+ }
+
+ }];
+
+ self.localizedLayersByIdentifier = [NSMutableDictionary dictionary];
+ }
+}
+
@end
diff --git a/platform/darwin/src/MGLVectorSource+MGLAdditions.h b/platform/darwin/src/MGLVectorSource+MGLAdditions.h
new file mode 100644
index 0000000000..43b0aba747
--- /dev/null
+++ b/platform/darwin/src/MGLVectorSource+MGLAdditions.h
@@ -0,0 +1,15 @@
+#import <Mapbox/Mapbox.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MGLVectorSource (MGLAdditions)
+
++ (NSString *)preferredMapboxStreetsLanguage;
+
+- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage;
+
+@property (nonatomic, readonly, getter=isMapboxStreets) BOOL mapboxStreets;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLVectorSource+MGLAdditions.m b/platform/darwin/src/MGLVectorSource+MGLAdditions.m
new file mode 100644
index 0000000000..a305388117
--- /dev/null
+++ b/platform/darwin/src/MGLVectorSource+MGLAdditions.m
@@ -0,0 +1,53 @@
+#import "MGLVectorSource+MGLAdditions.h"
+
+@implementation MGLVectorSource (MGLAdditions)
+
++ (NS_SET_OF(NSString *) *)mapboxStreetsLanguages {
+ // https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview
+ static dispatch_once_t onceToken;
+ static NS_SET_OF(NSString *) *mapboxStreetsLanguages;
+ dispatch_once(&onceToken, ^{
+ // https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview
+ mapboxStreetsLanguages = [NSSet setWithObjects:@"ar", @"de", @"en", @"es", @"fr", @"pt", @"ru", @"zh", @"zh-Hans", nil];
+ });
+ return mapboxStreetsLanguages;
+}
+
++ (NSString *)preferredMapboxStreetsLanguage {
+ NSArray<NSString *> *supportedLanguages = [MGLVectorSource mapboxStreetsLanguages].allObjects;
+ NSArray<NSString *> *preferredLanguages = [NSBundle preferredLocalizationsFromArray:supportedLanguages
+ forPreferences:[NSLocale preferredLanguages]];
+ NSString *mostSpecificLanguage;
+ for (NSString *language in preferredLanguages) {
+ if (language.length > mostSpecificLanguage.length) {
+ mostSpecificLanguage = language;
+ }
+ }
+ return mostSpecificLanguage ?: @"en";
+}
+
+- (BOOL)isMapboxStreets {
+ NSURL *url = self.configurationURL;
+ if (![url.scheme isEqualToString:@"mapbox"]) {
+ return NO;
+ }
+ NSArray *identifiers = [url.host componentsSeparatedByString:@","];
+ return [identifiers containsObject:@"mapbox.mapbox-streets-v7"] || [identifiers containsObject:@"mapbox.mapbox-streets-v6"];
+}
+
+- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage {
+ if (!self.mapboxStreets) {
+ return @{};
+ }
+
+ // Replace {name} and {name_*} with the matching localized name tag.
+ NSString *localizedKey = preferredLanguage ? [NSString stringWithFormat:@"name_%@", preferredLanguage] : @"name";
+ NSMutableDictionary *localizedKeysByKey = [NSMutableDictionary dictionaryWithObject:localizedKey forKey:@"name"];
+ for (NSString *languageCode in [MGLVectorSource mapboxStreetsLanguages]) {
+ NSString *key = [NSString stringWithFormat:@"name_%@", languageCode];
+ localizedKeysByKey[key] = localizedKey;
+ }
+ return localizedKeysByKey;
+}
+
+@end
diff --git a/platform/darwin/src/MGLVectorSource.mm b/platform/darwin/src/MGLVectorSource.mm
index 431e0c250c..b1bda56f2d 100644
--- a/platform/darwin/src/MGLVectorSource.mm
+++ b/platform/darwin/src/MGLVectorSource.mm
@@ -64,8 +64,8 @@
}
std::vector<mbgl::Feature> features;
- if (self.style) {
- features = self.style.mapView.renderer->querySourceFeatures(self.rawSource->getID(), { optionalSourceLayerIDs, optionalFilter });
+ if (self.mapView) {
+ features = self.mapView.renderer->querySourceFeatures(self.rawSource->getID(), { optionalSourceLayerIDs, optionalFilter });
}
return MGLFeaturesFromMBGLFeatures(features);
}
diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift
index ae72b35d82..42c656f203 100644
--- a/platform/darwin/test/MGLDocumentationExampleTests.swift
+++ b/platform/darwin/test/MGLDocumentationExampleTests.swift
@@ -103,6 +103,18 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
XCTAssertNotNil(mapView.style?.source(withIdentifier: "pois"))
}
+
+ func testMGLPolyline() {
+ //#-example-code
+ let coordinates = [
+ CLLocationCoordinate2D(latitude: 35.68476, longitude: -220.24257),
+ CLLocationCoordinate2D(latitude: 37.78428, longitude: -122.41310)
+ ]
+ let polyline = MGLPolyline(coordinates: coordinates, count: UInt(coordinates.count))
+ //#-end-example-code
+
+ XCTAssertNotNil(polyline)
+ }
func testMGLImageSource() {
//#-example-code