summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/CONTRIBUTING_LINUX.md4
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java45
-rw-r--r--platform/android/scripts/configure.sh2
-rw-r--r--platform/android/src/example_custom_layer.cpp4
-rwxr-xr-xplatform/android/src/jni.cpp301
-rw-r--r--platform/darwin/src/MGLFeature.h137
-rw-r--r--platform/darwin/src/MGLFeature.mm269
-rw-r--r--platform/darwin/src/MGLFeature_Private.h11
-rw-r--r--platform/darwin/src/MGLGeometry_Private.h5
-rw-r--r--platform/darwin/src/MGLMultiPoint.h5
-rw-r--r--platform/darwin/src/MGLMultiPoint.mm36
-rw-r--r--platform/darwin/src/MGLMultiPoint_Private.h9
-rw-r--r--platform/darwin/src/MGLPolygon.h55
-rw-r--r--platform/darwin/src/MGLPolygon.mm96
-rw-r--r--platform/darwin/src/MGLPolyline.h27
-rw-r--r--platform/darwin/src/MGLPolyline.mm64
-rw-r--r--platform/darwin/src/MGLShapeCollection.h35
-rw-r--r--platform/darwin/src/MGLShapeCollection.m21
-rw-r--r--platform/darwin/test/MGLFeatureTests.mm160
-rw-r--r--platform/default/glfw_view.cpp51
-rw-r--r--platform/default/mbgl/storage/offline.cpp8
-rw-r--r--platform/default/mbgl/storage/offline_download.cpp31
-rw-r--r--platform/default/mbgl/storage/offline_download.hpp19
-rw-r--r--platform/default/resources/api_mapbox_com-digicert.derbin2077 -> 1913 bytes
-rw-r--r--platform/default/resources/api_mapbox_com-geotrust.derbin1969 -> 1757 bytes
-rw-r--r--platform/ios/CHANGELOG.md9
-rw-r--r--platform/ios/DEVELOPING.md8
-rw-r--r--platform/ios/Mapbox-iOS-SDK-symbols.podspec2
-rw-r--r--platform/ios/Mapbox-iOS-SDK.podspec2
-rw-r--r--platform/ios/app/MBXAnnotationView.m2
-rw-r--r--platform/ios/app/MBXViewController.m54
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj230
-rw-r--r--platform/ios/jazzy.yml14
-rw-r--r--platform/ios/scripts/configure.sh2
-rwxr-xr-xplatform/ios/scripts/deploy-packages.sh1
-rwxr-xr-xplatform/ios/scripts/package.sh16
-rw-r--r--platform/ios/src/MGLAPIClient.m2
-rw-r--r--platform/ios/src/MGLAnnotationContainerView.h17
-rw-r--r--platform/ios/src/MGLAnnotationContainerView.m52
-rw-r--r--platform/ios/src/MGLAnnotationView.h11
-rw-r--r--platform/ios/src/MGLAnnotationView.m69
-rw-r--r--platform/ios/src/MGLAnnotationView.mm147
-rw-r--r--platform/ios/src/MGLMapView.h414
-rw-r--r--platform/ios/src/MGLMapView.mm228
-rw-r--r--platform/ios/src/MGLMapViewDelegate.h284
-rw-r--r--platform/ios/src/MGLMapView_Internal.h3
-rw-r--r--platform/ios/src/MGLMapboxEvents.m22
-rw-r--r--platform/ios/src/Mapbox.h5
-rw-r--r--platform/linux/platform.gyp14
-rw-r--r--platform/linux/scripts/configure.sh3
-rw-r--r--platform/node/CHANGELOG.md9
-rw-r--r--platform/node/README.md6
-rw-r--r--platform/node/src/node_map.cpp7
-rw-r--r--platform/node/src/node_request.cpp37
-rw-r--r--platform/node/src/node_request.hpp9
-rw-r--r--platform/node/test/js/map.test.js20
-rw-r--r--platform/osx/CHANGELOG.md3
-rw-r--r--platform/osx/app/Base.lproj/MainMenu.xib2
-rw-r--r--platform/osx/app/Base.lproj/MapDocument.xib8
-rw-r--r--platform/osx/app/MapDocument.m48
-rw-r--r--platform/osx/jazzy.yml13
-rw-r--r--platform/osx/osx.xcodeproj/project.pbxproj141
-rw-r--r--platform/osx/platform.gyp14
-rw-r--r--platform/osx/scripts/configure.sh3
-rw-r--r--platform/osx/src/MGLMapView.h137
-rw-r--r--platform/osx/src/MGLMapView.mm138
-rw-r--r--platform/osx/src/Mapbox.h2
-rw-r--r--platform/qt/README.md1
-rw-r--r--platform/qt/include/qmapbox.hpp2
-rw-r--r--platform/qt/include/qmapboxgl.hpp4
-rw-r--r--platform/qt/scripts/configure.sh2
-rw-r--r--platform/qt/src/async_task.cpp4
-rw-r--r--platform/qt/src/qmapboxgl.cpp109
-rw-r--r--platform/qt/src/qmapboxgl_p.hpp3
74 files changed, 2649 insertions, 1079 deletions
diff --git a/platform/android/CONTRIBUTING_LINUX.md b/platform/android/CONTRIBUTING_LINUX.md
index d4b5200878..875f7a800a 100644
--- a/platform/android/CONTRIBUTING_LINUX.md
+++ b/platform/android/CONTRIBUTING_LINUX.md
@@ -32,13 +32,11 @@ gradle will take the value of the `MAPBOX_ACCESS_TOKEN` environ variable and sav
## Building
-Checking out the code and initializing the git submodules:
+Checking out the code:
```
$ git clone https://github.com/mapbox/mapbox-gl-native.git
$ cd mapbox-gl-native
-$ git submodule init
-$ git submodule update
```
Building a debug version will generated a self-signed test application that can be installed on the phone or emulator:
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
index 760ad56c77..e92e310c63 100755
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
@@ -195,11 +195,7 @@ final class NativeMapView {
}
public void setStyleJson(String newStyleJson) {
- setStyleJson(newStyleJson, "");
- }
-
- public void setStyleJson(String newStyleJson, String base) {
- nativeSetStyleJson(mNativeMapViewPtr, newStyleJson, base);
+ nativeSetStyleJson(mNativeMapViewPtr, newStyleJson);
}
public String getStyleJson() {
@@ -348,27 +344,30 @@ final class NativeMapView {
}
public long addMarker(Marker marker) {
- return nativeAddMarker(mNativeMapViewPtr, marker);
+ Marker[] markers = { marker };
+ return nativeAddMarkers(mNativeMapViewPtr, markers)[0];
}
public long[] addMarkers(List<Marker> markers) {
- return nativeAddMarkers(mNativeMapViewPtr, markers);
+ return nativeAddMarkers(mNativeMapViewPtr, markers.toArray(new Marker[markers.size()]));
}
public long addPolyline(Polyline polyline) {
- return nativeAddPolyline(mNativeMapViewPtr, polyline);
+ Polyline[] polylines = { polyline };
+ return nativeAddPolylines(mNativeMapViewPtr, polylines)[0];
}
public long[] addPolylines(List<Polyline> polylines) {
- return nativeAddPolylines(mNativeMapViewPtr, polylines);
+ return nativeAddPolylines(mNativeMapViewPtr, polylines.toArray(new Polyline[polylines.size()]));
}
public long addPolygon(Polygon polygon) {
- return nativeAddPolygon(mNativeMapViewPtr, polygon);
+ Polygon[] polygons = { polygon };
+ return nativeAddPolygons(mNativeMapViewPtr, polygons)[0];
}
- public long[] addPolygons(List<Polygon> polygon) {
- return nativeAddPolygons(mNativeMapViewPtr, polygon);
+ public long[] addPolygons(List<Polygon> polygons) {
+ return nativeAddPolygons(mNativeMapViewPtr, polygons.toArray(new Polygon[polygons.size()]));
}
public void updateMarker(Marker marker) {
@@ -378,7 +377,8 @@ final class NativeMapView {
}
public void removeAnnotation(long id) {
- nativeRemoveAnnotation(mNativeMapViewPtr, id);
+ long[] ids = { id };
+ removeAnnotations(ids);
}
public void removeAnnotations(long[] ids) {
@@ -527,8 +527,7 @@ final class NativeMapView {
private native void nativeSetStyleUrl(long nativeMapViewPtr, String url);
- private native void nativeSetStyleJson(long nativeMapViewPtr,
- String newStyleJson, String base);
+ private native void nativeSetStyleJson(long nativeMapViewPtr, String newStyleJson);
private native String nativeGetStyleJson(long nativeMapViewPtr);
@@ -592,21 +591,13 @@ final class NativeMapView {
private native void nativeResetNorth(long nativeMapViewPtr);
- private native long nativeAddMarker(long nativeMapViewPtr, Marker marker);
-
- private native void nativeUpdateMarker(long nativeMapViewPtr, long markerId, double lat, double lon, String iconId);
-
- private native long[] nativeAddMarkers(long nativeMapViewPtr, List<Marker> markers);
-
- private native long nativeAddPolyline(long nativeMapViewPtr, Polyline polyline);
-
- private native long[] nativeAddPolylines(long mNativeMapViewPtr, List<Polyline> polygon);
+ private native void nativeUpdateMarker(long nativeMapViewPtr, Marker marker);
- private native long nativeAddPolygon(long mNativeMapViewPtr, Polygon polygon);
+ private native long[] nativeAddMarkers(long nativeMapViewPtr, Marker[] markers);
- private native long[] nativeAddPolygons(long mNativeMapViewPtr, List<Polygon> polygon);
+ private native long[] nativeAddPolylines(long mNativeMapViewPtr, Polyline[] polylines);
- private native void nativeRemoveAnnotation(long nativeMapViewPtr, long id);
+ private native long[] nativeAddPolygons(long mNativeMapViewPtr, Polygon[] polygons);
private native void nativeRemoveAnnotations(long nativeMapViewPtr, long[] id);
diff --git a/platform/android/scripts/configure.sh b/platform/android/scripts/configure.sh
index 93d9c301dd..2bbc134597 100644
--- a/platform/android/scripts/configure.sh
+++ b/platform/android/scripts/configure.sh
@@ -1,5 +1,6 @@
#!/usr/bin/env bash
+UNIQUE_RESOURCE_VERSION=dev
PROTOZERO_VERSION=1.3.0
BOOST_VERSION=1.60.0
LIBPNG_VERSION=1.6.20
@@ -13,5 +14,6 @@ GEOJSONVT_VERSION=4.1.2
VARIANT_VERSION=1.1.0
RAPIDJSON_VERSION=1.0.2
JNI_HPP_VERSION=2.0.0
+EARCUT_VERSION=0.11
export MASON_ANDROID_ABI=${MASON_PLATFORM_VERSION}
diff --git a/platform/android/src/example_custom_layer.cpp b/platform/android/src/example_custom_layer.cpp
index a513b7faf6..516a8f2cd5 100644
--- a/platform/android/src/example_custom_layer.cpp
+++ b/platform/android/src/example_custom_layer.cpp
@@ -1,7 +1,7 @@
#include <jni.h>
#include <GLES2/gl2.h>
-#include <mbgl/style/types.hpp>
+#include <mbgl/style/layers/custom_layer.hpp>
static const GLchar * vertexShaderSource = "attribute vec2 a_pos; void main() { gl_Position = vec4(a_pos, 0, 1); }";
static const GLchar * fragmentShaderSource = "void main() { gl_FragColor = vec4(0, 1, 0, 1); }";
@@ -64,7 +64,7 @@ void nativeInitialize(void *context) {
reinterpret_cast<ExampleCustomLayer*>(context)->initialize();
}
-void nativeRender(void *context, const mbgl::CustomLayerRenderParameters& /*parameters*/) {
+void nativeRender(void *context, const mbgl::style::CustomLayerRenderParameters& /*parameters*/) {
reinterpret_cast<ExampleCustomLayer*>(context)->render();
}
diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp
index e2effa6834..6f1b892c7e 100755
--- a/platform/android/src/jni.cpp
+++ b/platform/android/src/jni.cpp
@@ -13,8 +13,8 @@
#include <mbgl/map/map.hpp>
#include <mbgl/map/camera.hpp>
-#include <mbgl/annotation/point_annotation.hpp>
-#include <mbgl/annotation/shape_annotation.hpp>
+#include <mbgl/annotation/annotation.hpp>
+#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/sprite/sprite_image.hpp>
#include <mbgl/platform/event.hpp>
#include <mbgl/platform/log.hpp>
@@ -248,64 +248,6 @@ jni::jarray<jlong>* std_vector_uint_to_jobject(JNIEnv *env, std::vector<uint32_t
return &jarray;
}
-mbgl::AnnotationSegment annotation_segment_from_latlng_jlist(JNIEnv *env, jni::jobject* jlist) {
- mbgl::AnnotationSegment segment;
-
- NullCheck(*env, jlist);
- jni::jarray<jni::jobject>* jarray =
- reinterpret_cast<jni::jarray<jni::jobject>*>(jni::CallMethod<jni::jobject*>(*env, jlist, *listToArrayId));
-
- NullCheck(*env, jarray);
- std::size_t len = jni::GetArrayLength(*env, *jarray);
-
- segment.reserve(len);
-
- for (std::size_t i = 0; i < len; i++) {
- jni::jobject* latLng = reinterpret_cast<jni::jobject*>(jni::GetObjectArrayElement(*env, *jarray, i));
- NullCheck(*env, latLng);
-
- jdouble latitude = jni::GetField<jdouble>(*env, latLng, *latLngLatitudeId);
- jdouble longitude = jni::GetField<jdouble>(*env, latLng, *latLngLongitudeId);
-
- segment.push_back(mbgl::LatLng(latitude, longitude));
- jni::DeleteLocalRef(*env, latLng);
- }
-
- jni::DeleteLocalRef(*env, jarray);
- jarray = nullptr;
-
- return segment;
-}
-
-std::pair<mbgl::AnnotationSegment, mbgl::ShapeAnnotation::Properties> annotation_std_pair_from_polygon_jobject(JNIEnv *env, jni::jobject* polygon) {
- jfloat alpha = jni::GetField<jfloat>(*env, polygon, *polygonAlphaId);
- jint fillColor = jni::GetField<jint>(*env, polygon, *polygonFillColorId);
- jint strokeColor = jni::GetField<jint>(*env, polygon, *polygonStrokeColorId);
-
- int rF = (fillColor >> 16) & 0xFF;
- int gF = (fillColor >> 8) & 0xFF;
- int bF = (fillColor) & 0xFF;
- int aF = (fillColor >> 24) & 0xFF;
-
- int rS = (strokeColor >> 16) & 0xFF;
- int gS = (strokeColor >> 8) & 0xFF;
- int bS = (strokeColor) & 0xFF;
- int aS = (strokeColor >> 24) & 0xFF;
-
- mbgl::ShapeAnnotation::Properties shapeProperties;
- mbgl::FillAnnotationProperties fillProperties;
- fillProperties.opacity = alpha;
- fillProperties.outlineColor = {{ static_cast<float>(rS) / 255.0f, static_cast<float>(gS) / 255.0f, static_cast<float>(bS) / 255.0f, static_cast<float>(aS) / 255.0f }};
- fillProperties.color = {{ static_cast<float>(rF) / 255.0f, static_cast<float>(gF) / 255.0f, static_cast<float>(bF) / 255.0f, static_cast<float>(aF) / 255.0f }};
- shapeProperties.set<mbgl::FillAnnotationProperties>(fillProperties);
-
- jni::jobject* points = jni::GetField<jni::jobject*>(*env, polygon, *polygonPointsId);
- mbgl::AnnotationSegment segment = annotation_segment_from_latlng_jlist(env, points);
- jni::DeleteLocalRef(*env, points);
-
- return std::make_pair(segment, shapeProperties);
-}
-
static std::vector<uint8_t> metadata_from_java(JNIEnv* env, jni::jarray<jbyte>& j) {
mbgl::Log::Debug(mbgl::Event::JNI, "metadata_from_java");
std::size_t length = jni::GetArrayLength(*env, j);
@@ -485,13 +427,11 @@ void nativeSetStyleUrl(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, j
nativeMapView->getMap().setStyleURL(std_string_from_jstring(env, url));
}
-void nativeSetStyleJson(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr,
- jni::jstring* newStyleJson, jni::jstring* base) {
+void nativeSetStyleJson(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* newStyleJson) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetStyleJSON");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setStyleJSON(std_string_from_jstring(env, newStyleJson),
- std_string_from_jstring(env, base));
+ nativeMapView->getMap().setStyleJSON(std_string_from_jstring(env, newStyleJson));
}
jni::jstring* nativeGetStyleJson(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
@@ -743,190 +683,147 @@ void nativeUpdateMarker(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr,
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
+ jlong markerId = jni::GetField<jlong>(*env, marker, *markerIdId);
if (markerId == -1) {
return;
}
+ jni::jobject* position = jni::GetField<jni::jobject*>(*env, marker, *markerPositionId);
+ jni::jobject* icon = jni::GetField<jni::jobject*>(*env, marker, *markerIconId);
+
+ jni::jstring* jid = reinterpret_cast<jni::jstring*>(jni::GetField<jni::jobject*>(*env, icon, *iconIdId));
std::string iconId = std_string_from_jstring(env, jid);
- // Because Java only has int, not unsigned int, we need to bump the annotation id up to a long.
- nativeMapView->getMap().updatePointAnnotation(markerId, mbgl::PointAnnotation(mbgl::LatLng(lat, lon), iconId));
+ jdouble latitude = jni::GetField<jdouble>(*env, position, *latLngLatitudeId);
+ jdouble longitude = jni::GetField<jdouble>(*env, position, *latLngLongitudeId);
+
+ nativeMapView->getMap().updateAnnotation(markerId, mbgl::SymbolAnnotation {
+ mbgl::Point<double>(longitude, latitude),
+ iconId
+ });
}
-jni::jarray<jlong>* nativeAddMarkers(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* jlist) {
+jni::jarray<jlong>* nativeAddMarkers(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jni::jobject>* jarray) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddMarkers");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- std::vector<mbgl::PointAnnotation> markers;
-
- NullCheck(*env, jlist);
- jni::jarray<jni::jobject>* jarray =
- reinterpret_cast<jni::jarray<jni::jobject>*>(jni::CallMethod<jni::jobject*>(*env, jlist, *listToArrayId));
-
NullCheck(*env, jarray);
std::size_t len = jni::GetArrayLength(*env, *jarray);
- markers.reserve(len);
+ std::vector<mbgl::AnnotationID> ids;
+ ids.reserve(len);
for (std::size_t i = 0; i < len; i++) {
jni::jobject* marker = jni::GetObjectArrayElement(*env, *jarray, i);
jni::jobject* position = jni::GetField<jni::jobject*>(*env, marker, *markerPositionId);
jni::jobject* icon = jni::GetField<jni::jobject*>(*env, marker, *markerIconId);
- jni::DeleteLocalRef(*env, marker);
-
jni::jstring* jid = reinterpret_cast<jni::jstring*>(jni::GetField<jni::jobject*>(*env, icon, *iconIdId));
- jni::DeleteLocalRef(*env, icon);
-
- std::string id = std_string_from_jstring(env, jid);
- jni::DeleteLocalRef(*env, jid);
jdouble latitude = jni::GetField<jdouble>(*env, position, *latLngLatitudeId);
jdouble longitude = jni::GetField<jdouble>(*env, position, *latLngLongitudeId);
- jni::DeleteLocalRef(*env, position);
- markers.emplace_back(mbgl::PointAnnotation(mbgl::LatLng(latitude, longitude), id));
- }
+ ids.push_back(nativeMapView->getMap().addAnnotation(mbgl::SymbolAnnotation {
+ mbgl::Point<double>(longitude, latitude),
+ std_string_from_jstring(env, jid)
+ }));
- jni::DeleteLocalRef(*env, jarray);
+ jni::DeleteLocalRef(*env, position);
+ jni::DeleteLocalRef(*env, jid);
+ jni::DeleteLocalRef(*env, icon);
+ jni::DeleteLocalRef(*env, marker);
+ }
- std::vector<uint32_t> pointAnnotationIDs = nativeMapView->getMap().addPointAnnotations(markers);
- return std_vector_uint_to_jobject(env, pointAnnotationIDs);
+ return std_vector_uint_to_jobject(env, ids);
}
+static mbgl::Color toColor(jint color) {
+ float r = (color >> 16) & 0xFF;
+ float g = (color >> 8) & 0xFF;
+ float b = (color) & 0xFF;
+ float a = (color >> 24) & 0xFF;
+ return {{ r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f }};
+}
-jlong nativeAddPolyline(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* polyline) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddPolyline");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- jfloat alpha = jni::GetField<jfloat>(*env, polyline, *polylineAlphaId);
- jint color = jni::GetField<jint>(*env, polyline, *polylineColorId);
-
- int r = (color >> 16) & 0xFF;
- int g = (color >> 8) & 0xFF;
- int b = (color) & 0xFF;
- int a = (color >> 24) & 0xFF;
+template <class Geometry>
+Geometry toGeometry(JNIEnv *env, jni::jobject* jlist) {
+ NullCheck(*env, jlist);
+ jni::jarray<jni::jobject>* jarray =
+ reinterpret_cast<jni::jarray<jni::jobject>*>(jni::CallMethod<jni::jobject*>(*env, jlist, *listToArrayId));
+ NullCheck(*env, jarray);
- jfloat width = jni::GetField<jfloat>(*env, polyline, *polylineWidthId);
+ Geometry geometry;
+ geometry.reserve(jni::GetArrayLength(*env, *jarray));
- mbgl::ShapeAnnotation::Properties shapeProperties;
- mbgl::LineAnnotationProperties lineProperties;
- lineProperties.opacity = alpha;
- lineProperties.color = {{ static_cast<float>(r) / 255.0f, static_cast<float>(g) / 255.0f, static_cast<float>(b) / 255.0f, static_cast<float>(a) / 255.0f }};
- lineProperties.width = width;
- shapeProperties.set<mbgl::LineAnnotationProperties>(lineProperties);
+ for (std::size_t i = 0; i < geometry.size(); i++) {
+ jni::jobject* latLng = reinterpret_cast<jni::jobject*>(jni::GetObjectArrayElement(*env, *jarray, i));
+ NullCheck(*env, latLng);
- jni::jobject* points = jni::GetField<jni::jobject*>(*env, polyline, *polylinePointsId);
- mbgl::AnnotationSegment segment = annotation_segment_from_latlng_jlist(env, points);
+ geometry.push_back(mbgl::Point<double>(
+ jni::GetField<jdouble>(*env, latLng, *latLngLongitudeId),
+ jni::GetField<jdouble>(*env, latLng, *latLngLatitudeId)));
- std::vector<mbgl::ShapeAnnotation> shapes;
- shapes.emplace_back(mbgl::AnnotationSegments { segment }, shapeProperties);
+ jni::DeleteLocalRef(*env, latLng);
+ }
- std::vector<uint32_t> shapeAnnotationIDs = nativeMapView->getMap().addShapeAnnotations(shapes);
- uint32_t id = shapeAnnotationIDs.at(0);
+ jni::DeleteLocalRef(*env, jarray);
+ jni::DeleteLocalRef(*env, jlist);
- return id;
+ return geometry;
}
-jni::jarray<jlong>* nativeAddPolylines(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* jlist) {
+jni::jarray<jlong>* nativeAddPolylines(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jni::jobject>* jarray) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddPolylines");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- std::vector<mbgl::ShapeAnnotation> shapes;
-
- jni::jarray<jni::jobject>* jarray =
- reinterpret_cast<jni::jarray<jni::jobject>*>(jni::CallMethod<jni::jobject*>(*env, jlist, *listToArrayId));
-
NullCheck(*env, jarray);
std::size_t len = jni::GetArrayLength(*env, *jarray);
- shapes.reserve(len);
+ std::vector<mbgl::AnnotationID> ids;
+ ids.reserve(len);
for (std::size_t i = 0; i < len; i++) {
jni::jobject* polyline = jni::GetObjectArrayElement(*env, *jarray, i);
-
- jfloat alpha = jni::GetField<jfloat>(*env, polyline, *polylineAlphaId);
- jint color = jni::GetField<jint>(*env, polyline, *polylineColorId);
-
- int r = (color >> 16) & 0xFF;
- int g = (color >> 8) & 0xFF;
- int b = (color) & 0xFF;
- int a = (color >> 24) & 0xFF;
-
- jfloat width = jni::GetField<jfloat>(*env, polyline, *polylineWidthId);
-
- mbgl::ShapeAnnotation::Properties shapeProperties;
- mbgl::LineAnnotationProperties lineProperties;
- lineProperties.opacity = alpha;
- lineProperties.color = {{ static_cast<float>(r) / 255.0f, static_cast<float>(g) / 255.0f, static_cast<float>(b) / 255.0f, static_cast<float>(a) / 255.0f }};
- lineProperties.width = width;
- shapeProperties.set<mbgl::LineAnnotationProperties>(lineProperties);
-
jni::jobject* points = jni::GetField<jni::jobject*>(*env, polyline, *polylinePointsId);
- mbgl::AnnotationSegment segment = annotation_segment_from_latlng_jlist(env, points);
- shapes.emplace_back(mbgl::AnnotationSegments { segment }, shapeProperties);
+ mbgl::LineAnnotation annotation { toGeometry<mbgl::LineString<double>>(env, points) };
+ annotation.opacity = jni::GetField<jfloat>(*env, polyline, *polylineAlphaId);
+ annotation.color = toColor(jni::GetField<jint>(*env, polyline, *polylineColorId));
+ annotation.width = jni::GetField<jfloat>(*env, polyline, *polylineWidthId);
+ ids.push_back(nativeMapView->getMap().addAnnotation(annotation));
jni::DeleteLocalRef(*env, polyline);
}
- jni::DeleteLocalRef(*env, jarray);
-
- std::vector<uint32_t> shapeAnnotationIDs = nativeMapView->getMap().addShapeAnnotations(shapes);
- return std_vector_uint_to_jobject(env, shapeAnnotationIDs);
-}
-
-jlong nativeAddPolygon(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* polygon) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddPolygon");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- std::vector<mbgl::ShapeAnnotation> shapes;
- std::pair<mbgl::AnnotationSegment, mbgl::ShapeAnnotation::Properties> segment = annotation_std_pair_from_polygon_jobject(env, polygon);
-
- shapes.emplace_back(mbgl::AnnotationSegments { segment.first }, segment.second);
-
- std::vector<uint32_t> shapeAnnotationIDs = nativeMapView->getMap().addShapeAnnotations(shapes);
- uint32_t id = shapeAnnotationIDs.at(0);
- return id;
+ return std_vector_uint_to_jobject(env, ids);
}
-jni::jarray<jlong>* nativeAddPolygons(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* jlist) {
+jni::jarray<jlong>* nativeAddPolygons(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jni::jobject>* jarray) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddPolygons");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- std::vector<mbgl::ShapeAnnotation> shapes;
-
- jni::jarray<jni::jobject>* jarray =
- reinterpret_cast<jni::jarray<jni::jobject>*>(jni::CallMethod<jni::jobject*>(*env, jlist, *listToArrayId));
-
NullCheck(*env, jarray);
std::size_t len = jni::GetArrayLength(*env, *jarray);
- shapes.reserve(len);
+
+ std::vector<mbgl::AnnotationID> ids;
+ ids.reserve(len);
for (std::size_t i = 0; i < len; i++) {
jni::jobject* polygon = jni::GetObjectArrayElement(*env, *jarray, i);
+ jni::jobject* points = jni::GetField<jni::jobject*>(*env, polygon, *polygonPointsId);
- std::pair<mbgl::AnnotationSegment, mbgl::ShapeAnnotation::Properties> segment = annotation_std_pair_from_polygon_jobject(env, polygon);
- shapes.emplace_back(mbgl::AnnotationSegments { segment.first }, segment.second);
+ mbgl::FillAnnotation annotation { mbgl::Polygon<double> { toGeometry<mbgl::LinearRing<double>>(env, points) } };
+ annotation.opacity = jni::GetField<jfloat>(*env, polygon, *polygonAlphaId);
+ annotation.outlineColor = toColor(jni::GetField<jint>(*env, polygon, *polygonStrokeColorId));
+ annotation.color = toColor(jni::GetField<jint>(*env, polygon, *polygonFillColorId));
+ ids.push_back(nativeMapView->getMap().addAnnotation(annotation));
jni::DeleteLocalRef(*env, polygon);
}
- jni::DeleteLocalRef(*env, jarray);
-
- std::vector<uint32_t> shapeAnnotationIDs = nativeMapView->getMap().addShapeAnnotations(shapes);
- return std_vector_uint_to_jobject(env, shapeAnnotationIDs);
-}
-
-void nativeRemoveAnnotation(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong annotationId) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeRemoveAnnotation");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().removeAnnotation(static_cast<uint32_t>(annotationId));
+ return std_vector_uint_to_jobject(env, ids);
}
void nativeRemoveAnnotations(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jlong>* jarray) {
@@ -936,20 +833,14 @@ void nativeRemoveAnnotations(JNIEnv *env, jni::jobject* obj, jlong nativeMapView
NullCheck(*env, jarray);
std::size_t len = jni::GetArrayLength(*env, *jarray);
-
- std::vector<uint32_t> ids;
- ids.reserve(len);
-
auto elements = jni::GetArrayElements(*env, *jarray);
jlong* jids = std::get<0>(elements).get();
for (std::size_t i = 0; i < len; i++) {
if(jids[i] == -1L)
continue;
- ids.push_back(static_cast<uint32_t>(jids[i]));
+ nativeMapView->getMap().removeAnnotation(jids[i]);
}
-
- nativeMapView->getMap().removeAnnotations(ids);
}
jni::jarray<jlong>* nativeGetAnnotationsInBounds(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* latLngBounds_) {
@@ -1010,17 +901,17 @@ void nativeSetVisibleCoordinateBounds(JNIEnv *env, jni::jobject* obj, jlong nati
std::size_t count = jni::GetArrayLength(*env, *coordinates);
mbgl::EdgeInsets mbglInsets = {top, left, bottom, right};
- mbgl::AnnotationSegment segment;
- segment.reserve(count);
+ std::vector<mbgl::LatLng> latLngs;
+ latLngs.reserve(count);
for (std::size_t i = 0; i < count; i++) {
jni::jobject* latLng = jni::GetObjectArrayElement(*env, *coordinates, i);
jdouble latitude = jni::GetField<jdouble>(*env, latLng, *latLngLatitudeId);
jdouble longitude = jni::GetField<jdouble>(*env, latLng, *latLngLongitudeId);
- segment.push_back(mbgl::LatLng(latitude, longitude));
+ latLngs.push_back(mbgl::LatLng(latitude, longitude));
}
- mbgl::CameraOptions cameraOptions = nativeMapView->getMap().cameraForLatLngs(segment, mbglInsets);
+ mbgl::CameraOptions cameraOptions = nativeMapView->getMap().cameraForLatLngs(latLngs, mbglInsets);
if (direction >= 0) {
// convert from degrees to radians
cameraOptions.angle = (-direction * M_PI) / 180;
@@ -1237,20 +1128,20 @@ void nativeAddCustomLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr
mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddCustomLayer");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().addCustomLayer(
+ nativeMapView->getMap().addLayer(std::make_unique<mbgl::style::CustomLayer>(
std_string_from_jstring(env, reinterpret_cast<jni::jstring*>(jni::GetField<jni::jobject*>(*env, customLayer, *customLayerIdId))),
- reinterpret_cast<mbgl::CustomLayerInitializeFunction>(jni::GetField<jlong>(*env, customLayer, *customLayerInitializeFunctionId)),
- reinterpret_cast<mbgl::CustomLayerRenderFunction>(jni::GetField<jlong>(*env, customLayer, *customLayerRenderFunctionId)),
- reinterpret_cast<mbgl::CustomLayerDeinitializeFunction>(jni::GetField<jlong>(*env, customLayer, *customLayerDeinitializeFunctionId)),
- reinterpret_cast<void*>(jni::GetField<jlong>(*env, customLayer, *customLayerContextId)),
- before ? std_string_from_jstring(env, before).c_str() : nullptr);
+ reinterpret_cast<mbgl::style::CustomLayerInitializeFunction>(jni::GetField<jlong>(*env, customLayer, *customLayerInitializeFunctionId)),
+ reinterpret_cast<mbgl::style::CustomLayerRenderFunction>(jni::GetField<jlong>(*env, customLayer, *customLayerRenderFunctionId)),
+ reinterpret_cast<mbgl::style::CustomLayerDeinitializeFunction>(jni::GetField<jlong>(*env, customLayer, *customLayerDeinitializeFunctionId)),
+ reinterpret_cast<void*>(jni::GetField<jlong>(*env, customLayer, *customLayerContextId))),
+ before ? mbgl::optional<std::string>(std_string_from_jstring(env, before)) : mbgl::optional<std::string>());
}
void nativeRemoveCustomLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* id) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeRemoveCustomLayer");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().removeCustomLayer(std_string_from_jstring(env, id));
+ nativeMapView->getMap().removeLayer(std_string_from_jstring(env, id));
}
// Offline calls begin
@@ -1315,7 +1206,7 @@ void listOfflineRegions(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourceP
jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionOfflineManagerId, obj);
jni::SetField<jlong>(*env2, jregion, *offlineRegionIdId, region.getID());
-
+
// Definition object
mbgl::OfflineTilePyramidRegionDefinition definition = region.getDefinition();
jni::jobject* jdefinition = &jni::NewObject(*env2, *offlineRegionDefinitionClass, *offlineRegionDefinitionConstructorId);
@@ -1325,7 +1216,7 @@ void listOfflineRegions(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourceP
jni::SetField<jdouble>(*env2, jdefinition, *offlineRegionDefinitionMaxZoomId, definition.maxZoom);
jni::SetField<jfloat>(*env2, jdefinition, *offlineRegionDefinitionPixelRatioId, definition.pixelRatio);
jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionDefinitionId, jdefinition);
-
+
// Metadata object
jni::jarray<jbyte>* metadata = metadata_from_native(env2, region.getMetadata());
jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionMetadataId, metadata);
@@ -1811,7 +1702,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
MAKE_NATIVE_METHOD(nativeSetClasses, "(JLjava/util/List;)V"),
MAKE_NATIVE_METHOD(nativeGetClasses, "(J)Ljava/util/List;"),
MAKE_NATIVE_METHOD(nativeSetStyleUrl, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeSetStyleJson, "(JLjava/lang/String;Ljava/lang/String;)V"),
+ MAKE_NATIVE_METHOD(nativeSetStyleJson, "(JLjava/lang/String;)V"),
MAKE_NATIVE_METHOD(nativeGetStyleJson, "(J)Ljava/lang/String;"),
MAKE_NATIVE_METHOD(nativeSetAccessToken, "(JLjava/lang/String;)V"),
MAKE_NATIVE_METHOD(nativeGetAccessToken, "(J)Ljava/lang/String;"),
@@ -1839,14 +1730,10 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
MAKE_NATIVE_METHOD(nativeSetBearingXY, "(JDDD)V"),
MAKE_NATIVE_METHOD(nativeGetBearing, "(J)D"),
MAKE_NATIVE_METHOD(nativeResetNorth, "(J)V"),
- MAKE_NATIVE_METHOD(nativeAddMarker, "(JLcom/mapbox/mapboxsdk/annotations/Marker;)J"),
- MAKE_NATIVE_METHOD(nativeAddMarkers, "(JLjava/util/List;)[J"),
- MAKE_NATIVE_METHOD(nativeAddPolyline, "(JLcom/mapbox/mapboxsdk/annotations/Polyline;)J"),
- MAKE_NATIVE_METHOD(nativeAddPolylines, "(JLjava/util/List;)[J"),
- MAKE_NATIVE_METHOD(nativeAddPolygon, "(JLcom/mapbox/mapboxsdk/annotations/Polygon;)J"),
- MAKE_NATIVE_METHOD(nativeAddPolygons, "(JLjava/util/List;)[J"),
- MAKE_NATIVE_METHOD(nativeUpdateMarker, "(JJDDLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeRemoveAnnotation, "(JJ)V"),
+ MAKE_NATIVE_METHOD(nativeAddMarkers, "(J[Lcom/mapbox/mapboxsdk/annotations/Marker;)[J"),
+ MAKE_NATIVE_METHOD(nativeAddPolylines, "(J[Lcom/mapbox/mapboxsdk/annotations/Polyline;)[J"),
+ MAKE_NATIVE_METHOD(nativeAddPolygons, "(J[Lcom/mapbox/mapboxsdk/annotations/Polygon;)[J"),
+ MAKE_NATIVE_METHOD(nativeUpdateMarker, "(JLcom/mapbox/mapboxsdk/annotations/Marker;)V"),
MAKE_NATIVE_METHOD(nativeRemoveAnnotations, "(J[J)V"),
MAKE_NATIVE_METHOD(nativeGetAnnotationsInBounds, "(JLcom/mapbox/mapboxsdk/geometry/LatLngBounds;)[J"),
MAKE_NATIVE_METHOD(nativeAddAnnotationIcon, "(JLjava/lang/String;IIF[B)V"),
diff --git a/platform/darwin/src/MGLFeature.h b/platform/darwin/src/MGLFeature.h
new file mode 100644
index 0000000000..69cff6b054
--- /dev/null
+++ b/platform/darwin/src/MGLFeature.h
@@ -0,0 +1,137 @@
+#import <Foundation/Foundation.h>
+
+#import "MGLPolyline.h"
+#import "MGLPolygon.h"
+#import "MGLPointAnnotation.h"
+#import "MGLShapeCollection.h"
+
+#import "MGLTypes.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ The `MGLFeature` protocol is used to provide details about geographic features
+ contained in a map view’s
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile sources</a>.
+ Each concrete subclass of `MGLShape` in turn has a subclass that conforms to
+ this protocol.
+
+ Typically, you do not create feature objects yourself but rather obtain them
+ using `-[MGLMapView visibleFeaturesAtPoint:]` and related methods. Each feature
+ object associates a shape with an identifier and attributes as specified by the
+ source. Like ordinary `MGLAnnotation` objects, some kinds of `MGLFeature`
+ objects can also be added to a map view using `-[MGLMapView addAnnotations:]`
+ and related methods.
+ */
+@protocol MGLFeature <MGLAnnotation>
+
+/**
+ An object that uniquely identifies the feature in its containing
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+
+ The value of this property is currently always an `NSNumber` object but may in
+ the future be an instance of another class, such as `NSString`.
+
+ The identifier corresponds to the
+ <a href="https://github.com/mapbox/vector-tile-spec/tree/master/2.1#42-features">feature identifier</a>
+ (`id`) in the tile source. If the source does not specify the feature’s
+ identifier, the value of this property is `nil`.
+
+ For details about the identifiers used in most Mapbox-provided styles, consult
+ the
+ <a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets</a>
+ layer reference.
+ */
+@property (nonatomic, copy, nullable, readonly) id identifier;
+
+/**
+ A dictionary of attributes for this feature specified by the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+
+ The keys and values of this dictionary are determined by the tile source. In
+ the tile source, each attribute name is a string, while each attribute value
+ may be a null value, Boolean value, integer, floating-point number, or string.
+ These data types are mapped to instances of the following Foundation classes:
+
+ <table>
+ <thead>
+ <tr><th>In the tile source</th><th>In this dictionary</th></tr>
+ </thead>
+ <tbody>
+ <tr><td>Null</td> <td><code>NSNull</code></td></tr>
+ <tr><td>Boolean</td> <td><code>NSNumber</code> (use the <code>boolValue</code> property)</td></tr>
+ <tr><td>Integer</td> <td><code>NSNumber</code> (use the <code>unsignedLongLongValue</code> or <code>longLongValue</code> property)</td></tr>
+ <tr><td>Floating-point number</td> <td><code>NSNumber</code> (use the <code>doubleValue</code> property)</td></tr>
+ <tr><td>String</td> <td><code>NSString</code></td></tr>
+ </tbody>
+ </table>
+
+ For details about the attribute names and values found in Mapbox-provided
+ vector tile sources, consult the
+ <a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets</a>
+ and
+ <a href="https://www.mapbox.com/vector-tiles/mapbox-terrain/">Mapbox Terrain</a>
+ layer references.
+ */
+@property (nonatomic, copy, readonly) NS_DICTIONARY_OF(NSString *, id) *attributes;
+
+/**
+ Returns the feature attribute for the given attribute name.
+
+ See the `attributes` property’s documentation for details on keys and values
+ associated with this method.
+ */
+- (nullable id)attributeForKey:(NSString *)key;
+
+@end
+
+/**
+ The `MGLPointFeature` class represents a point in a
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ */
+@interface MGLPointFeature : MGLPointAnnotation <MGLFeature>
+@end
+
+/**
+ The `MGLPolylineFeature` class represents a polyline in a
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ */
+@interface MGLPolylineFeature : MGLPolyline <MGLFeature>
+@end
+
+/**
+ The `MGLPolygonFeature` class represents a polygon in a
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ */
+@interface MGLPolygonFeature : MGLPolygon <MGLFeature>
+@end
+
+/**
+ The `MGLMultiPointFeature` class represents a multipoint in a
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ */
+@interface MGLMultiPointFeature : MGLMultiPoint <MGLFeature>
+@end
+
+/**
+ The `MGLMultiPolylineFeature` class represents a multipolyline in a
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ */
+@interface MGLMultiPolylineFeature : MGLMultiPolyline <MGLFeature>
+@end
+
+/**
+ The `MGLMultiPolygonFeature` class represents a multipolygon in a
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ */
+@interface MGLMultiPolygonFeature : MGLMultiPolygon <MGLFeature>
+@end
+
+/**
+ The `MGLShapeCollectionFeature` class represents a shape collection in a
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
+ */
+@interface MGLShapeCollectionFeature : MGLShapeCollection <MGLFeature>
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm
new file mode 100644
index 0000000000..777b296303
--- /dev/null
+++ b/platform/darwin/src/MGLFeature.mm
@@ -0,0 +1,269 @@
+#import "MGLFeature_Private.h"
+
+#import "MGLPointAnnotation.h"
+#import "MGLPolyline.h"
+#import "MGLPolygon.h"
+
+#import "MGLMultiPoint_Private.h"
+
+#import <mbgl/util/geometry.hpp>
+
+@protocol MGLFeaturePrivate <MGLFeature>
+
+@property (nonatomic, copy, nullable, readwrite) id identifier;
+@property (nonatomic, copy, readwrite) NS_DICTIONARY_OF(NSString *, id) *attributes;
+
+@end
+
+@interface MGLPointFeature () <MGLFeaturePrivate>
+@end
+
+@implementation MGLPointFeature
+
+@synthesize identifier;
+@synthesize attributes;
+
+- (id)attributeForKey:(NSString *)key {
+ return self.attributes[key];
+}
+
+@end
+
+@interface MGLPolylineFeature () <MGLFeaturePrivate>
+@end
+
+@implementation MGLPolylineFeature
+
+@synthesize identifier;
+@synthesize attributes;
+
+- (id)attributeForKey:(NSString *)key {
+ return self.attributes[key];
+}
+
+@end
+
+@interface MGLPolygonFeature () <MGLFeaturePrivate>
+@end
+
+@implementation MGLPolygonFeature
+
+@synthesize identifier;
+@synthesize attributes;
+
+- (id)attributeForKey:(NSString *)key {
+ return self.attributes[key];
+}
+
+@end
+
+@interface MGLMultiPointFeature () <MGLFeaturePrivate>
+@end
+
+@implementation MGLMultiPointFeature
+
+@synthesize identifier;
+@synthesize attributes;
+
+- (id)attributeForKey:(NSString *)key {
+ return self.attributes[key];
+}
+
+@end
+
+@interface MGLMultiPolylineFeature () <MGLFeaturePrivate>
+@end
+
+@implementation MGLMultiPolylineFeature
+
+@synthesize identifier;
+@synthesize attributes;
+
+- (id)attributeForKey:(NSString *)key {
+ return self.attributes[key];
+}
+
+@end
+
+@interface MGLMultiPolygonFeature () <MGLFeaturePrivate>
+@end
+
+@implementation MGLMultiPolygonFeature
+
+@synthesize identifier;
+@synthesize attributes;
+
+- (id)attributeForKey:(NSString *)key {
+ return self.attributes[key];
+}
+
+@end
+
+@interface MGLShapeCollectionFeature () <MGLFeaturePrivate>
+@end
+
+@implementation MGLShapeCollectionFeature
+
+@synthesize identifier;
+@synthesize attributes;
+
+- (id)attributeForKey:(NSString *)key {
+ return self.attributes[key];
+}
+
+@end
+
+/**
+ Recursively transforms a C++ type into the corresponding Foundation type.
+ */
+class PropertyValueEvaluator {
+public:
+ id operator()(const std::nullptr_t &) const {
+ return [NSNull null];
+ }
+
+ id operator()(const bool &value) const {
+ return value ? @YES : @NO;
+ }
+
+ id operator()(const uint64_t &value) const {
+ return @(value);
+ }
+
+ id operator()(const int64_t &value) const {
+ return @(value);
+ }
+
+ id operator()(const double &value) const {
+ return @(value);
+ }
+
+ id operator()(const std::string &value) const {
+ return @(value.c_str());
+ }
+
+ id operator()(const std::vector<mbgl::Value> &values) const {
+ NSMutableArray *objects = [NSMutableArray arrayWithCapacity:values.size()];
+ for (const auto &v : values) {
+ [objects addObject:mbgl::Value::visit(v, *this)];
+ }
+ return objects;
+ }
+
+ id operator()(const std::unordered_map<std::string, mbgl::Value> &items) const {
+ NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:items.size()];
+ for (auto &item : items) {
+ attributes[@(item.first.c_str())] = mbgl::Value::visit(item.second, *this);
+ }
+ return attributes;
+ }
+};
+
+/**
+ Transforms an `mbgl::geometry::geometry` type into an instance of the
+ corresponding Objective-C geometry class.
+ */
+template <typename T>
+class GeometryEvaluator {
+public:
+ MGLShape <MGLFeaturePrivate> * operator()(const mbgl::Point<T> &geometry) const {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ feature.coordinate = toLocationCoordinate2D(geometry);
+ return feature;
+ }
+
+ MGLShape <MGLFeaturePrivate> * operator()(const mbgl::LineString<T> &geometry) const {
+ std::vector<CLLocationCoordinate2D> coordinates = toLocationCoordinates2D(geometry);
+ return [MGLPolylineFeature polylineWithCoordinates:&coordinates[0] count:coordinates.size()];
+ }
+
+ MGLShape <MGLFeaturePrivate> * operator()(const mbgl::Polygon<T> &geometry) const {
+ return toShape<MGLPolygonFeature>(geometry);
+ }
+
+ MGLShape <MGLFeaturePrivate> * operator()(const mbgl::MultiPoint<T> &geometry) const {
+ std::vector<CLLocationCoordinate2D> coordinates = toLocationCoordinates2D(geometry);
+ return [[MGLMultiPointFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()];
+ }
+
+ MGLShape <MGLFeaturePrivate> * operator()(const mbgl::MultiLineString<T> &geometry) const {
+ NSMutableArray *polylines = [NSMutableArray arrayWithCapacity:geometry.size()];
+ for (auto &lineString : geometry) {
+ std::vector<CLLocationCoordinate2D> coordinates = toLocationCoordinates2D(lineString);
+ MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:&coordinates[0] count:coordinates.size()];
+ [polylines addObject:polyline];
+ }
+
+ return [MGLMultiPolylineFeature multiPolylineWithPolylines:polylines];
+ }
+
+ MGLShape <MGLFeaturePrivate> * operator()(const mbgl::MultiPolygon<T> &geometry) const {
+ NSMutableArray *polygons = [NSMutableArray arrayWithCapacity:geometry.size()];
+ for (auto &polygon : geometry) {
+ [polygons addObject:toShape(polygon)];
+ }
+
+ return [MGLMultiPolygonFeature multiPolygonWithPolygons:polygons];
+ }
+
+ MGLShape <MGLFeaturePrivate> * operator()(const mapbox::geometry::geometry_collection<T> &collection) const {
+ NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:collection.size()];
+ for (auto &geometry : collection) {
+ // This is very much like the transformation that happens in MGLFeaturesFromMBGLFeatures(), but these are raw geometries with no associated feature IDs or attributes.
+ MGLShape <MGLFeaturePrivate> *shape = mapbox::geometry::geometry<T>::visit(geometry, *this);
+ [shapes addObject:shape];
+ }
+ return [MGLShapeCollectionFeature shapeCollectionWithShapes:shapes];
+ }
+
+private:
+ static CLLocationCoordinate2D toLocationCoordinate2D(const mbgl::Point<T> &point) {
+ return CLLocationCoordinate2DMake(point.y, point.x);
+ }
+
+ static std::vector<CLLocationCoordinate2D> toLocationCoordinates2D(const std::vector<mbgl::Point<T>> &points) {
+ std::vector<CLLocationCoordinate2D> coordinates;
+ coordinates.reserve(points.size());
+ std::transform(points.begin(), points.end(), std::back_inserter(coordinates), toLocationCoordinate2D);
+ return coordinates;
+ }
+
+ template<typename U = MGLPolygon>
+ static U *toShape(const mbgl::Polygon<T> &geometry) {
+ auto &linearRing = geometry.front();
+ std::vector<CLLocationCoordinate2D> coordinates = toLocationCoordinates2D(linearRing);
+ NSMutableArray *innerPolygons;
+ if (geometry.size() > 1) {
+ innerPolygons = [NSMutableArray arrayWithCapacity:geometry.size() - 1];
+ for (auto iter = geometry.begin() + 1; iter != geometry.end(); iter++) {
+ auto &innerRing = *iter;
+ std::vector<CLLocationCoordinate2D> coordinates = toLocationCoordinates2D(innerRing);
+ MGLPolygon *innerPolygon = [MGLPolygon polygonWithCoordinates:&coordinates[0] count:coordinates.size()];
+ [innerPolygons addObject:innerPolygon];
+ }
+ }
+
+ return [U polygonWithCoordinates:&coordinates[0] count:coordinates.size() interiorPolygons:innerPolygons];
+ }
+};
+
+NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features) {
+ NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:features.size()];
+ for (const auto &feature : features) {
+ NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:feature.properties.size()];
+ for (auto &pair : feature.properties) {
+ auto &value = pair.second;
+ PropertyValueEvaluator evaluator;
+ attributes[@(pair.first.c_str())] = mbgl::Value::visit(value, evaluator);
+ }
+
+ GeometryEvaluator<double> evaluator;
+ MGLShape <MGLFeaturePrivate> *shape = mapbox::geometry::geometry<double>::visit(feature.geometry, evaluator);
+ if (feature.id) {
+ shape.identifier = @(*feature.id);
+ }
+ shape.attributes = attributes;
+ [shapes addObject:shape];
+ }
+ return shapes;
+}
diff --git a/platform/darwin/src/MGLFeature_Private.h b/platform/darwin/src/MGLFeature_Private.h
new file mode 100644
index 0000000000..fbc7f88559
--- /dev/null
+++ b/platform/darwin/src/MGLFeature_Private.h
@@ -0,0 +1,11 @@
+#import "MGLFeature.h"
+#import "MGLShape.h"
+
+#import <mbgl/util/geo.hpp>
+#import <mbgl/util/feature.hpp>
+
+/**
+ Returns an array of `MGLFeature` objects converted from the given vector of
+ vector tile features.
+ */
+NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features);
diff --git a/platform/darwin/src/MGLGeometry_Private.h b/platform/darwin/src/MGLGeometry_Private.h
index 0538cd94ea..fc57460128 100644
--- a/platform/darwin/src/MGLGeometry_Private.h
+++ b/platform/darwin/src/MGLGeometry_Private.h
@@ -6,6 +6,7 @@
#endif
#import <mbgl/util/geo.hpp>
+#import <mbgl/util/geometry.hpp>
/// Returns the smallest rectangle that contains both the given rectangle and
/// the given point.
@@ -15,6 +16,10 @@ NS_INLINE mbgl::LatLng MGLLatLngFromLocationCoordinate2D(CLLocationCoordinate2D
return mbgl::LatLng(coordinate.latitude, coordinate.longitude);
}
+NS_INLINE mbgl::Point<double> MGLPointFromLocationCoordinate2D(CLLocationCoordinate2D coordinate) {
+ return mbgl::Point<double>(coordinate.longitude, coordinate.latitude);
+}
+
NS_INLINE CLLocationCoordinate2D MGLLocationCoordinate2DFromLatLng(mbgl::LatLng latLng) {
return CLLocationCoordinate2DMake(latLng.latitude, latLng.longitude);
}
diff --git a/platform/darwin/src/MGLMultiPoint.h b/platform/darwin/src/MGLMultiPoint.h
index 041c52e8f2..2d6b327086 100644
--- a/platform/darwin/src/MGLMultiPoint.h
+++ b/platform/darwin/src/MGLMultiPoint.h
@@ -17,7 +17,10 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface MGLMultiPoint : MGLShape
-/** The number of points associated with the shape. (read-only) */
+/** The array of coordinates associated with the shape. */
+@property (nonatomic, readonly) CLLocationCoordinate2D *coordinates NS_RETURNS_INNER_POINTER;
+
+/** The number of coordinates associated with the shape. (read-only) */
@property (nonatomic, readonly) NSUInteger pointCount;
/**
diff --git a/platform/darwin/src/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm
index a864b7bce7..6084535d05 100644
--- a/platform/darwin/src/MGLMultiPoint.mm
+++ b/platform/darwin/src/MGLMultiPoint.mm
@@ -14,7 +14,6 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) {
@implementation MGLMultiPoint
{
- CLLocationCoordinate2D *_coords;
size_t _count;
MGLCoordinateBounds _bounds;
}
@@ -27,13 +26,13 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) {
if (self)
{
_count = count;
- _coords = (CLLocationCoordinate2D *)malloc(_count * sizeof(CLLocationCoordinate2D));
+ _coordinates = (CLLocationCoordinate2D *)malloc(_count * sizeof(CLLocationCoordinate2D));
mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
for (NSUInteger i = 0; i < _count; i++)
{
- _coords[i] = coords[i];
+ _coordinates[i] = coords[i];
bounds.extend(mbgl::LatLng(coords[i].latitude, coords[i].longitude));
}
@@ -45,7 +44,7 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) {
- (void)dealloc
{
- free(_coords);
+ free(_coordinates);
}
- (CLLocationCoordinate2D)coordinate
@@ -59,7 +58,7 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) {
assert(_count > 0);
- return CLLocationCoordinate2DMake(_coords[0].latitude, _coords[0].longitude);
+ return CLLocationCoordinate2DMake(_coordinates[0].latitude, _coordinates[0].longitude);
}
- (NSUInteger)pointCount
@@ -89,7 +88,7 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) {
for (NSUInteger i = range.location; i < range.location + range.length; i++)
{
- coords[index] = _coords[i];
+ coords[index] = _coordinates[i];
index++;
}
}
@@ -104,28 +103,9 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) {
return MGLLatLngBoundsFromCoordinateBounds(_bounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds));
}
-- (void)addShapeAnnotationObjectToCollection:(std::vector<mbgl::ShapeAnnotation> &)shapes withDelegate:(id <MGLMultiPointDelegate>)delegate {
- NSUInteger count = self.pointCount;
- if (count == 0) {
- return;
- }
-
- CLLocationCoordinate2D *coordinates = (CLLocationCoordinate2D *)malloc(count * sizeof(CLLocationCoordinate2D));
- NSAssert(coordinates, @"Unable to allocate annotation with %lu points", (unsigned long)count);
- [self getCoordinates:coordinates range:NSMakeRange(0, count)];
-
- mbgl::AnnotationSegment segment;
- segment.reserve(count);
- for (NSUInteger i = 0; i < count; i++) {
- segment.push_back(MGLLatLngFromLocationCoordinate2D(coordinates[i]));
- }
- free(coordinates);
- shapes.emplace_back(mbgl::AnnotationSegments {{ segment }},
- [self shapeAnnotationPropertiesObjectWithDelegate:delegate]);
-}
-
-- (mbgl::ShapeAnnotation::Properties)shapeAnnotationPropertiesObjectWithDelegate:(__unused id <MGLMultiPointDelegate>)delegate {
- return mbgl::ShapeAnnotation::Properties();
+- (mbgl::Annotation)annotationObjectWithDelegate:(__unused id <MGLMultiPointDelegate>)delegate {
+ NSAssert(NO, @"Cannot add an annotation from an instance of %@", NSStringFromClass([self class]));
+ return mbgl::SymbolAnnotation({mbgl::Point<double>()});
}
- (NSString *)description
diff --git a/platform/darwin/src/MGLMultiPoint_Private.h b/platform/darwin/src/MGLMultiPoint_Private.h
index c1f1fa1584..aa52a02fcb 100644
--- a/platform/darwin/src/MGLMultiPoint_Private.h
+++ b/platform/darwin/src/MGLMultiPoint_Private.h
@@ -3,7 +3,7 @@
#import "MGLGeometry.h"
#import "MGLTypes.h"
-#import <mbgl/annotation/shape_annotation.hpp>
+#import <mbgl/annotation/annotation.hpp>
#import <vector>
#import <CoreGraphics/CoreGraphics.h>
@@ -21,11 +21,8 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count;
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds;
-/** Adds a shape annotation to the given vector by asking the delegate for style values. */
-- (void)addShapeAnnotationObjectToCollection:(std::vector<mbgl::ShapeAnnotation> &)shapes withDelegate:(id <MGLMultiPointDelegate>)delegate;
-
-/** Constructs a shape annotation properties object by asking the delegate for style values. */
-- (mbgl::ShapeAnnotation::Properties)shapeAnnotationPropertiesObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate;
+/** Constructs a shape annotation object, asking the delegate for style values. */
+- (mbgl::Annotation)annotationObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate;
@end
diff --git a/platform/darwin/src/MGLPolygon.h b/platform/darwin/src/MGLPolygon.h
index 1a158874bb..3d5b36abb6 100644
--- a/platform/darwin/src/MGLPolygon.h
+++ b/platform/darwin/src/MGLPolygon.h
@@ -17,6 +17,17 @@ NS_ASSUME_NONNULL_BEGIN
@interface MGLPolygon : MGLMultiPoint <MGLOverlay>
/**
+ The array of polygons nested inside the receiver.
+
+ The area occupied by any interior polygons is excluded from the overall shape.
+ Interior polygons should not overlap. An interior polygon should not have
+ interior polygons of its own.
+
+ If there are no interior polygons, the value of this property is `nil`.
+ */
+@property (nonatomic, nullable, readonly) NS_ARRAY_OF(MGLPolygon *) *interiorPolygons;
+
+/**
Creates and returns an `MGLPolygon` object from the specified set of
coordinates.
@@ -25,8 +36,48 @@ NS_ASSUME_NONNULL_BEGIN
@param count The number of items in the `coords` array.
@return A new polygon object.
*/
-+ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords
- count:(NSUInteger)count;
++ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count;
+
+/**
+ Creates and returns an `MGLPolygon` object from the specified set of
+ coordinates and interior polygons.
+
+ @param coords The array of coordinates defining the shape. The data in this
+ array is copied to the new object.
+ @param count The number of items in the `coords` array.
+ @param interiorPolygons An array of `MGLPolygon` objects that define regions
+ excluded from the overall shape. If this array is `nil` or empty, the shape
+ is considered to have no interior polygons.
+ @return A new polygon object.
+ */
++ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count interiorPolygons:(nullable NS_ARRAY_OF(MGLPolygon *) *)interiorPolygons;
+
+@end
+
+/**
+ The `MGLMultiPolygon` class represents a shape consisting of one or more
+ polygons that do not overlap. For example, you would use an `MGLMultiPolygon`
+ object to represent an atoll together with an island in the atoll’s lagoon:
+ the atoll itself would be one `MGLPolygon` object, while the inner island would
+ be another.
+
+ @note `MGLMultiPolygon` objects cannot be added to a map view using
+ `-[MGLMapView addAnnotations:]` and related methods.
+ */
+@interface MGLMultiPolygon : MGLShape <MGLOverlay>
+
+/**
+ An array of polygons forming the multipolygon.
+ */
+@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLPolygon *) *polygons;
+
+/**
+ Creates and returns a multipolygon object consisting of the given polygons.
+
+ @param polygons The array of polygons defining the shape.
+ @return A new multipolygon object.
+ */
++ (instancetype)multiPolygonWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons;
@end
diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm
index 5019385cb2..c009d9e3d6 100644
--- a/platform/darwin/src/MGLPolygon.mm
+++ b/platform/darwin/src/MGLPolygon.mm
@@ -1,28 +1,90 @@
#import "MGLPolygon.h"
#import "MGLMultiPoint_Private.h"
+#import "MGLGeometry_Private.h"
@implementation MGLPolygon
@dynamic overlayBounds;
-+ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords
- count:(NSUInteger)count
-{
- return [[self alloc] initWithCoordinates:coords count:count];
-}
-
-- (mbgl::ShapeAnnotation::Properties)shapeAnnotationPropertiesObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate {
- mbgl::ShapeAnnotation::Properties shapeProperties = [super shapeAnnotationPropertiesObjectWithDelegate:delegate];
-
- mbgl::FillAnnotationProperties fillProperties;
- fillProperties.opacity = [delegate alphaForShapeAnnotation:self];
- fillProperties.outlineColor = [delegate strokeColorForShapeAnnotation:self];
- fillProperties.color = [delegate fillColorForPolygonAnnotation:self];
-
- shapeProperties.set<mbgl::FillAnnotationProperties>(fillProperties);
-
- return shapeProperties;
++ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count {
+ return [self polygonWithCoordinates:coords count:count interiorPolygons:nil];
+}
+
++ (instancetype)polygonWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count interiorPolygons:(NSArray<MGLPolygon *> *)interiorPolygons {
+ return [[self alloc] initWithCoordinates:coords count:count interiorPolygons:interiorPolygons];
+}
+
+- (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count interiorPolygons:(NSArray<MGLPolygon *> *)interiorPolygons {
+ if (self = [super initWithCoordinates:coords count:count]) {
+ if (interiorPolygons.count) {
+ _interiorPolygons = interiorPolygons;
+ }
+ }
+ return self;
+}
+
+- (mbgl::LinearRing<double>)ring {
+ NSUInteger count = self.pointCount;
+ CLLocationCoordinate2D *coordinates = self.coordinates;
+
+ mbgl::LinearRing<double> result;
+ result.reserve(self.pointCount);
+ for (NSUInteger i = 0; i < count; i++) {
+ result.push_back(mbgl::Point<double>(coordinates[i].longitude, coordinates[i].latitude));
+ }
+ return result;
+}
+
+- (mbgl::Annotation)annotationObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate {
+ mbgl::Polygon<double> geometry;
+ geometry.push_back(self.ring);
+ for (MGLPolygon *polygon in self.interiorPolygons) {
+ geometry.push_back(polygon.ring);
+ }
+
+ mbgl::FillAnnotation annotation { geometry };
+ annotation.opacity = [delegate alphaForShapeAnnotation:self];
+ annotation.outlineColor = [delegate strokeColorForShapeAnnotation:self];
+ annotation.color = [delegate fillColorForPolygonAnnotation:self];
+
+ return annotation;
+}
+
+@end
+
+@interface MGLMultiPolygon ()
+
+@property (nonatomic, copy, readwrite) NS_ARRAY_OF(MGLPolygon *) *polygons;
+
+@end
+
+@implementation MGLMultiPolygon {
+ MGLCoordinateBounds _overlayBounds;
+}
+
+@synthesize overlayBounds = _overlayBounds;
+
++ (instancetype)multiPolygonWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons {
+ return [[self alloc] initWithPolygons:polygons];
+}
+
+- (instancetype)initWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons {
+ if (self = [super init]) {
+ _polygons = polygons;
+
+ mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
+
+ for (MGLPolygon *polygon in _polygons) {
+ bounds.extend(MGLLatLngBoundsFromCoordinateBounds(polygon.overlayBounds));
+ }
+ _overlayBounds = MGLCoordinateBoundsFromLatLngBounds(bounds);
+ }
+ return self;
+}
+
+- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
+ return MGLLatLngBoundsFromCoordinateBounds(_overlayBounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds));
}
@end
diff --git a/platform/darwin/src/MGLPolyline.h b/platform/darwin/src/MGLPolyline.h
index 5e45513735..78d9649751 100644
--- a/platform/darwin/src/MGLPolyline.h
+++ b/platform/darwin/src/MGLPolyline.h
@@ -30,4 +30,31 @@ NS_ASSUME_NONNULL_BEGIN
@end
+/**
+ The `MGLMultiPolyline` class represents a shape consisting of one or more
+ polylines. For example, you could use an `MGLMultiPolyline` object to represent
+ both sides of a divided highway (dual carriageway), excluding the median
+ (central reservation): each carriageway would be a distinct `MGLPolyline`
+ object.
+
+ @note `MGLMultiPolyline` objects cannot be added to a map view using
+ `-[MGLMapView addAnnotations:]` and related methods.
+ */
+@interface MGLMultiPolyline : MGLShape <MGLOverlay>
+
+/**
+ An array of polygons forming the multipolyline.
+ */
+@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLPolyline *) *polylines;
+
+/**
+ Creates and returns a multipolyline object consisting of the given polylines.
+
+ @param polylines The array of polylines defining the shape.
+ @return A new multipolyline object.
+ */
++ (instancetype)multiPolylineWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines;
+
+@end
+
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm
index f560a571bc..15ea5a0952 100644
--- a/platform/darwin/src/MGLPolyline.mm
+++ b/platform/darwin/src/MGLPolyline.mm
@@ -1,6 +1,7 @@
#import "MGLPolyline.h"
#import "MGLMultiPoint_Private.h"
+#import "MGLGeometry_Private.h"
@implementation MGLPolyline
@@ -12,17 +13,58 @@
return [[self alloc] initWithCoordinates:coords count:count];
}
-- (mbgl::ShapeAnnotation::Properties)shapeAnnotationPropertiesObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate {
- mbgl::ShapeAnnotation::Properties shapeProperties = [super shapeAnnotationPropertiesObjectWithDelegate:delegate];
-
- mbgl::LineAnnotationProperties lineProperties;
- lineProperties.opacity = [delegate alphaForShapeAnnotation:self];
- lineProperties.color = [delegate strokeColorForShapeAnnotation:self];
- lineProperties.width = [delegate lineWidthForPolylineAnnotation:self];
-
- shapeProperties.set<mbgl::LineAnnotationProperties>(lineProperties);
-
- return shapeProperties;
+- (mbgl::Annotation)annotationObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate {
+ NSUInteger count = self.pointCount;
+ CLLocationCoordinate2D *coordinates = self.coordinates;
+
+ mbgl::LineString<double> geometry;
+ geometry.reserve(self.pointCount);
+ for (NSUInteger i = 0; i < count; i++) {
+ geometry.push_back(mbgl::Point<double>(coordinates[i].longitude, coordinates[i].latitude));
+ }
+
+ mbgl::LineAnnotation annotation { geometry };
+ annotation.opacity = [delegate alphaForShapeAnnotation:self];
+ annotation.color = [delegate strokeColorForShapeAnnotation:self];
+ annotation.width = [delegate lineWidthForPolylineAnnotation:self];
+
+ return annotation;
+}
+
+@end
+
+@interface MGLMultiPolyline ()
+
+@property (nonatomic, copy, readwrite) NS_ARRAY_OF(MGLPolyline *) *polylines;
+
+@end
+
+@implementation MGLMultiPolyline {
+ MGLCoordinateBounds _overlayBounds;
+}
+
+@synthesize overlayBounds = _overlayBounds;
+
++ (instancetype)multiPolylineWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines {
+ return [[self alloc] initWithPolylines:polylines];
+}
+
+- (instancetype)initWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines {
+ if (self = [super init]) {
+ _polylines = polylines;
+
+ mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
+
+ for (MGLPolyline *polyline in _polylines) {
+ bounds.extend(MGLLatLngBoundsFromCoordinateBounds(polyline.overlayBounds));
+ }
+ _overlayBounds = MGLCoordinateBoundsFromLatLngBounds(bounds);
+ }
+ return self;
+}
+
+- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
+ return MGLLatLngBoundsFromCoordinateBounds(_overlayBounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds));
}
@end
diff --git a/platform/darwin/src/MGLShapeCollection.h b/platform/darwin/src/MGLShapeCollection.h
new file mode 100644
index 0000000000..a617223ea7
--- /dev/null
+++ b/platform/darwin/src/MGLShapeCollection.h
@@ -0,0 +1,35 @@
+#import <Foundation/Foundation.h>
+
+#import "MGLShape.h"
+
+#import "MGLTypes.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ The `MGLShapeCollection` class represents a shape consisting of one or more
+ distinct but related shapes that are instances of `MGLShape`. The constituent
+ shapes can be a mixture of different kinds of shapes.
+
+ @note `MGLShapeCollection` objects cannot be added to a map view using
+ `-[MGLMapView addAnnotations:]` and related methods.
+ */
+@interface MGLShapeCollection : MGLShape
+
+/**
+ An array of shapes forming the shape collection.
+ */
+@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLShape *) *shapes;
+
+/**
+ Creates and returns a shape collection consisting of the given shapes.
+
+ @param shapes The array of shapes defining the shape collection. The data in
+ this array is copied to the new object.
+ @return A new shape collection object.
+ */
++ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLShapeCollection.m b/platform/darwin/src/MGLShapeCollection.m
new file mode 100644
index 0000000000..5d42b5a51c
--- /dev/null
+++ b/platform/darwin/src/MGLShapeCollection.m
@@ -0,0 +1,21 @@
+#import "MGLShapeCollection.h"
+
+@implementation MGLShapeCollection
+
++ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes {
+ return [[self alloc] initWithShapes:shapes];
+}
+
+- (instancetype)initWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes {
+ if (self = [super init]) {
+ NSAssert(shapes.count, @"Cannot create an empty shape collection");
+ _shapes = shapes.copy;
+ }
+ return self;
+}
+
+- (CLLocationCoordinate2D)coordinate {
+ return _shapes.firstObject.coordinate;
+}
+
+@end
diff --git a/platform/darwin/test/MGLFeatureTests.mm b/platform/darwin/test/MGLFeatureTests.mm
new file mode 100644
index 0000000000..6cf038d4fb
--- /dev/null
+++ b/platform/darwin/test/MGLFeatureTests.mm
@@ -0,0 +1,160 @@
+#import <Mapbox/Mapbox.h>
+#import <XCTest/XCTest.h>
+
+#import "../../darwin/src/MGLFeature_Private.h"
+
+@interface MGLFeatureTests : XCTestCase
+
+@end
+
+@implementation MGLFeatureTests
+
+- (void)testGeometryConversion {
+ std::vector<mbgl::Feature> features;
+
+ mapbox::geometry::point<double> point = { -90.066667, 29.95 };
+ features.emplace_back(point);
+
+ mapbox::geometry::line_string<double> lineString = {
+ { -84.516667, 39.1 },
+ { -90.066667, 29.95 },
+ };
+ features.emplace_back(lineString);
+
+ mapbox::geometry::polygon<double> polygon = {
+ {
+ { 1, 1 },
+ { 4, 1 },
+ { 4, 4 },
+ { 1, 4 },
+ },
+ {
+ { 2, 2 },
+ { 3, 2 },
+ { 3, 3 },
+ { 2, 3 },
+ },
+ };
+ features.emplace_back(polygon);
+
+ NS_ARRAY_OF(MGLShape <MGLFeature> *) *shapes = MGLFeaturesFromMBGLFeatures(features);
+ XCTAssertEqual(shapes.count, 3, @"All features should be converted into shapes");
+
+ MGLPointFeature *pointShape = (MGLPointFeature *)shapes[0];
+ XCTAssertTrue([pointShape isKindOfClass:[MGLPointFeature class]]);
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:pointShape.coordinate],
+ [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(29.95, -90.066667)]);
+
+ MGLPolylineFeature *polylineShape = (MGLPolylineFeature *)shapes[1];
+ XCTAssertTrue([polylineShape isKindOfClass:[MGLPolylineFeature class]]);
+ XCTAssertEqual(polylineShape.pointCount, 2);
+ CLLocationCoordinate2D polylineCoordinates[2];
+ [polylineShape getCoordinates:polylineCoordinates range:NSMakeRange(0, polylineShape.pointCount)];
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polylineCoordinates[0]],
+ [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(39.1, -84.516667)]);
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polylineCoordinates[1]],
+ [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(29.95, -90.066667)]);
+
+ MGLPolygonFeature *polygonShape = (MGLPolygonFeature *)shapes[2];
+ XCTAssertTrue([polygonShape isKindOfClass:[MGLPolygonFeature class]]);
+ XCTAssertEqual(polygonShape.pointCount, 4);
+ CLLocationCoordinate2D *polygonCoordinates = polygonShape.coordinates;
+ XCTAssertNotEqual(polygonCoordinates, nil);
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polygonCoordinates[0]],
+ [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(1, 1)]);
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polygonCoordinates[1]],
+ [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(1, 4)]);
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polygonCoordinates[2]],
+ [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(4, 4)]);
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polygonCoordinates[3]],
+ [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(4, 1)]);
+ NS_ARRAY_OF(MGLPolygon *) *interiorPolygons = polygonShape.interiorPolygons;
+ XCTAssertEqual(interiorPolygons.count, 1);
+ MGLPolygon *interiorPolygon = interiorPolygons.firstObject;
+ XCTAssertEqual(interiorPolygon.pointCount, 4);
+ CLLocationCoordinate2D interiorPolygonCoordinates[4];
+ [interiorPolygon getCoordinates:interiorPolygonCoordinates range:NSMakeRange(0, interiorPolygon.pointCount)];
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:interiorPolygonCoordinates[0]],
+ [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(2, 2)]);
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:interiorPolygonCoordinates[1]],
+ [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(2, 3)]);
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:interiorPolygonCoordinates[2]],
+ [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(3, 3)]);
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:interiorPolygonCoordinates[3]],
+ [NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(3, 2)]);
+}
+
+- (void)testPropertyConversion {
+ std::vector<mbgl::Feature> features;
+
+ mapbox::geometry::point<double> point = { -90.066667, 29.95 };
+ mbgl::Feature pointFeature(point);
+ pointFeature.id = UINT64_MAX;
+ pointFeature.properties["null"] = nullptr;
+ pointFeature.properties["bool"] = true;
+ pointFeature.properties["unsigned int"] = UINT64_MAX;
+ pointFeature.properties["int"] = INT64_MIN;
+ pointFeature.properties["double"] = DBL_MAX;
+ pointFeature.properties["string"] = std::string("🚏");
+ std::vector<bool> vector;
+ vector.push_back(true);
+ vector.push_back(false);
+ vector.push_back(true);
+ features.push_back(pointFeature);
+
+ NS_ARRAY_OF(MGLShape <MGLFeature> *) *shapes = MGLFeaturesFromMBGLFeatures(features);
+ XCTAssertEqual(shapes.count, 1, @"All features should be converted into shapes");
+
+ MGLShape <MGLFeature> *shape = shapes.firstObject;
+ XCTAssertTrue([shape conformsToProtocol:@protocol(MGLFeature)]);
+ XCTAssertTrue([shape isKindOfClass:[MGLShape class]]);
+
+ NSNumber *identifier = shape.identifier;
+ XCTAssertTrue([identifier isKindOfClass:[NSNumber class]], @"Feature identifier should be NSNumber");
+ XCTAssertEqual(strcmp(identifier.objCType, @encode(uint64_t)), 0, @"Feature identifier should be 64-bit unsigned integer");
+
+ NSNull *null = [shape attributeForKey:@"null"];
+ XCTAssertNotNil(null);
+ XCTAssertTrue([null isKindOfClass:[NSNull class]]);
+ XCTAssertEqual(null, shape.attributes[@"null"]);
+
+ NSNumber *boolean = [shape attributeForKey:@"bool"];
+ XCTAssertNotNil(boolean);
+ XCTAssertTrue([boolean isKindOfClass:[NSNumber class]]);
+#if (TARGET_OS_IPHONE && __LP64__) || TARGET_OS_WATCH
+ XCTAssertEqual(strcmp(boolean.objCType, @encode(char)), 0, @"Boolean property should be converted to bool NSNumber");
+#else
+ XCTAssertEqual(strcmp(boolean.objCType, @encode(BOOL)), 0, @"Boolean property should be converted to bool NSNumber");
+#endif
+ XCTAssertTrue(boolean.boolValue);
+ XCTAssertEqual(boolean, shape.attributes[@"bool"]);
+
+ NSNumber *unsignedInteger = [shape attributeForKey:@"unsigned int"];
+ XCTAssertNotNil(unsignedInteger);
+ XCTAssertTrue([unsignedInteger isKindOfClass:[NSNumber class]]);
+ XCTAssertEqual(strcmp(unsignedInteger.objCType, @encode(uint64_t)), 0, @"Unsigned integer property should be converted to unsigned long long NSNumber");
+ XCTAssertEqual(unsignedInteger.unsignedLongLongValue, UINT64_MAX);
+ XCTAssertEqual(unsignedInteger, shape.attributes[@"unsigned int"]);
+
+ NSNumber *integer = [shape attributeForKey:@"int"];
+ XCTAssertNotNil(integer);
+ XCTAssertTrue([integer isKindOfClass:[NSNumber class]]);
+ XCTAssertEqual(strcmp(integer.objCType, @encode(int64_t)), 0, @"Integer property should be converted to long long NSNumber");
+ XCTAssertEqual(integer.longLongValue, INT64_MIN);
+ XCTAssertEqual(integer, shape.attributes[@"int"]);
+
+ NSNumber *floatingPointNumber = [shape attributeForKey:@"double"];
+ XCTAssertNotNil(floatingPointNumber);
+ XCTAssertTrue([floatingPointNumber isKindOfClass:[NSNumber class]]);
+ XCTAssertEqual(strcmp(floatingPointNumber.objCType, @encode(double)), 0, @"Floating-point number property should be converted to double NSNumber");
+ XCTAssertEqual(floatingPointNumber.doubleValue, DBL_MAX);
+ XCTAssertEqual(floatingPointNumber, shape.attributes[@"double"]);
+
+ NSString *string = [shape attributeForKey:@"string"];
+ XCTAssertNotNil(string);
+ XCTAssertTrue([string isKindOfClass:[NSString class]]);
+ XCTAssertEqualObjects(string, @"🚏");
+ XCTAssertEqual(string, shape.attributes[@"string"]);
+}
+
+@end
diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp
index f5fdb60df7..67e9748a70 100644
--- a/platform/default/glfw_view.cpp
+++ b/platform/default/glfw_view.cpp
@@ -1,8 +1,7 @@
#include <mbgl/platform/default/glfw_view.hpp>
-#include <mbgl/annotation/point_annotation.hpp>
-#include <mbgl/annotation/shape_annotation.hpp>
+#include <mbgl/annotation/annotation.hpp>
#include <mbgl/sprite/sprite_image.hpp>
-#include <mbgl/style/property_transition.hpp>
+#include <mbgl/style/transition_options.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/gl_values.hpp>
#include <mbgl/gl/gl_helper.hpp>
@@ -147,7 +146,7 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
break;
case GLFW_KEY_R:
if (!mods) {
- static const mbgl::PropertyTransition transition { { mbgl::Milliseconds(300) } };
+ static const mbgl::style::TransitionOptions transition { { mbgl::Milliseconds(300) } };
if (view->map->hasClass("night")) {
view->map->removeClass("night", transition);
} else {
@@ -208,10 +207,11 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
}
}
-mbgl::LatLng GLFWView::makeRandomPoint() const {
+mbgl::Point<double> GLFWView::makeRandomPoint() const {
const double x = width * double(std::rand()) / RAND_MAX;
const double y = height * double(std::rand()) / RAND_MAX;
- return map->latLngForPixel({ x, y });
+ mbgl::LatLng latLng = map->latLngForPixel({ x, y });
+ return { latLng.longitude, latLng.latitude };
}
std::shared_ptr<const mbgl::SpriteImage>
@@ -254,59 +254,34 @@ void GLFWView::nextOrientation() {
}
void GLFWView::addRandomCustomPointAnnotations(int count) {
- std::vector<mbgl::PointAnnotation> points;
-
for (int i = 0; i < count; i++) {
static int spriteID = 1;
const auto name = std::string{ "marker-" } + mbgl::util::toString(spriteID++);
map->addAnnotationIcon(name, makeSpriteImage(22, 22, 1));
spriteIDs.push_back(name);
- points.emplace_back(makeRandomPoint(), name);
+ annotationIDs.push_back(map->addAnnotation(mbgl::SymbolAnnotation { makeRandomPoint(), name }));
}
-
- auto newIDs = map->addPointAnnotations(points);
- annotationIDs.insert(annotationIDs.end(), newIDs.begin(), newIDs.end());
}
void GLFWView::addRandomPointAnnotations(int count) {
- std::vector<mbgl::PointAnnotation> points;
-
for (int i = 0; i < count; i++) {
- points.emplace_back(makeRandomPoint(), "default_marker");
+ annotationIDs.push_back(map->addAnnotation(mbgl::SymbolAnnotation { makeRandomPoint(), "default_marker" }));
}
-
- auto newIDs = map->addPointAnnotations(points);
- annotationIDs.insert(annotationIDs.end(), newIDs.begin(), newIDs.end());
}
void GLFWView::addRandomShapeAnnotations(int count) {
- std::vector<mbgl::ShapeAnnotation> shapes;
-
- mbgl::FillAnnotationProperties properties;
- properties.opacity = .1;
-
for (int i = 0; i < count; i++) {
- mbgl::AnnotationSegment triangle;
- triangle.push_back(makeRandomPoint());
- triangle.push_back(makeRandomPoint());
- triangle.push_back(makeRandomPoint());
-
- mbgl::AnnotationSegments segments;
- segments.push_back(triangle);
-
- shapes.emplace_back(segments, properties);
+ mbgl::Polygon<double> triangle;
+ triangle.push_back({ makeRandomPoint(), makeRandomPoint(), makeRandomPoint() });
+ annotationIDs.push_back(map->addAnnotation(mbgl::FillAnnotation { triangle, .1 }));
}
-
- auto newIDs = map->addShapeAnnotations(shapes);
- annotationIDs.insert(annotationIDs.end(), newIDs.begin(), newIDs.end());
}
void GLFWView::clearAnnotations() {
- if (annotationIDs.empty()) {
- return;
+ for (const auto& id : annotationIDs) {
+ map->removeAnnotation(id);
}
- map->removeAnnotations(annotationIDs);
annotationIDs.clear();
}
diff --git a/platform/default/mbgl/storage/offline.cpp b/platform/default/mbgl/storage/offline.cpp
index b13aa05039..d8e0357ae2 100644
--- a/platform/default/mbgl/storage/offline.cpp
+++ b/platform/default/mbgl/storage/offline.cpp
@@ -1,6 +1,6 @@
#include <mbgl/storage/offline.hpp>
#include <mbgl/util/tile_cover.hpp>
-#include <mbgl/source/source_info.hpp>
+#include <mbgl/util/tileset.hpp>
#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
@@ -23,9 +23,9 @@ OfflineTilePyramidRegionDefinition::OfflineTilePyramidRegionDefinition(
}
}
-std::vector<CanonicalTileID> OfflineTilePyramidRegionDefinition::tileCover(SourceType type, uint16_t tileSize, const SourceInfo& info) const {
- double minZ = std::max<double>(util::coveringZoomLevel(minZoom, type, tileSize), info.minZoom);
- double maxZ = std::min<double>(util::coveringZoomLevel(maxZoom, type, tileSize), info.maxZoom);
+std::vector<CanonicalTileID> OfflineTilePyramidRegionDefinition::tileCover(SourceType type, uint16_t tileSize, const Tileset& tileset) const {
+ double minZ = std::max<double>(util::coveringZoomLevel(minZoom, type, tileSize), tileset.minZoom);
+ double maxZ = std::min<double>(util::coveringZoomLevel(maxZoom, type, tileSize), tileset.maxZoom);
assert(minZ >= 0);
assert(maxZ >= 0);
diff --git a/platform/default/mbgl/storage/offline_download.cpp b/platform/default/mbgl/storage/offline_download.cpp
index d694235149..11ca862925 100644
--- a/platform/default/mbgl/storage/offline_download.cpp
+++ b/platform/default/mbgl/storage/offline_download.cpp
@@ -3,8 +3,7 @@
#include <mbgl/storage/file_source.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
-#include <mbgl/style/style_parser.hpp>
-#include <mbgl/layer/symbol_layer.hpp>
+#include <mbgl/style/parser.hpp>
#include <mbgl/text/glyph.hpp>
#include <mbgl/util/tile_cover.hpp>
#include <mbgl/util/mapbox.hpp>
@@ -47,7 +46,7 @@ void OfflineDownload::setState(OfflineRegionDownloadState state) {
observer->statusChanged(status);
}
-std::vector<Resource> OfflineDownload::spriteResources(const StyleParser& parser) const {
+std::vector<Resource> OfflineDownload::spriteResources(const style::Parser& parser) const {
std::vector<Resource> result;
if (!parser.spriteURL.empty()) {
@@ -58,7 +57,7 @@ std::vector<Resource> OfflineDownload::spriteResources(const StyleParser& parser
return result;
}
-std::vector<Resource> OfflineDownload::glyphResources(const StyleParser& parser) const {
+std::vector<Resource> OfflineDownload::glyphResources(const style::Parser& parser) const {
std::vector<Resource> result;
if (!parser.glyphURL.empty()) {
@@ -72,11 +71,11 @@ std::vector<Resource> OfflineDownload::glyphResources(const StyleParser& parser)
return result;
}
-std::vector<Resource> OfflineDownload::tileResources(SourceType type, uint16_t tileSize, const SourceInfo& info) const {
+std::vector<Resource> OfflineDownload::tileResources(SourceType type, uint16_t tileSize, const Tileset& tileset) const {
std::vector<Resource> result;
- for (const auto& tile : definition.tileCover(type, tileSize, info)) {
- result.push_back(Resource::tile(info.tiles[0], definition.pixelRatio, tile.x, tile.y, tile.z));
+ for (const auto& tile : definition.tileCover(type, tileSize, tileset)) {
+ result.push_back(Resource::tile(tileset.tiles[0], definition.pixelRatio, tile.x, tile.y, tile.z));
}
return result;
@@ -95,7 +94,7 @@ OfflineRegionStatus OfflineDownload::getStatus() const {
return result;
}
- StyleParser parser;
+ style::Parser parser;
parser.parse(*styleResponse->data);
result.requiredResourceCountIsPrecise = true;
@@ -104,14 +103,14 @@ OfflineRegionStatus OfflineDownload::getStatus() const {
switch (source->type) {
case SourceType::Vector:
case SourceType::Raster:
- if (source->getInfo()) {
- result.requiredResourceCount += tileResources(source->type, source->tileSize, *source->getInfo()).size();
+ if (source->getTileset()) {
+ result.requiredResourceCount += tileResources(source->type, source->tileSize, *source->getTileset()).size();
} else {
result.requiredResourceCount += 1;
optional<Response> sourceResponse = offlineDatabase.get(Resource::source(source->url));
if (sourceResponse) {
result.requiredResourceCount += tileResources(source->type, source->tileSize,
- *StyleParser::parseTileJSON(*sourceResponse->data, source->url, source->type, source->tileSize)).size();
+ *style::parseTileJSON(*sourceResponse->data, source->url, source->type, source->tileSize)).size();
} else {
result.requiredResourceCountIsPrecise = false;
}
@@ -145,7 +144,7 @@ void OfflineDownload::activateDownload() {
ensureResource(Resource::style(definition.styleURL), [&] (Response styleResponse) {
status.requiredResourceCountIsPrecise = true;
- StyleParser parser;
+ style::Parser parser;
parser.parse(*styleResponse.data);
for (const auto& source : parser.sources) {
@@ -156,14 +155,14 @@ void OfflineDownload::activateDownload() {
switch (type) {
case SourceType::Vector:
case SourceType::Raster:
- if (source->getInfo()) {
- ensureTiles(type, tileSize, *source->getInfo());
+ if (source->getTileset()) {
+ ensureTiles(type, tileSize, *source->getTileset());
} else {
status.requiredResourceCountIsPrecise = false;
requiredSourceURLs.insert(url);
ensureResource(Resource::source(url), [=] (Response sourceResponse) {
- ensureTiles(type, tileSize, *StyleParser::parseTileJSON(*sourceResponse.data, url, type, tileSize));
+ ensureTiles(type, tileSize, *style::parseTileJSON(*sourceResponse.data, url, type, tileSize));
requiredSourceURLs.erase(url);
if (requiredSourceURLs.empty()) {
@@ -199,7 +198,7 @@ void OfflineDownload::deactivateDownload() {
requests.clear();
}
-void OfflineDownload::ensureTiles(SourceType type, uint16_t tileSize, const SourceInfo& info) {
+void OfflineDownload::ensureTiles(SourceType type, uint16_t tileSize, const Tileset& info) {
for (const auto& resource : tileResources(type, tileSize, info)) {
ensureResource(resource);
}
diff --git a/platform/default/mbgl/storage/offline_download.hpp b/platform/default/mbgl/storage/offline_download.hpp
index 706cdf98d8..1a0d7536d8 100644
--- a/platform/default/mbgl/storage/offline_download.hpp
+++ b/platform/default/mbgl/storage/offline_download.hpp
@@ -1,7 +1,6 @@
- #pragma once
+#pragma once
#include <mbgl/storage/offline.hpp>
-#include <mbgl/style/types.hpp>
#include <list>
#include <set>
@@ -14,9 +13,11 @@ class FileSource;
class AsyncRequest;
class Resource;
class Response;
-class SourceInfo;
-class StyleParser;
-class Source;
+class Tileset;
+
+namespace style {
+class Parser;
+}
/**
* Coordinates the request and storage of all resources for an offline region.
@@ -37,9 +38,9 @@ private:
void activateDownload();
void deactivateDownload();
- std::vector<Resource> spriteResources(const StyleParser&) const;
- std::vector<Resource> glyphResources(const StyleParser&) const;
- std::vector<Resource> tileResources(SourceType, uint16_t, const SourceInfo&) const;
+ std::vector<Resource> spriteResources(const style::Parser&) const;
+ std::vector<Resource> glyphResources(const style::Parser&) const;
+ std::vector<Resource> tileResources(SourceType, uint16_t, const Tileset&) const;
/*
* Ensure that the resource is stored in the database, requesting it if necessary.
@@ -47,7 +48,7 @@ private:
* is deactivated, all in progress requests are cancelled.
*/
void ensureResource(const Resource&, std::function<void (Response)> = {});
- void ensureTiles(SourceType, uint16_t, const SourceInfo&);
+ void ensureTiles(SourceType, uint16_t, const Tileset&);
bool checkTileCountLimit(const Resource& resource);
int64_t id;
diff --git a/platform/default/resources/api_mapbox_com-digicert.der b/platform/default/resources/api_mapbox_com-digicert.der
index d84cee3908..e8ef427f33 100644
--- a/platform/default/resources/api_mapbox_com-digicert.der
+++ b/platform/default/resources/api_mapbox_com-digicert.der
Binary files differ
diff --git a/platform/default/resources/api_mapbox_com-geotrust.der b/platform/default/resources/api_mapbox_com-geotrust.der
index 116144bc0c..1c7331dedc 100644
--- a/platform/default/resources/api_mapbox_com-geotrust.der
+++ b/platform/default/resources/api_mapbox_com-geotrust.der
Binary files differ
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index 90ebea58a2..8c2eeca35f 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -10,8 +10,13 @@ Mapbox welcomes participation and contributions from everyone. Please read [CON
- The user dot now moves smoothly between user location updates while user location tracking is disabled. ([#1582](https://github.com/mapbox/mapbox-gl-native/pull/1582))
- An MGLAnnotation can be relocated by changing its `coordinate` property in a KVO-compliant way. An MGLMultiPoint cannot be relocated. ([#3835](https://github.com/mapbox/mapbox-gl-native/pull/3835))
- Setting the `image` property of an MGLAnnotationImage to `nil` resets it to the default red pin image and reclaims resources that can be used to customize additional annotations. ([#3835](https://github.com/mapbox/mapbox-gl-native/pull/3835))
+- Added methods to MGLMapView for obtaining the underlying map data rendered by the current style, along with additional classes to represent complex geometry in that data. ([#5110](https://github.com/mapbox/mapbox-gl-native/pull/5110))
+- An MGLPolygon can now have interior polygons, representing holes knocked out of the overall shape. ([#5110](https://github.com/mapbox/mapbox-gl-native/pull/5110))
- `MGLOfflinePackProgress` now indicates how many tiles have been downloaded and how much space they take up. ([#4874](https://github.com/mapbox/mapbox-gl-native/pull/4874))
- The compass, user dot, and visible annotations are now accessible to VoiceOver users. ([#1496](https://github.com/mapbox/mapbox-gl-native/pull/1496))
+- Fixed an issue (speculatively) where the tile cache could be included in iCloud backups. ([#5124](https://github.com/mapbox/mapbox-gl-native/pull/5124))
+- Improved performance viewing regions with large landcover polygons when viewing a style that uses the Mapbox Streets source. ([#2444](https://github.com/mapbox/mapbox-gl-native/pull/2444))
+- Fixed a memory leak when using raster resources. ([#5141](https://github.com/mapbox/mapbox-gl-native/pull/5141))
- The SDK is now localizable. No localizations are currently provided, other than English, but if you need a particular localization, you can install the SDK manually and drop a .lproj folder into the framework. ([#4783](https://github.com/mapbox/mapbox-gl-native/pull/4783))
- Fixed an issue preventing KVO change notifications from being generated on MGLMapView’s `userTrackingMode` key path when `-setUserTrackingMode:animated:` is called. ([#4724](https://github.com/mapbox/mapbox-gl-native/pull/4724))
- Rendering now occurs on the main thread, fixing a hang when calling `-[MGLMapView styleURL]` before the map view has fully loaded or while the application is in the background. ([#2909](https://github.com/mapbox/mapbox-gl-native/pull/2909))
@@ -22,14 +27,12 @@ Mapbox welcomes participation and contributions from everyone. Please read [CON
- Added a `-reloadStyle:` action to MGLMapView to force a reload of the current style. ([#4728](https://github.com/mapbox/mapbox-gl-native/pull/4728))
- A more specific user agent string is now sent with style and tile requests. ([#4012](https://github.com/mapbox/mapbox-gl-native/pull/4012))
- Mapbox Telemetry is automatically disabled while the host application is running in the iOS Simulator. ([#4726](https://github.com/mapbox/mapbox-gl-native/pull/4726))
+- Fixed an issue preventing `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` from being called when returning to the view controller containing the map view from another view controller. ([#5164](https://github.com/mapbox/mapbox-gl-native/pull/5164))
- Suppressed “Unable to make space for entry” console spew. ([#4708](https://github.com/mapbox/mapbox-gl-native/pull/4708))
- Removed unused SVG files from the SDK’s resource bundle. ([#4641](https://github.com/mapbox/mapbox-gl-native/pull/4641))
- Deprecated `-[MGLMapView emptyMemoryCache]`. ([#4725](https://github.com/mapbox/mapbox-gl-native/pull/4725))
- Added `MGLCoordinateInCoordinateBounds()`, a function that tests whether or not a coordinate is in a given bounds. ([#5053](https://github.com/mapbox/mapbox-gl-native/pull/5053))
-- An MGLAnnotationView can be repositioned in relation to the associated MGLAnnotation.coordinate by changing its `centerOffset` property. ([#5059](https://github.com/mapbox/mapbox-gl-native/issues/5059))
-- An MGLAnnotationView can be rotated to match the rotation pitch of the associated map view.
- Added a new option to `MGLMapDebugMaskOptions`, `MGLMapDebugWireframesMask`, that shows wireframes instead of the usual rendered output. ([#4359](https://github.com/mapbox/mapbox-gl-native/pull/4359))
-- Fixed an issue (speculatively) where the tile cache could be included in iCloud backups. ([#5124](https://github.com/mapbox/mapbox-gl-native/pull/5124))
## 3.2.2
diff --git a/platform/ios/DEVELOPING.md b/platform/ios/DEVELOPING.md
index d1be5d703e..67481d4f8a 100644
--- a/platform/ios/DEVELOPING.md
+++ b/platform/ios/DEVELOPING.md
@@ -36,6 +36,7 @@ If you don’t have an Apple Developer account, change the destination to a simu
You can customize the build output by passing the following arguments into the `make` invocation:
+* `BUILDTYPE=Release` will optimize for distribution. Defaults to `Debug`.
* `BUILD_DEVICE=false` builds only for the iOS Simulator.
* `FORMAT=dynamic` builds only a dynamic framework. `FORMAT=static` builds only a static framework, for compatibility with iOS 7.x.
* `SYMBOLS=NO` strips the build output of any debug symbols, yielding much smaller binaries.
@@ -80,13 +81,6 @@ To add or update text that the user may see in the iOS SDK:
`make test-ios` builds and runs unit tests of cross-platform code as well as the SDK.
-Before you can run UI tests of the SDK, check out KIF and OHHTTPStubs via Git submodules:
-
-```bash
-git submodule init
-git submodule update
-```
-
Before you can run unit tests of the cross-platform code on the command line, install ios-sim version 3.2.0 (not any other version):
```bash
diff --git a/platform/ios/Mapbox-iOS-SDK-symbols.podspec b/platform/ios/Mapbox-iOS-SDK-symbols.podspec
index 492d20abe1..a29e9467ea 100644
--- a/platform/ios/Mapbox-iOS-SDK-symbols.podspec
+++ b/platform/ios/Mapbox-iOS-SDK-symbols.podspec
@@ -1,7 +1,7 @@
Pod::Spec.new do |m|
m.name = 'Mapbox-iOS-SDK'
- m.version = '3.3.0-alpha.3-symbols'
+ m.version = '3.3.0-beta.1-symbols'
m.summary = 'Open source vector map solution for iOS with full styling capabilities.'
m.description = 'Open source, OpenGL-based vector map solution for iOS with full styling capabilities and Cocoa Touch APIs.'
diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec
index dcd51a1b0f..33b83e5370 100644
--- a/platform/ios/Mapbox-iOS-SDK.podspec
+++ b/platform/ios/Mapbox-iOS-SDK.podspec
@@ -1,7 +1,7 @@
Pod::Spec.new do |m|
m.name = 'Mapbox-iOS-SDK'
- m.version = '3.3.0-alpha.3'
+ m.version = '3.3.0-beta.1'
m.summary = 'Open source vector map solution for iOS with full styling capabilities.'
m.description = 'Open source, OpenGL-based vector map solution for iOS with full styling capabilities and Cocoa Touch APIs.'
diff --git a/platform/ios/app/MBXAnnotationView.m b/platform/ios/app/MBXAnnotationView.m
index 8cbe07a367..890881a316 100644
--- a/platform/ios/app/MBXAnnotationView.m
+++ b/platform/ios/app/MBXAnnotationView.m
@@ -12,7 +12,7 @@
[super layoutSubviews];
if (!self.centerView) {
self.backgroundColor = [UIColor blueColor];
- self.centerView = [[UIView alloc] initWithFrame:CGRectInset(self.bounds, 5.0, 5.0)];
+ self.centerView = [[UIView alloc] initWithFrame:CGRectInset(self.bounds, 1.0, 1.0)];
self.centerView.backgroundColor = self.centerColor;
[self addSubview:self.centerView];
}
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index 414329b437..70f777422d 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -306,6 +306,22 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
free(polygonCoordinates);
}
+
+ CLLocationCoordinate2D innerCoordinates[] = {
+ CLLocationCoordinate2DMake(-5, -5),
+ CLLocationCoordinate2DMake(-5, 5),
+ CLLocationCoordinate2DMake(5, 5),
+ CLLocationCoordinate2DMake(5, -5),
+ };
+ MGLPolygon *innerPolygon = [MGLPolygon polygonWithCoordinates:innerCoordinates count:sizeof(innerCoordinates) / sizeof(innerCoordinates[0])];
+ CLLocationCoordinate2D outerCoordinates[] = {
+ CLLocationCoordinate2DMake(-10, -20),
+ CLLocationCoordinate2DMake(-10, 10),
+ CLLocationCoordinate2DMake(10, 10),
+ CLLocationCoordinate2DMake(10, -10),
+ };
+ MGLPolygon *outerPolygon = [MGLPolygon polygonWithCoordinates:outerCoordinates count:sizeof(outerCoordinates) / sizeof(outerCoordinates[0]) interiorPolygons:@[innerPolygon]];
+ [self.mapView addAnnotation:outerPolygon];
}
else if (buttonIndex == actionSheet.firstOtherButtonIndex + 10)
{
@@ -395,13 +411,22 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
{
if (longPress.state == UIGestureRecognizerStateBegan)
{
- MBXDroppedPinAnnotation *point = [[MBXDroppedPinAnnotation alloc] init];
- point.coordinate = [self.mapView convertPoint:[longPress locationInView:longPress.view]
+ CGPoint point = [longPress locationInView:longPress.view];
+ NSArray *features = [self.mapView visibleFeaturesAtPoint:point];
+ NSString *title;
+ for (id <MGLFeature> feature in features) {
+ if (!title) {
+ title = [feature attributeForKey:@"name_en"] ?: [feature attributeForKey:@"name"];
+ }
+ }
+
+ MBXDroppedPinAnnotation *pin = [[MBXDroppedPinAnnotation alloc] init];
+ pin.coordinate = [self.mapView convertPoint:point
toCoordinateFromView:self.mapView];
- point.title = @"Dropped Pin";
- point.subtitle = [[[MGLCoordinateFormatter alloc] init] stringFromCoordinate:point.coordinate];
+ pin.title = title ?: @"Dropped Pin";
+ pin.subtitle = [[[MGLCoordinateFormatter alloc] init] stringFromCoordinate:pin.coordinate];
// Calling `addAnnotation:` on mapView is not required since `selectAnnotation:animated` has the side effect of adding the annotation if required
- [self.mapView selectAnnotation:point animated:YES];
+ [self.mapView selectAnnotation:pin animated:YES];
}
}
@@ -549,13 +574,28 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
- (MGLAnnotationView *)mapView:(MGLMapView *)mapView viewForAnnotation:(id<MGLAnnotation>)annotation
{
+ // Use GL backed pins for dropped pin annotations
+ if ([annotation isMemberOfClass:[MBXDroppedPinAnnotation class]])
+ {
+ return nil;
+ }
+
MBXAnnotationView *annotationView = (MBXAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:MBXViewControllerAnnotationViewReuseIdentifer];
if (!annotationView)
{
annotationView = [[MBXAnnotationView alloc] initWithReuseIdentifier:MBXViewControllerAnnotationViewReuseIdentifer];
- annotationView.frame = CGRectMake(0, 0, 40, 40);
+ annotationView.frame = CGRectMake(0, 0, 10, 10);
annotationView.centerColor = [UIColor whiteColor];
- annotationView.flat = YES;
+
+ // uncomment to flatten the annotation view against the map when the map is tilted
+ // this currently causes severe performance issues when more than 2k annotations are visible
+ // annotationView.flat = YES;
+
+ // uncomment to force annotation view to maintain a constant size when the map is tilted
+ // by default, annotation views will shrink and grow as the move towards and away from the
+ // horizon. Relatedly, annotations backed by GL sprites ONLY scale with viewing distance currently.
+ // annotationView.scalesWithViewingDistance = NO;
+
} else {
// orange indicates that the annotation view was reused
annotationView.centerColor = [UIColor orangeColor];
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index 6271fc455b..cb1bd70199 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -7,12 +7,16 @@
objects = {
/* Begin PBXBuildFile section */
- 4018B1C71CDC287F00F666AF /* MGLAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4018B1C41CDC277F00F666AF /* MGLAnnotationView.m */; };
- 4018B1C81CDC287F00F666AF /* MGLAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4018B1C41CDC277F00F666AF /* MGLAnnotationView.m */; };
+ 4018B1C71CDC287F00F666AF /* MGLAnnotationView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4018B1C41CDC277F00F666AF /* MGLAnnotationView.mm */; };
+ 4018B1C81CDC287F00F666AF /* MGLAnnotationView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4018B1C41CDC277F00F666AF /* MGLAnnotationView.mm */; };
4018B1C91CDC288A00F666AF /* MGLAnnotationView_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4018B1C31CDC277F00F666AF /* MGLAnnotationView_Private.h */; };
4018B1CA1CDC288E00F666AF /* MGLAnnotationView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */; settings = {ATTRIBUTES = (Public, ); }; };
4018B1CB1CDC288E00F666AF /* MGLAnnotationView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 40EDA1C01CFE0E0200D9EA68 /* MGLAnnotationContainerView.h in Headers */ = {isa = PBXBuildFile; fileRef = 40EDA1BD1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.h */; };
+ 40EDA1C11CFE0E0500D9EA68 /* MGLAnnotationContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40EDA1BE1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.m */; };
+ 40EDA1C21CFE0E0500D9EA68 /* MGLAnnotationContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40EDA1BE1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.m */; };
40FDA76B1CCAAA6800442548 /* MBXAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40FDA76A1CCAAA6800442548 /* MBXAnnotationView.m */; };
+ DA0CD5901CF56F6A00A5F5A5 /* MGLFeatureTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */; };
DA17BE301CC4BAC300402C41 /* MGLMapView_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = DA17BE2F1CC4BAC300402C41 /* MGLMapView_Internal.h */; };
DA17BE311CC4BDAA00402C41 /* MGLMapView_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = DA17BE2F1CC4BAC300402C41 /* MGLMapView_Internal.h */; };
DA1DC96A1CB6C6B7006E619F /* MBXCustomCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1DC9671CB6C6B7006E619F /* MBXCustomCalloutView.m */; };
@@ -55,6 +59,8 @@
DA35A2CA1CCAAAD200E826B2 /* NSValue+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DA35A2C71CCAAAD200E826B2 /* NSValue+MGLAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA35A2CB1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2C81CCAAAD200E826B2 /* NSValue+MGLAdditions.m */; };
DA35A2CC1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2C81CCAAAD200E826B2 /* NSValue+MGLAdditions.m */; };
+ DA737EE11D056A4E005BDA16 /* MGLMapViewDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = DA737EE01D056A4E005BDA16 /* MGLMapViewDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ DA737EE21D056A4E005BDA16 /* MGLMapViewDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = DA737EE01D056A4E005BDA16 /* MGLMapViewDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA821D061CCC6D59007508D4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DA821D041CCC6D59007508D4 /* LaunchScreen.storyboard */; };
DA821D071CCC6D59007508D4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DA821D051CCC6D59007508D4 /* Main.storyboard */; };
DA8847D91CBAF91600AB86E3 /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA8847D21CBAF91600AB86E3 /* Mapbox.framework */; };
@@ -228,6 +234,15 @@
DABFB8731CBE9A9900D62B32 /* Mapbox.h in Headers */ = {isa = PBXBuildFile; fileRef = DA88485E1CBAFC2E00AB86E3 /* Mapbox.h */; settings = {ATTRIBUTES = (Public, ); }; };
DAC49C5C1CD02BC9009E1AA3 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DAC49C5F1CD02BC9009E1AA3 /* Localizable.stringsdict */; };
DAC49C5D1CD02BC9009E1AA3 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DAC49C5F1CD02BC9009E1AA3 /* Localizable.stringsdict */; };
+ DAD1656C1CF41981001FF4B9 /* MGLFeature.h in Headers */ = {isa = PBXBuildFile; fileRef = DAD165691CF41981001FF4B9 /* MGLFeature.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ DAD1656D1CF41981001FF4B9 /* MGLFeature.h in Headers */ = {isa = PBXBuildFile; fileRef = DAD165691CF41981001FF4B9 /* MGLFeature.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ DAD1656E1CF41981001FF4B9 /* MGLFeature_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAD1656A1CF41981001FF4B9 /* MGLFeature_Private.h */; };
+ DAD165701CF41981001FF4B9 /* MGLFeature.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAD1656B1CF41981001FF4B9 /* MGLFeature.mm */; };
+ DAD165711CF41981001FF4B9 /* MGLFeature.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAD1656B1CF41981001FF4B9 /* MGLFeature.mm */; };
+ DAD165781CF4CDFF001FF4B9 /* MGLShapeCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = DAD165761CF4CDFF001FF4B9 /* MGLShapeCollection.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ DAD165791CF4CDFF001FF4B9 /* MGLShapeCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = DAD165761CF4CDFF001FF4B9 /* MGLShapeCollection.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ DAD1657A1CF4CDFF001FF4B9 /* MGLShapeCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = DAD165771CF4CDFF001FF4B9 /* MGLShapeCollection.m */; };
+ DAD1657B1CF4CDFF001FF4B9 /* MGLShapeCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = DAD165771CF4CDFF001FF4B9 /* MGLShapeCollection.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -311,11 +326,14 @@
/* Begin PBXFileReference section */
4018B1C31CDC277F00F666AF /* MGLAnnotationView_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationView_Private.h; sourceTree = "<group>"; };
- 4018B1C41CDC277F00F666AF /* MGLAnnotationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAnnotationView.m; sourceTree = "<group>"; };
+ 4018B1C41CDC277F00F666AF /* MGLAnnotationView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAnnotationView.mm; sourceTree = "<group>"; };
4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationView.h; sourceTree = "<group>"; };
402E9DE01CD2C76200FD4519 /* Mapbox.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Mapbox.playground; sourceTree = "<group>"; };
+ 40EDA1BD1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationContainerView.h; sourceTree = "<group>"; };
+ 40EDA1BE1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAnnotationContainerView.m; sourceTree = "<group>"; };
40FDA7691CCAAA6800442548 /* MBXAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBXAnnotationView.h; sourceTree = "<group>"; };
40FDA76A1CCAAA6800442548 /* MBXAnnotationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBXAnnotationView.m; sourceTree = "<group>"; };
+ DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLFeatureTests.mm; path = ../../darwin/test/MGLFeatureTests.mm; sourceTree = "<group>"; };
DA17BE2F1CC4BAC300402C41 /* MGLMapView_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapView_Internal.h; sourceTree = "<group>"; };
DA1DC94A1CB6C1C2006E619F /* Mapbox GL.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mapbox GL.app"; sourceTree = BUILT_PRODUCTS_DIR; };
DA1DC9501CB6C1C2006E619F /* MBXAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBXAppDelegate.h; sourceTree = "<group>"; };
@@ -357,6 +375,7 @@
DA35A2C81CCAAAD200E826B2 /* NSValue+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSValue+MGLAdditions.m"; sourceTree = "<group>"; };
DA35A2D11CCAB25200E826B2 /* jazzy.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = jazzy.yml; sourceTree = "<group>"; };
DA4A26961CB6E795000B7809 /* Mapbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Mapbox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ DA737EE01D056A4E005BDA16 /* MGLMapViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapViewDelegate.h; sourceTree = "<group>"; };
DA821D041CCC6D59007508D4 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
DA821D051CCC6D59007508D4 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
DA8847D21CBAF91600AB86E3 /* Mapbox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Mapbox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -474,6 +493,11 @@
DABCABC01CB80717000A7C39 /* locations.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = locations.hpp; sourceTree = "<group>"; };
DAC07C961CBB2CD6000CB309 /* mbgl.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = mbgl.xcconfig; path = ../../build/ios/mbgl.xcconfig; sourceTree = "<group>"; };
DAC49C621CD07D74009E1AA3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
+ DAD165691CF41981001FF4B9 /* MGLFeature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature.h; sourceTree = "<group>"; };
+ DAD1656A1CF41981001FF4B9 /* MGLFeature_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature_Private.h; sourceTree = "<group>"; };
+ DAD1656B1CF41981001FF4B9 /* MGLFeature.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFeature.mm; sourceTree = "<group>"; };
+ DAD165761CF4CDFF001FF4B9 /* MGLShapeCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeCollection.h; sourceTree = "<group>"; };
+ DAD165771CF4CDFF001FF4B9 /* MGLShapeCollection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLShapeCollection.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -624,6 +648,7 @@
DA35A2C31CCA9F8300E826B2 /* MGLClockDirectionFormatterTests.m */,
DA35A2C41CCA9F8300E826B2 /* MGLCompassDirectionFormatterTests.m */,
DA35A2A91CCA058D00E826B2 /* MGLCoordinateFormatterTests.m */,
+ DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */,
DA2E885C1CC0382C00F24E7B /* MGLGeometryTests.mm */,
DA2E885D1CC0382C00F24E7B /* MGLOfflinePackTests.m */,
DA2E885E1CC0382C00F24E7B /* MGLOfflineRegionTests.m */,
@@ -654,56 +679,19 @@
DA8847DE1CBAFA3E00AB86E3 /* Foundation */ = {
isa = PBXGroup;
children = (
+ DAD165831CF4CFED001FF4B9 /* Categories */,
+ DAD165801CF4CF9A001FF4B9 /* Formatters */,
+ DAD165811CF4CFC4001FF4B9 /* Geometry */,
+ DAD165821CF4CFE3001FF4B9 /* Offline Maps */,
DA8847DF1CBAFA5100AB86E3 /* MGLAccountManager.h */,
DA8847FF1CBAFA6200AB86E3 /* MGLAccountManager_Private.h */,
DA8848001CBAFA6200AB86E3 /* MGLAccountManager.m */,
- DA8847E01CBAFA5100AB86E3 /* MGLAnnotation.h */,
- DA35A2BA1CCA9A6900E826B2 /* MGLClockDirectionFormatter.h */,
- DA35A2B71CCA9A5D00E826B2 /* MGLClockDirectionFormatter.m */,
- DA35A2AF1CCA141D00E826B2 /* MGLCompassDirectionFormatter.h */,
- DA35A2B01CCA141D00E826B2 /* MGLCompassDirectionFormatter.m */,
- DA35A29D1CC9E94C00E826B2 /* MGLCoordinateFormatter.h */,
- DA35A2A01CC9E95F00E826B2 /* MGLCoordinateFormatter.m */,
- DA8847E11CBAFA5100AB86E3 /* MGLGeometry.h */,
- DA8848011CBAFA6200AB86E3 /* MGLGeometry_Private.h */,
- DA8848021CBAFA6200AB86E3 /* MGLGeometry.mm */,
DA8847E21CBAFA5100AB86E3 /* MGLMapCamera.h */,
DA8848031CBAFA6200AB86E3 /* MGLMapCamera.mm */,
- DA8847E31CBAFA5100AB86E3 /* MGLMultiPoint.h */,
- DA8848041CBAFA6200AB86E3 /* MGLMultiPoint_Private.h */,
- DA8848051CBAFA6200AB86E3 /* MGLMultiPoint.mm */,
- DA8847E41CBAFA5100AB86E3 /* MGLOfflinePack.h */,
- DA8848061CBAFA6200AB86E3 /* MGLOfflinePack_Private.h */,
- DA8848071CBAFA6200AB86E3 /* MGLOfflinePack.mm */,
- DA8847E51CBAFA5100AB86E3 /* MGLOfflineRegion.h */,
- DA8848081CBAFA6200AB86E3 /* MGLOfflineRegion_Private.h */,
- DA8847E61CBAFA5100AB86E3 /* MGLOfflineStorage.h */,
- DA8848091CBAFA6200AB86E3 /* MGLOfflineStorage_Private.h */,
- DA88480A1CBAFA6200AB86E3 /* MGLOfflineStorage.mm */,
- DA8847E71CBAFA5100AB86E3 /* MGLOverlay.h */,
- DA8847E81CBAFA5100AB86E3 /* MGLPointAnnotation.h */,
- DA88480B1CBAFA6200AB86E3 /* MGLPointAnnotation.m */,
- DA8847E91CBAFA5100AB86E3 /* MGLPolygon.h */,
- DA88480C1CBAFA6200AB86E3 /* MGLPolygon.mm */,
- DA8847EA1CBAFA5100AB86E3 /* MGLPolyline.h */,
- DA88480D1CBAFA6200AB86E3 /* MGLPolyline.mm */,
- DA8847EB1CBAFA5100AB86E3 /* MGLShape.h */,
- DA88480E1CBAFA6200AB86E3 /* MGLShape.m */,
DA8847EC1CBAFA5100AB86E3 /* MGLStyle.h */,
DA88480F1CBAFA6200AB86E3 /* MGLStyle.mm */,
- DA8847ED1CBAFA5100AB86E3 /* MGLTilePyramidOfflineRegion.h */,
- DA8848101CBAFA6200AB86E3 /* MGLTilePyramidOfflineRegion.mm */,
DA8847EE1CBAFA5100AB86E3 /* MGLTypes.h */,
DA8848111CBAFA6200AB86E3 /* MGLTypes.m */,
- DA8848121CBAFA6200AB86E3 /* NSBundle+MGLAdditions.h */,
- DA8848131CBAFA6200AB86E3 /* NSBundle+MGLAdditions.m */,
- DA8848141CBAFA6200AB86E3 /* NSException+MGLAdditions.h */,
- DA8848151CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.h */,
- DA8848161CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.m */,
- DA8848171CBAFA6200AB86E3 /* NSString+MGLAdditions.h */,
- DA8848181CBAFA6200AB86E3 /* NSString+MGLAdditions.m */,
- DA35A2C71CCAAAD200E826B2 /* NSValue+MGLAdditions.h */,
- DA35A2C81CCAAAD200E826B2 /* NSValue+MGLAdditions.m */,
DA8848911CBB049300AB86E3 /* reachability */,
);
name = Foundation;
@@ -713,31 +701,14 @@
DA8848331CBAFB2A00AB86E3 /* Kit */ = {
isa = PBXGroup;
children = (
- 4018B1C31CDC277F00F666AF /* MGLAnnotationView_Private.h */,
- 4018B1C41CDC277F00F666AF /* MGLAnnotationView.m */,
- 4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */,
- DA8848341CBAFB8500AB86E3 /* MGLAnnotationImage.h */,
- DA8848401CBAFB9800AB86E3 /* MGLAnnotationImage_Private.h */,
- DA8848411CBAFB9800AB86E3 /* MGLAnnotationImage.m */,
- DA8848421CBAFB9800AB86E3 /* MGLAPIClient.h */,
- DA8848431CBAFB9800AB86E3 /* MGLAPIClient.m */,
- DA8848351CBAFB8500AB86E3 /* MGLCalloutView.h */,
- DA8848441CBAFB9800AB86E3 /* MGLCompactCalloutView.h */,
- DA8848451CBAFB9800AB86E3 /* MGLCompactCalloutView.m */,
- DA8848461CBAFB9800AB86E3 /* MGLLocationManager.h */,
- DA8848471CBAFB9800AB86E3 /* MGLLocationManager.m */,
- DA8848481CBAFB9800AB86E3 /* MGLMapboxEvents.h */,
- DA8848491CBAFB9800AB86E3 /* MGLMapboxEvents.m */,
+ DAD165841CF4D06B001FF4B9 /* Annotations */,
+ DAD165851CF4D08B001FF4B9 /* Telemetry */,
DA8848361CBAFB8500AB86E3 /* MGLMapView.h */,
DA17BE2F1CC4BAC300402C41 /* MGLMapView_Internal.h */,
DA8848371CBAFB8500AB86E3 /* MGLMapView+IBAdditions.h */,
DA8848381CBAFB8500AB86E3 /* MGLMapView+MGLCustomStyleLayerAdditions.h */,
+ DA737EE01D056A4E005BDA16 /* MGLMapViewDelegate.h */,
DA88484A1CBAFB9800AB86E3 /* MGLMapView.mm */,
- DA8848391CBAFB8500AB86E3 /* MGLUserLocation.h */,
- DA88484B1CBAFB9800AB86E3 /* MGLUserLocation_Private.h */,
- DA88484C1CBAFB9800AB86E3 /* MGLUserLocation.m */,
- DA88484D1CBAFB9800AB86E3 /* MGLUserLocationAnnotationView.h */,
- DA88484E1CBAFB9800AB86E3 /* MGLUserLocationAnnotationView.m */,
DA88487F1CBB033F00AB86E3 /* Fabric */,
DA8848881CBB036000AB86E3 /* SMCalloutView */,
);
@@ -858,6 +829,116 @@
name = Configuration;
sourceTree = "<group>";
};
+ DAD165801CF4CF9A001FF4B9 /* Formatters */ = {
+ isa = PBXGroup;
+ children = (
+ DA35A2BA1CCA9A6900E826B2 /* MGLClockDirectionFormatter.h */,
+ DA35A2B71CCA9A5D00E826B2 /* MGLClockDirectionFormatter.m */,
+ DA35A2AF1CCA141D00E826B2 /* MGLCompassDirectionFormatter.h */,
+ DA35A2B01CCA141D00E826B2 /* MGLCompassDirectionFormatter.m */,
+ DA35A29D1CC9E94C00E826B2 /* MGLCoordinateFormatter.h */,
+ DA35A2A01CC9E95F00E826B2 /* MGLCoordinateFormatter.m */,
+ );
+ name = Formatters;
+ sourceTree = "<group>";
+ };
+ DAD165811CF4CFC4001FF4B9 /* Geometry */ = {
+ isa = PBXGroup;
+ children = (
+ DA8847E01CBAFA5100AB86E3 /* MGLAnnotation.h */,
+ DAD165691CF41981001FF4B9 /* MGLFeature.h */,
+ DAD1656A1CF41981001FF4B9 /* MGLFeature_Private.h */,
+ DAD1656B1CF41981001FF4B9 /* MGLFeature.mm */,
+ DA8847E11CBAFA5100AB86E3 /* MGLGeometry.h */,
+ DA8848011CBAFA6200AB86E3 /* MGLGeometry_Private.h */,
+ DA8848021CBAFA6200AB86E3 /* MGLGeometry.mm */,
+ DA8847E31CBAFA5100AB86E3 /* MGLMultiPoint.h */,
+ DA8848041CBAFA6200AB86E3 /* MGLMultiPoint_Private.h */,
+ DA8848051CBAFA6200AB86E3 /* MGLMultiPoint.mm */,
+ DA8847E71CBAFA5100AB86E3 /* MGLOverlay.h */,
+ DA8847E81CBAFA5100AB86E3 /* MGLPointAnnotation.h */,
+ DA88480B1CBAFA6200AB86E3 /* MGLPointAnnotation.m */,
+ DA8847E91CBAFA5100AB86E3 /* MGLPolygon.h */,
+ DA88480C1CBAFA6200AB86E3 /* MGLPolygon.mm */,
+ DA8847EA1CBAFA5100AB86E3 /* MGLPolyline.h */,
+ DA88480D1CBAFA6200AB86E3 /* MGLPolyline.mm */,
+ DA8847EB1CBAFA5100AB86E3 /* MGLShape.h */,
+ DA88480E1CBAFA6200AB86E3 /* MGLShape.m */,
+ DAD165761CF4CDFF001FF4B9 /* MGLShapeCollection.h */,
+ DAD165771CF4CDFF001FF4B9 /* MGLShapeCollection.m */,
+ );
+ name = Geometry;
+ sourceTree = "<group>";
+ };
+ DAD165821CF4CFE3001FF4B9 /* Offline Maps */ = {
+ isa = PBXGroup;
+ children = (
+ DA8847E41CBAFA5100AB86E3 /* MGLOfflinePack.h */,
+ DA8848061CBAFA6200AB86E3 /* MGLOfflinePack_Private.h */,
+ DA8848071CBAFA6200AB86E3 /* MGLOfflinePack.mm */,
+ DA8847E51CBAFA5100AB86E3 /* MGLOfflineRegion.h */,
+ DA8848081CBAFA6200AB86E3 /* MGLOfflineRegion_Private.h */,
+ DA8847E61CBAFA5100AB86E3 /* MGLOfflineStorage.h */,
+ DA8848091CBAFA6200AB86E3 /* MGLOfflineStorage_Private.h */,
+ DA88480A1CBAFA6200AB86E3 /* MGLOfflineStorage.mm */,
+ DA8847ED1CBAFA5100AB86E3 /* MGLTilePyramidOfflineRegion.h */,
+ DA8848101CBAFA6200AB86E3 /* MGLTilePyramidOfflineRegion.mm */,
+ );
+ name = "Offline Maps";
+ sourceTree = "<group>";
+ };
+ DAD165831CF4CFED001FF4B9 /* Categories */ = {
+ isa = PBXGroup;
+ children = (
+ DA8848121CBAFA6200AB86E3 /* NSBundle+MGLAdditions.h */,
+ DA8848131CBAFA6200AB86E3 /* NSBundle+MGLAdditions.m */,
+ DA8848141CBAFA6200AB86E3 /* NSException+MGLAdditions.h */,
+ DA8848151CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.h */,
+ DA8848161CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.m */,
+ DA8848171CBAFA6200AB86E3 /* NSString+MGLAdditions.h */,
+ DA8848181CBAFA6200AB86E3 /* NSString+MGLAdditions.m */,
+ DA35A2C71CCAAAD200E826B2 /* NSValue+MGLAdditions.h */,
+ DA35A2C81CCAAAD200E826B2 /* NSValue+MGLAdditions.m */,
+ );
+ name = Categories;
+ sourceTree = "<group>";
+ };
+ DAD165841CF4D06B001FF4B9 /* Annotations */ = {
+ isa = PBXGroup;
+ children = (
+ 40EDA1BD1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.h */,
+ 40EDA1BE1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.m */,
+ 4018B1C31CDC277F00F666AF /* MGLAnnotationView_Private.h */,
+ 4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */,
+ 4018B1C41CDC277F00F666AF /* MGLAnnotationView.mm */,
+ DA8848341CBAFB8500AB86E3 /* MGLAnnotationImage.h */,
+ DA8848401CBAFB9800AB86E3 /* MGLAnnotationImage_Private.h */,
+ DA8848411CBAFB9800AB86E3 /* MGLAnnotationImage.m */,
+ DA8848351CBAFB8500AB86E3 /* MGLCalloutView.h */,
+ DA8848441CBAFB9800AB86E3 /* MGLCompactCalloutView.h */,
+ DA8848451CBAFB9800AB86E3 /* MGLCompactCalloutView.m */,
+ DA8848391CBAFB8500AB86E3 /* MGLUserLocation.h */,
+ DA88484B1CBAFB9800AB86E3 /* MGLUserLocation_Private.h */,
+ DA88484C1CBAFB9800AB86E3 /* MGLUserLocation.m */,
+ DA88484D1CBAFB9800AB86E3 /* MGLUserLocationAnnotationView.h */,
+ DA88484E1CBAFB9800AB86E3 /* MGLUserLocationAnnotationView.m */,
+ );
+ name = Annotations;
+ sourceTree = "<group>";
+ };
+ DAD165851CF4D08B001FF4B9 /* Telemetry */ = {
+ isa = PBXGroup;
+ children = (
+ DA8848421CBAFB9800AB86E3 /* MGLAPIClient.h */,
+ DA8848431CBAFB9800AB86E3 /* MGLAPIClient.m */,
+ DA8848461CBAFB9800AB86E3 /* MGLLocationManager.h */,
+ DA8848471CBAFB9800AB86E3 /* MGLLocationManager.m */,
+ DA8848481CBAFB9800AB86E3 /* MGLMapboxEvents.h */,
+ DA8848491CBAFB9800AB86E3 /* MGLMapboxEvents.m */,
+ );
+ name = Telemetry;
+ sourceTree = "<group>";
+ };
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@@ -894,6 +975,7 @@
DA88483F1CBAFB8500AB86E3 /* MGLUserLocation.h in Headers */,
DA88483D1CBAFB8500AB86E3 /* MGLMapView+IBAdditions.h in Headers */,
DA17BE301CC4BAC300402C41 /* MGLMapView_Internal.h in Headers */,
+ DAD165781CF4CDFF001FF4B9 /* MGLShapeCollection.h in Headers */,
DA88481E1CBAFA6200AB86E3 /* MGLMultiPoint_Private.h in Headers */,
DA35A29E1CC9E94C00E826B2 /* MGLCoordinateFormatter.h in Headers */,
DA8847F71CBAFA5100AB86E3 /* MGLOverlay.h in Headers */,
@@ -905,9 +987,12 @@
DA8847F91CBAFA5100AB86E3 /* MGLPolygon.h in Headers */,
DA8847F81CBAFA5100AB86E3 /* MGLPointAnnotation.h in Headers */,
DA8847F31CBAFA5100AB86E3 /* MGLMultiPoint.h in Headers */,
+ DAD1656C1CF41981001FF4B9 /* MGLFeature.h in Headers */,
+ 40EDA1C01CFE0E0200D9EA68 /* MGLAnnotationContainerView.h in Headers */,
DA88484F1CBAFB9800AB86E3 /* MGLAnnotationImage_Private.h in Headers */,
DA8847F21CBAFA5100AB86E3 /* MGLMapCamera.h in Headers */,
DA8847F51CBAFA5100AB86E3 /* MGLOfflineRegion.h in Headers */,
+ DA737EE11D056A4E005BDA16 /* MGLMapViewDelegate.h in Headers */,
DA8848851CBB033F00AB86E3 /* FABKitProtocol.h in Headers */,
DA88481B1CBAFA6200AB86E3 /* MGLGeometry_Private.h in Headers */,
DA88485C1CBAFB9800AB86E3 /* MGLUserLocationAnnotationView.h in Headers */,
@@ -917,6 +1002,7 @@
DA88482F1CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.h in Headers */,
DA8848601CBAFC2E00AB86E3 /* Mapbox.h in Headers */,
DA8847F61CBAFA5100AB86E3 /* MGLOfflineStorage.h in Headers */,
+ DAD1656E1CF41981001FF4B9 /* MGLFeature_Private.h in Headers */,
DA88483C1CBAFB8500AB86E3 /* MGLMapView.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -928,6 +1014,7 @@
DA35A2CA1CCAAAD200E826B2 /* NSValue+MGLAdditions.h in Headers */,
DABFB85E1CBE99E500D62B32 /* MGLAnnotation.h in Headers */,
DABFB8641CBE99E500D62B32 /* MGLOfflineStorage.h in Headers */,
+ DAD165791CF4CDFF001FF4B9 /* MGLShapeCollection.h in Headers */,
DA35A29F1CC9E94C00E826B2 /* MGLCoordinateFormatter.h in Headers */,
DABFB8711CBE9A0F00D62B32 /* MGLMapView+MGLCustomStyleLayerAdditions.h in Headers */,
DABFB8611CBE99E500D62B32 /* MGLMultiPoint.h in Headers */,
@@ -935,6 +1022,7 @@
DABFB8721CBE9A0F00D62B32 /* MGLUserLocation.h in Headers */,
DABFB8661CBE99E500D62B32 /* MGLPointAnnotation.h in Headers */,
DABFB8621CBE99E500D62B32 /* MGLOfflinePack.h in Headers */,
+ DAD1656D1CF41981001FF4B9 /* MGLFeature.h in Headers */,
DA17BE311CC4BDAA00402C41 /* MGLMapView_Internal.h in Headers */,
DABFB86C1CBE99E500D62B32 /* MGLTypes.h in Headers */,
DABFB8691CBE99E500D62B32 /* MGLShape.h in Headers */,
@@ -953,6 +1041,7 @@
DA35A2BC1CCA9A6900E826B2 /* MGLClockDirectionFormatter.h in Headers */,
DABFB86E1CBE9A0F00D62B32 /* MGLCalloutView.h in Headers */,
DABFB8601CBE99E500D62B32 /* MGLMapCamera.h in Headers */,
+ DA737EE21D056A4E005BDA16 /* MGLMapViewDelegate.h in Headers */,
DABFB86A1CBE99E500D62B32 /* MGLStyle.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -1262,6 +1351,7 @@
DA35A2C51CCA9F8300E826B2 /* MGLClockDirectionFormatterTests.m in Sources */,
DA2E88621CC0382C00F24E7B /* MGLOfflinePackTests.m in Sources */,
DA35A2AA1CCA058D00E826B2 /* MGLCoordinateFormatterTests.m in Sources */,
+ DA0CD5901CF56F6A00A5F5A5 /* MGLFeatureTests.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1270,12 +1360,15 @@
buildActionMask = 2147483647;
files = (
DA88485D1CBAFB9800AB86E3 /* MGLUserLocationAnnotationView.m in Sources */,
+ DAD165701CF41981001FF4B9 /* MGLFeature.mm in Sources */,
+ 40EDA1C11CFE0E0500D9EA68 /* MGLAnnotationContainerView.m in Sources */,
DA8848541CBAFB9800AB86E3 /* MGLCompactCalloutView.m in Sources */,
DA8848251CBAFA6200AB86E3 /* MGLPointAnnotation.m in Sources */,
DA88482D1CBAFA6200AB86E3 /* NSBundle+MGLAdditions.m in Sources */,
DA88485B1CBAFB9800AB86E3 /* MGLUserLocation.m in Sources */,
DA88488C1CBB037E00AB86E3 /* SMCalloutView.m in Sources */,
DA35A2B81CCA9A5D00E826B2 /* MGLClockDirectionFormatter.m in Sources */,
+ DAD1657A1CF4CDFF001FF4B9 /* MGLShapeCollection.m in Sources */,
DA8848901CBB048E00AB86E3 /* reachability.m in Sources */,
DA8848211CBAFA6200AB86E3 /* MGLOfflinePack.mm in Sources */,
DA8848591CBAFB9800AB86E3 /* MGLMapView.mm in Sources */,
@@ -1289,7 +1382,7 @@
DA88481C1CBAFA6200AB86E3 /* MGLGeometry.mm in Sources */,
DA88481F1CBAFA6200AB86E3 /* MGLMultiPoint.mm in Sources */,
DA88482B1CBAFA6200AB86E3 /* MGLTypes.m in Sources */,
- 4018B1C71CDC287F00F666AF /* MGLAnnotationView.m in Sources */,
+ 4018B1C71CDC287F00F666AF /* MGLAnnotationView.mm in Sources */,
DA88481D1CBAFA6200AB86E3 /* MGLMapCamera.mm in Sources */,
DA8848261CBAFA6200AB86E3 /* MGLPolygon.mm in Sources */,
DA8848521CBAFB9800AB86E3 /* MGLAPIClient.m in Sources */,
@@ -1308,12 +1401,15 @@
buildActionMask = 2147483647;
files = (
DAA4E4221CBB730400178DFB /* MGLPointAnnotation.m in Sources */,
+ DAD165711CF41981001FF4B9 /* MGLFeature.mm in Sources */,
+ 40EDA1C21CFE0E0500D9EA68 /* MGLAnnotationContainerView.m in Sources */,
DAA4E4291CBB730400178DFB /* NSBundle+MGLAdditions.m in Sources */,
DAA4E42E1CBB730400178DFB /* MGLAPIClient.m in Sources */,
DAA4E4201CBB730400178DFB /* MGLOfflinePack.mm in Sources */,
DAA4E4331CBB730400178DFB /* MGLUserLocation.m in Sources */,
DAA4E4351CBB730400178DFB /* SMCalloutView.m in Sources */,
DA35A2B91CCA9A5D00E826B2 /* MGLClockDirectionFormatter.m in Sources */,
+ DAD1657B1CF4CDFF001FF4B9 /* MGLShapeCollection.m in Sources */,
DAA4E4251CBB730400178DFB /* MGLShape.m in Sources */,
DAA4E42B1CBB730400178DFB /* NSString+MGLAdditions.m in Sources */,
DAA4E4261CBB730400178DFB /* MGLStyle.mm in Sources */,
@@ -1327,7 +1423,7 @@
DAA4E4301CBB730400178DFB /* MGLLocationManager.m in Sources */,
DAA4E4321CBB730400178DFB /* MGLMapView.mm in Sources */,
DAA4E41E1CBB730400178DFB /* MGLMapCamera.mm in Sources */,
- 4018B1C81CDC287F00F666AF /* MGLAnnotationView.m in Sources */,
+ 4018B1C81CDC287F00F666AF /* MGLAnnotationView.mm in Sources */,
DAA4E4341CBB730400178DFB /* MGLUserLocationAnnotationView.m in Sources */,
DAA4E42C1CBB730400178DFB /* reachability.m in Sources */,
DAA4E4311CBB730400178DFB /* MGLMapboxEvents.m in Sources */,
@@ -1583,6 +1679,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
+ "$(variant_cflags)",
"$(geometry_cflags)",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test;
@@ -1600,6 +1697,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
+ "$(variant_cflags)",
"$(geometry_cflags)",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test;
diff --git a/platform/ios/jazzy.yml b/platform/ios/jazzy.yml
index f6a5cfba4b..67d877cda3 100644
--- a/platform/ios/jazzy.yml
+++ b/platform/ios/jazzy.yml
@@ -30,15 +30,29 @@ custom_categories:
- MGLAnnotation
- MGLAnnotationImage
- MGLAnnotationVerticalAlignment
+ - MGLAnnotationView
- MGLCalloutView
- MGLCalloutViewDelegate
- MGLMultiPoint
+ - MGLMultiPolygon
+ - MGLMultiPolyline
- MGLPointAnnotation
- MGLPolygon
- MGLPolyline
- MGLOverlay
- MGLShape
+ - MGLShapeCollection
- MGLUserLocation
+ - name: Map Data
+ children:
+ - MGLFeature
+ - MGLMultiPointFeature
+ - MGLMultiPolygonFeature
+ - MGLMultiPolylineFeature
+ - MGLPointFeature
+ - MGLPolygonFeature
+ - MGLPolylineFeature
+ - MGLShapeCollectionFeature
- name: Offline Maps
children:
- MGLOfflineRegion
diff --git a/platform/ios/scripts/configure.sh b/platform/ios/scripts/configure.sh
index 3a63f649a1..408180881c 100644
--- a/platform/ios/scripts/configure.sh
+++ b/platform/ios/scripts/configure.sh
@@ -1,5 +1,6 @@
#!/usr/bin/env bash
+UNIQUE_RESOURCE_VERSION=dev
PROTOZERO_VERSION=1.3.0
BOOST_VERSION=1.60.0
SQLITE_VERSION=system
@@ -10,3 +11,4 @@ VARIANT_VERSION=1.1.0
RAPIDJSON_VERSION=1.0.2
GTEST_VERSION=1.7.0
PIXELMATCH_VERSION=0.9.0
+EARCUT_VERSION=0.11
diff --git a/platform/ios/scripts/deploy-packages.sh b/platform/ios/scripts/deploy-packages.sh
index 64cb472f6b..42bce89cf3 100755
--- a/platform/ios/scripts/deploy-packages.sh
+++ b/platform/ios/scripts/deploy-packages.sh
@@ -56,6 +56,7 @@ export TRAVIS_REPO_SLUG=mapbox-gl-native
export PUBLISH_VERSION=$1
export GITHUB_USER=mapbox
export GITHUB_REPO=mapbox-gl-native
+export BUILDTYPE=Release
BINARY_DIRECTORY=$2
PUBLISH_PRE_FLAG=''
diff --git a/platform/ios/scripts/package.sh b/platform/ios/scripts/package.sh
index 8f41003b79..f0ca683389 100755
--- a/platform/ios/scripts/package.sh
+++ b/platform/ios/scripts/package.sh
@@ -9,7 +9,7 @@ OUTPUT=build/ios/pkg
DERIVED_DATA=build/ios
PRODUCTS=${DERIVED_DATA}/Build/Products
-BUILDTYPE=${BUILDTYPE:-Release}
+BUILDTYPE=${BUILDTYPE:-Debug}
BUILD_FOR_DEVICE=${BUILD_DEVICE:-true}
GCC_GENERATE_DEBUGGING_SYMBOLS=${SYMBOLS:-YES}
@@ -84,6 +84,7 @@ xcodebuild \
CURRENT_SHORT_VERSION=${SHORT_VERSION} \
CURRENT_SEMANTIC_VERSION=${SEM_VERSION} \
CURRENT_COMMIT_HASH=${HASH} \
+ ONLY_ACTIVE_ARCH=NO \
-derivedDataPath ${DERIVED_DATA} \
-workspace ./platform/ios/ios.xcworkspace \
-scheme ${SCHEME} \
@@ -98,6 +99,7 @@ if [[ ${BUILD_FOR_DEVICE} == true ]]; then
CURRENT_SHORT_VERSION=${SHORT_VERSION} \
CURRENT_SEMANTIC_VERSION=${SEM_VERSION} \
CURRENT_COMMIT_HASH=${HASH} \
+ ONLY_ACTIVE_ARCH=NO \
-derivedDataPath ${DERIVED_DATA} \
-workspace ./platform/ios/ios.xcworkspace \
-scheme ${SCHEME} \
@@ -106,7 +108,7 @@ if [[ ${BUILD_FOR_DEVICE} == true ]]; then
-jobs ${JOBS} | xcpretty
fi
-LIBS=(core.a platform-ios.a)
+LIBS=(Mapbox.a mbgl-core.a mbgl-platform-ios.a)
# https://medium.com/@syshen/create-an-ios-universal-framework-148eb130a46c
if [[ "${BUILD_FOR_DEVICE}" == true ]]; then
@@ -114,10 +116,10 @@ if [[ "${BUILD_FOR_DEVICE}" == true ]]; then
step "Assembling static framework for iOS Simulator and devices…"
mkdir -p ${OUTPUT}/static/${NAME}.framework
libtool -static -no_warning_for_no_symbols \
- `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libgeojsonvt.a` \
-o ${OUTPUT}/static/${NAME}.framework/${NAME} \
- ${LIBS[@]/#/${PRODUCTS}/${BUILDTYPE}-iphoneos/libmbgl-} \
- ${LIBS[@]/#/${PRODUCTS}/${BUILDTYPE}-iphonesimulator/libmbgl-}
+ ${LIBS[@]/#/${PRODUCTS}/${BUILDTYPE}-iphoneos/lib} \
+ ${LIBS[@]/#/${PRODUCTS}/${BUILDTYPE}-iphonesimulator/lib} \
+ `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libgeojsonvt.a`
cp -rv ${PRODUCTS}/${BUILDTYPE}-iphoneos/${NAME}.bundle ${STATIC_BUNDLE_DIR}
fi
@@ -145,9 +147,9 @@ else
step "Assembling static library for iOS Simulator…"
mkdir -p ${OUTPUT}/static/${NAME}.framework
libtool -static -no_warning_for_no_symbols \
- `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libgeojsonvt.a` \
-o ${OUTPUT}/static/${NAME}.framework/${NAME} \
- ${LIBS[@]/#/${PRODUCTS}/${BUILDTYPE}-iphonesimulator/libmbgl-}
+ ${LIBS[@]/#/${PRODUCTS}/${BUILDTYPE}-iphonesimulator/lib} \
+ `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libgeojsonvt.a`
cp -rv ${PRODUCTS}/${BUILDTYPE}-iphonesimulator/${NAME}.bundle ${STATIC_BUNDLE_DIR}
fi
diff --git a/platform/ios/src/MGLAPIClient.m b/platform/ios/src/MGLAPIClient.m
index 2a224c5584..31fd39c83d 100644
--- a/platform/ios/src/MGLAPIClient.m
+++ b/platform/ios/src/MGLAPIClient.m
@@ -3,7 +3,7 @@
#import "MGLAccountManager.h"
static NSString * const MGLAPIClientUserAgentBase = @"MapboxEventsiOS";
-static NSString * const MGLAPIClientBaseURL = @"https://api.mapbox.com";
+static NSString * const MGLAPIClientBaseURL = @"https://events.mapbox.com";
static NSString * const MGLAPIClientEventsPath = @"events/v2";
static NSString * const MGLAPIClientHeaderFieldUserAgentKey = @"User-Agent";
diff --git a/platform/ios/src/MGLAnnotationContainerView.h b/platform/ios/src/MGLAnnotationContainerView.h
new file mode 100644
index 0000000000..90d2964831
--- /dev/null
+++ b/platform/ios/src/MGLAnnotationContainerView.h
@@ -0,0 +1,17 @@
+#import <UIKit/UIKit.h>
+
+#import "MGLTypes.h"
+
+@class MGLAnnotationView;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MGLAnnotationContainerView : UIView
+
++ (instancetype)annotationContainerViewWithAnnotationContainerView:(MGLAnnotationContainerView *)annotationContainerView;
+
+- (void)addSubviews:(NS_ARRAY_OF(MGLAnnotationView *) *)subviews;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/ios/src/MGLAnnotationContainerView.m b/platform/ios/src/MGLAnnotationContainerView.m
new file mode 100644
index 0000000000..9a823c839c
--- /dev/null
+++ b/platform/ios/src/MGLAnnotationContainerView.m
@@ -0,0 +1,52 @@
+#import "MGLAnnotationContainerView.h"
+#import "MGLAnnotationView.h"
+
+@interface MGLAnnotationContainerView ()
+
+@property (nonatomic) NS_MUTABLE_ARRAY_OF(MGLAnnotationView *) *annotationViews;
+
+@end
+
+@implementation MGLAnnotationContainerView
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ self = [super initWithFrame:frame];
+ if (self)
+ {
+ _annotationViews = [NSMutableArray array];
+ }
+ return self;
+}
+
++ (instancetype)annotationContainerViewWithAnnotationContainerView:(nonnull MGLAnnotationContainerView *)annotationContainerView
+{
+ MGLAnnotationContainerView *newAnnotationContainerView = [[MGLAnnotationContainerView alloc] initWithFrame:annotationContainerView.frame];
+ [newAnnotationContainerView addSubviews:annotationContainerView.subviews];
+ return newAnnotationContainerView;
+}
+
+- (void)addSubviews:(NS_ARRAY_OF(MGLAnnotationView *) *)subviews
+{
+ for (MGLAnnotationView *view in subviews)
+ {
+ [self addSubview:view];
+ [self.annotationViews addObject:view];
+ }
+}
+
+#pragma mark UIAccessibility methods
+
+- (UIAccessibilityTraits)accessibilityTraits {
+ return UIAccessibilityTraitAdjustable;
+}
+
+- (void)accessibilityIncrement {
+ [self.superview.superview accessibilityIncrement];
+}
+
+- (void)accessibilityDecrement {
+ [self.superview.superview accessibilityDecrement];
+}
+
+@end
diff --git a/platform/ios/src/MGLAnnotationView.h b/platform/ios/src/MGLAnnotationView.h
index 0762286b02..5b8091e7b4 100644
--- a/platform/ios/src/MGLAnnotationView.h
+++ b/platform/ios/src/MGLAnnotationView.h
@@ -11,9 +11,9 @@ NS_ASSUME_NONNULL_BEGIN
Initializes and returns a new annotation view object.
@param reuseIdentifier The string that identifies that this annotation view is reusable.
- @return The initialized annotation view object or `nil` if there was a problem initializing the object.
+ @return The initialized annotation view object.
*/
-- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier;
+- (instancetype)initWithReuseIdentifier:(nullable NSString *)reuseIdentifier;
/**
The string that identifies that this annotation view is reusable. (read-only)
@@ -40,6 +40,13 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, assign, getter=isFlat) BOOL flat;
+/**
+ Setting this property to YES will cause the annotation view to shrink as it approaches the horizon and grow as it moves away from the
+ horizon when the associated map view is tilted. Conversely, setting this property to NO will ensure that the annotation view maintains
+ a constant size even when the map view is tilted. To maintain consistency with annotation representations that are not backed by an
+ MGLAnnotationView object, the default value of this property is YES.
+ */
+@property (nonatomic, assign, getter=isScaledWithViewingDistance) BOOL scalesWithViewingDistance;
/**
Called when the view is removed from the reuse queue.
diff --git a/platform/ios/src/MGLAnnotationView.m b/platform/ios/src/MGLAnnotationView.m
deleted file mode 100644
index 5fcfe2651d..0000000000
--- a/platform/ios/src/MGLAnnotationView.m
+++ /dev/null
@@ -1,69 +0,0 @@
-#import "MGLAnnotationView.h"
-#import "MGLAnnotationView_Private.h"
-#import "MGLMapView.h"
-
-@interface MGLAnnotationView ()
-
-@property (nonatomic) id<MGLAnnotation> annotation;
-@property (nonatomic, readwrite, nullable) NSString *reuseIdentifier;
-@end
-
-@implementation MGLAnnotationView
-
-- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier
-{
- self = [super init];
-
- if (self)
- {
- _reuseIdentifier = [reuseIdentifier copy];
- }
-
- return self;
-}
-
-- (void)prepareForReuse
-{
- // Intentionally left blank. The default implementation of this method does nothing.
-}
-
-- (void)setCenterOffset:(CGVector)centerOffset
-{
- _centerOffset = centerOffset;
- self.center = self.center;
-}
-
-- (void)setCenter:(CGPoint)center
-{
- [self setCenter:center pitch:0];
-}
-
-- (void)setCenter:(CGPoint)center pitch:(CGFloat)pitch
-{
- center.x += _centerOffset.dx;
- center.y += _centerOffset.dy;
-
- [super setCenter:center];
-
- if (_flat) {
- [self updatePitch:pitch];
- }
-}
-
-- (void)updatePitch:(CGFloat)pitch
-{
- CATransform3D t = CATransform3DRotate(CATransform3DIdentity, MGLRadiansFromDegrees(pitch), 1.0, 0, 0);
- self.layer.transform = t;
-}
-
-- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
-{
- // Allow mbgl to drive animation of this view’s bounds.
- if ([event isEqualToString:@"bounds"])
- {
- return [NSNull null];
- }
- return [super actionForLayer:layer forKey:event];
-}
-
-@end \ No newline at end of file
diff --git a/platform/ios/src/MGLAnnotationView.mm b/platform/ios/src/MGLAnnotationView.mm
new file mode 100644
index 0000000000..31657dbf4e
--- /dev/null
+++ b/platform/ios/src/MGLAnnotationView.mm
@@ -0,0 +1,147 @@
+#import "MGLAnnotationView.h"
+#import "MGLAnnotationView_Private.h"
+#import "MGLMapView_Internal.h"
+
+#import "NSBundle+MGLAdditions.h"
+
+#include <mbgl/util/constants.hpp>
+
+@interface MGLAnnotationView ()
+
+@property (nonatomic) id<MGLAnnotation> annotation;
+@property (nonatomic, readwrite, nullable) NSString *reuseIdentifier;
+
+@end
+
+@implementation MGLAnnotationView
+
+- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier
+{
+ self = [self initWithFrame:CGRectZero];
+ if (self)
+ {
+ _reuseIdentifier = [reuseIdentifier copy];
+ _scalesWithViewingDistance = YES;
+ }
+ return self;
+}
+
+- (void)prepareForReuse
+{
+ // Intentionally left blank. The default implementation of this method does nothing.
+}
+
+- (void)setCenterOffset:(CGVector)centerOffset
+{
+ _centerOffset = centerOffset;
+ self.center = self.center;
+}
+
+- (void)setCenter:(CGPoint)center
+{
+ [self setCenter:center pitch:0];
+}
+
+- (void)setCenter:(CGPoint)center pitch:(CGFloat)pitch
+{
+ center.x += _centerOffset.dx;
+ center.y += _centerOffset.dy;
+
+ [super setCenter:center];
+
+ if (self.flat)
+ {
+ [self updatePitch:pitch];
+ }
+
+ if (self.scalesWithViewingDistance)
+ {
+ [self updateScaleForPitch:pitch];
+ }
+}
+
+- (void)updatePitch:(CGFloat)pitch
+{
+ CATransform3D t = CATransform3DRotate(CATransform3DIdentity, MGLRadiansFromDegrees(pitch), 1.0, 0, 0);
+ self.layer.transform = t;
+}
+
+- (void)updateScaleForPitch:(CGFloat)pitch
+{
+ CGFloat superviewHeight = CGRectGetHeight(self.superview.frame);
+ if (superviewHeight > 0.0) {
+ // Find the maximum amount of scale reduction to apply as the view's center moves from the top
+ // of the superview to the bottom. For example, if this view's center has moved 25% of the way
+ // from the top of the superview towards the bottom then the maximum scale reduction is 1 - .25
+ // or 75%. The range goes from a maximum of 100% to 0% as the view moves from the top to the bottom
+ // along the y axis of its superview.
+ CGFloat maxScaleReduction = 1.0 - self.center.y / superviewHeight;
+
+ // The pitch intensity represents how much the map view is actually pitched compared to
+ // what is possible. The value will range from 0% (not pitched at all) to 100% (pitched as much
+ // as the map view will allow). The map view's maximum pitch is defined in `mbgl::util::PITCH_MAX`.
+ // Since it is possible for the map view to report a pitch less than 0 due to the nature of
+ // how the gesture information is captured, the value is guarded with MAX.
+ CGFloat pitchIntensity = MAX(pitch, 0) / MGLDegreesFromRadians(mbgl::util::PITCH_MAX);
+
+ // The pitch adjusted scale is the inverse proportion of the maximum possible scale reduction
+ // multiplied by the pitch intensity. For example, if the maximum scale reduction is 75% and the
+ // map view is 50% pitched then the annotation view should be reduced by 37.5% (.75 * .5). The
+ // reduction is then normalized for a scale of 1.0.
+ CGFloat pitchAdjustedScale = 1.0 - maxScaleReduction * pitchIntensity;
+
+ CATransform3D transform = self.flat ? self.layer.transform : CATransform3DIdentity;
+ self.layer.transform = CATransform3DScale(transform, pitchAdjustedScale, pitchAdjustedScale, 1);
+ }
+}
+
+- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
+{
+ // Allow mbgl to drive animation of this view’s bounds.
+ if ([event isEqualToString:@"bounds"])
+ {
+ return [NSNull null];
+ }
+ return [super actionForLayer:layer forKey:event];
+}
+
+#pragma mark UIAccessibility methods
+
+- (BOOL)isAccessibilityElement {
+ return !self.hidden;
+}
+
+- (UIAccessibilityTraits)accessibilityTraits {
+ return UIAccessibilityTraitButton | UIAccessibilityTraitAdjustable;
+}
+
+- (NSString *)accessibilityLabel {
+ return [self.annotation respondsToSelector:@selector(title)] ? self.annotation.title : super.accessibilityLabel;
+}
+
+- (NSString *)accessibilityValue {
+ return [self.annotation respondsToSelector:@selector(subtitle)] ? self.annotation.subtitle : super.accessibilityValue;
+}
+
+- (NSString *)accessibilityHint {
+ return NSLocalizedStringWithDefaultValue(@"ANNOTATION_A11Y_HINT", nil, nil, @"Shows more info", @"Accessibility hint");
+}
+
+- (CGRect)accessibilityFrame {
+ CGRect accessibilityFrame = self.frame;
+ CGRect minimumFrame = CGRectInset({ self.center, CGSizeZero },
+ -MGLAnnotationAccessibilityElementMinimumSize.width / 2,
+ -MGLAnnotationAccessibilityElementMinimumSize.height / 2);
+ accessibilityFrame = CGRectUnion(accessibilityFrame, minimumFrame);
+ return accessibilityFrame;
+}
+
+- (void)accessibilityIncrement {
+ [self.superview accessibilityIncrement];
+}
+
+- (void)accessibilityDecrement {
+ [self.superview accessibilityDecrement];
+}
+
+@end \ No newline at end of file
diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h
index 3f54b07f41..d02c3a93a9 100644
--- a/platform/ios/src/MGLMapView.h
+++ b/platform/ios/src/MGLMapView.h
@@ -19,6 +19,7 @@ NS_ASSUME_NONNULL_BEGIN
@protocol MGLAnnotation;
@protocol MGLOverlay;
@protocol MGLCalloutView;
+@protocol MGLFeature;
/** The vertical alignment of an annotation within a map view. */
typedef NS_ENUM(NSUInteger, MGLAnnotationVerticalAlignment) {
@@ -880,6 +881,11 @@ IB_DESIGNABLE
/**
Adds an annotation to the map view.
+ @note `MGLMultiPolyline`, `MGLMultiPolygon`, and `MGLShapeCollection` objects
+ cannot be added to the map view at this time. Any multipolyline,
+ multipolygon, or shape collection object that is passed into this method is
+ silently ignored.
+
@param annotation The annotation object to add to the receiver. This object
must conform to the `MGLAnnotation` protocol. The map view retains the
annotation object. */
@@ -888,6 +894,11 @@ IB_DESIGNABLE
/**
Adds an array of annotations to the map view.
+ @note `MGLMultiPolyline`, `MGLMultiPolygon`, and `MGLShapeCollection` objects
+ cannot be added to the map view at this time. Any multipolyline,
+ multipolygon, or shape collection objects that are passed in are silently
+ ignored.
+
@param annotations An array of annotation objects. Each object in the array
must conform to the `MGLAnnotation` protocol. The map view retains each
individual annotation object.
@@ -1021,6 +1032,132 @@ IB_DESIGNABLE
*/
- (void)removeOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays;
+#pragma mark Accessing the Underlying Map Data
+
+/**
+ Returns an array of rendered map features that intersect with a given point.
+
+ This method may return features from any of the map’s style layers. To restrict
+ the search to a particular layer or layers, use the
+ `-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:` method. For more
+ information about searching for map features, see that method’s documentation.
+
+ @param point A point expressed in the map view’s coordinate system.
+ @return An array of objects conforming to the `MGLFeature` protocol that
+ represent features in the sources used by the current style.
+ */
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point NS_SWIFT_NAME(visibleFeatures(at:));
+
+/**
+ Returns an array of rendered map features that intersect with a given point,
+ restricted to the given style layers.
+
+ Each object in the returned array represents a feature rendered by the
+ current style and provides access to attributes specified by the relevant
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile sources</a>.
+ The returned array includes features specified in vector and GeoJSON tile
+ sources but does not include anything from raster, image, or video sources.
+
+ Only visible features are returned. For example, suppose the current style uses
+ the
+ <a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets source</a>,
+ but none of the specified style layers includes features that have the `maki`
+ property set to `bus`. If you pass a point corresponding to the location of a
+ bus stop into this method, the bus stop feature does not appear in the
+ resulting array. On the other hand, if the style does include bus stops, an
+ `MGLFeature` object representing that bus stop is returned and its
+ `featureAttributes` dictionary has the `maki` key set to `bus` (along with
+ other attributes). The dictionary contains only the attributes provided by the
+ tile source; it does not include computed attribute values or rules about how
+ the feature is rendered by the current style.
+
+ The returned array is sorted by z-order, starting with the topmost rendered
+ feature and ending with the bottommost rendered feature. A feature that is
+ rendered multiple times due to wrapping across the antimeridian at low zoom
+ levels is included only once, subject to the caveat that follows.
+
+ Features come from tiled vector data or GeoJSON data that is converted to tiles
+ internally, so feature geometries are clipped at tile boundaries and features
+ may appear duplicated across tiles. For example, suppose the specified point
+ lies along a road that spans the screen. The resulting array includes those
+ parts of the road that lie within the map tile that contain the specified
+ point, even if the road extends into other tiles.
+
+ To find out the layer names in a particular style, view the style in
+ <a href="https://www.mapbox.com/studio/">Mapbox Studio</a>.
+
+ @param point A point expressed in the map view’s coordinate system.
+ @param styleLayerIdentifiers A set of strings that correspond to the names of
+ layers defined in the current style. Only the features contained in these
+ layers are included in the returned array.
+ @return An array of objects conforming to the `MGLFeature` protocol that
+ represent features in the sources used by the current style.
+ */
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:));
+
+/**
+ Returns an array of rendered map features that intersect with the given
+ rectangle.
+
+ This method may return features from any of the map’s style layers. To restrict
+ the search to a particular layer or layers, use the
+ `-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:` method. For more
+ information about searching for map features, see that method’s documentation.
+
+ @param rect A rectangle expressed in the map view’s coordinate system.
+ @return An array of objects conforming to the `MGLFeature` protocol that
+ represent features in the sources used by the current style.
+ */
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect NS_SWIFT_NAME(visibleFeatures(in:));
+
+/**
+ Returns an array of rendered map features that intersect with the given
+ rectangle, restricted to the given style layers.
+
+ Each object in the returned array represents a feature rendered by the
+ current style and provides access to attributes specified by the relevant
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile sources</a>.
+ The returned array includes features specified in vector and GeoJSON tile
+ sources but does not include anything from raster, image, or video sources.
+
+ Only visible features are returned. For example, suppose the current style uses
+ the
+ <a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets source</a>,
+ but none of the specified style layers includes features that have the `maki`
+ property set to `bus`. If you pass a rectangle containing the location of a bus
+ stop into this method, the bus stop feature does not appear in the resulting
+ array. On the other hand, if the style does include bus stops, an `MGLFeature`
+ object representing that bus stop is returned and its `featureAttributes`
+ dictionary has the `maki` key set to `bus` (along with other attributes). The
+ dictionary contains only the attributes provided by the tile source; it does
+ not include computed attribute values or rules about how the feature is
+ rendered by the current style.
+
+ The returned array is sorted by z-order, starting with the topmost rendered
+ feature and ending with the bottommost rendered feature. A feature that is
+ rendered multiple times due to wrapping across the antimeridian at low zoom
+ levels is included only once, subject to the caveat that follows.
+
+ Features come from tiled vector data or GeoJSON data that is converted to tiles
+ internally, so feature geometries are clipped at tile boundaries and features
+ may appear duplicated across tiles. For example, suppose the specified
+ rectangle intersects with a road that spans the screen. The resulting array
+ includes those parts of the road that lie within the map tiles covering the
+ specified rectangle, even if the road extends into other tiles. The portion of
+ the road within each map tile is included individually.
+
+ To find out the layer names in a particular style, view the style in
+ <a href="https://www.mapbox.com/studio/">Mapbox Studio</a>.
+
+ @param rect A rectangle expressed in the map view’s coordinate system.
+ @param styleLayerIdentifiers A set of strings that correspond to the names of
+ layers defined in the current style. Only the features contained in these
+ layers are included in the returned array.
+ @return An array of objects conforming to the `MGLFeature` protocol that
+ represent features in the sources used by the current style.
+ */
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(in:styleLayerIdentifiers:));
+
#pragma mark Debugging the Map
/**
@@ -1045,281 +1182,4 @@ IB_DESIGNABLE
@end
-#pragma mark - MGLMapViewDelegate
-
-/** The MGLMapViewDelegate protocol defines a set of optional methods that you can use to receive map-related update messages. Because many map operations require the `MGLMapView` class to load data asynchronously, the map view calls these methods to notify your application when specific operations complete. The map view also uses these methods to request annotation marker symbology and to manage interactions with those markers. */
-@protocol MGLMapViewDelegate <NSObject>
-
-@optional
-
-#pragma mark Responding to Map Position Changes
-
-/**
- Tells the delegate that the region displayed by the map view is about to change.
-
- This method is called whenever the currently displayed map region will start changing.
-
- @param mapView The map view whose visible region will change.
- @param animated Whether the change will cause an animated effect on the map.
- */
-- (void)mapView:(MGLMapView *)mapView regionWillChangeAnimated:(BOOL)animated;
-
-/**
- Tells the delegate that the region displayed by the map view is changing.
-
- This method is called whenever the currently displayed map region changes. During movement, this method may be called many times to report updates to the map position. Therefore, your implementation of this method should be as lightweight as possible to avoid affecting performance.
-
- @param mapView The map view whose visible region is changing.
- */
-- (void)mapViewRegionIsChanging:(MGLMapView *)mapView;
-
-/**
- Tells the delegate that the region displayed by the map view just changed.
-
- This method is called whenever the currently displayed map region has finished changing.
-
- @param mapView The map view whose visible region changed.
- @param animated Whether the change caused an animated effect on the map.
- */
-- (void)mapView:(MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
-
-#pragma mark Loading the Map
-
-/**
- Tells the delegate that the map view will begin to load.
-
- This method is called whenever the map view starts loading, including when a new style has been set and the map must reload.
-
- @param mapView The map view that is starting to load.
- */
-- (void)mapViewWillStartLoadingMap:(MGLMapView *)mapView;
-
-/**
- Tells the delegate that the map view has finished loading.
-
- This method is called whenever the map view finishes loading, either after the initial load or after a style change has forced a reload.
-
- @param mapView The map view that has finished loading.
- */
-- (void)mapViewDidFinishLoadingMap:(MGLMapView *)mapView;
-
-// TODO
-- (void)mapViewDidFailLoadingMap:(MGLMapView *)mapView withError:(NSError *)error;
-
-// TODO
-- (void)mapViewWillStartRenderingMap:(MGLMapView *)mapView;
-
-// TODO
-- (void)mapViewDidFinishRenderingMap:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered;
-
-// TODO
-- (void)mapViewWillStartRenderingFrame:(MGLMapView *)mapView;
-
-// TODO
-- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered;
-
-#pragma mark Tracking User Location
-
-/**
- Tells the delegate that the map view will begin tracking the user's location.
-
- This method is called when the value of the `showsUserLocation` property changes to `YES`.
-
- @param mapView The map view that is tracking the user's location.
- */
-- (void)mapViewWillStartLocatingUser:(MGLMapView *)mapView;
-
-/**
- Tells the delegate that the map view has stopped tracking the user's location.
-
- This method is called when the value of the `showsUserLocation` property changes to `NO`.
-
- @param mapView The map view that is tracking the user's location.
- */
-- (void)mapViewDidStopLocatingUser:(MGLMapView *)mapView;
-
-/**
- Tells the delegate that the location of the user was updated.
-
- While the `showsUserLocation` property is set to `YES`, this method is called whenever a new location update is received by the map view. This method is also called if the map view's user tracking mode is set to `MGLUserTrackingModeFollowWithHeading` and the heading changes, or if it is set to `MGLUserTrackingModeFollowWithCourse` and the course changes.
-
- This method is not called if the application is currently running in the background. If you want to receive location updates while running in the background, you must use the Core Location framework.
-
- @param mapView The map view that is tracking the user's location.
- @param userLocation The location object representing the user's latest location. This property may be `nil`.
- */
-- (void)mapView:(MGLMapView *)mapView didUpdateUserLocation:(nullable MGLUserLocation *)userLocation;
-
-/**
- Tells the delegate that an attempt to locate the user's position failed.
-
- @param mapView The map view that is tracking the user's location.
- @param error An error object containing the reason why location tracking failed.
- */
-- (void)mapView:(MGLMapView *)mapView didFailToLocateUserWithError:(NSError *)error;
-
-/**
- Tells the delegate that the map view's user tracking mode has changed.
-
- This method is called after the map view asynchronously changes to reflect the new user tracking mode, for example by beginning to zoom or rotate.
-
- @param mapView The map view that changed its tracking mode.
- @param mode The new tracking mode.
- @param animated Whether the change caused an animated effect on the map.
- */
-- (void)mapView:(MGLMapView *)mapView didChangeUserTrackingMode:(MGLUserTrackingMode)mode animated:(BOOL)animated;
-
-#pragma mark Managing the Display of Annotations
-
-/**
- Returns a view object to use for the marker for the specified point annotation object.
-
- @param mapView The map view that requested the annotation view.
- @param annotation The object representing the annotation that is about to be displayed.
- @return The view object to display for the specified annotation or `nil` if you want to display the default marker image.
- */
-- (nullable MGLAnnotationView *)mapView:(MGLMapView *)mapView viewForAnnotation:(id <MGLAnnotation>)annotation;
-
-/**
- Returns an image object to use for the marker for the specified point annotation object.
-
- @param mapView The map view that requested the annotation image.
- @param annotation The object representing the annotation that is about to be displayed.
- @return The image object to display for the specified annotation or `nil` if you want to display the default marker image.
- */
-- (nullable MGLAnnotationImage *)mapView:(MGLMapView *)mapView imageForAnnotation:(id <MGLAnnotation>)annotation;
-
-/**
- Returns the alpha value to use when rendering a shape annotation. Defaults to `1.0`.
-
- @param mapView The map view rendering the shape annotation.
- @param annotation The annotation being rendered.
- @return An alpha value between `0` and `1.0`.
- */
-- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation;
-
-/**
- Returns the stroke color to use when rendering a shape annotation. Defaults to the map view’s tint color.
-
- @param mapView The map view rendering the shape annotation.
- @param annotation The annotation being rendered.
- @return A color to use for the shape outline.
- */
-- (UIColor *)mapView:(MGLMapView *)mapView strokeColorForShapeAnnotation:(MGLShape *)annotation;
-
-/**
- Returns the fill color to use when rendering a polygon annotation. Defaults to the map view’s tint color.
-
- @param mapView The map view rendering the polygon annotation.
- @param annotation The annotation being rendered.
- @return A color to use for the polygon interior.
- */
-- (UIColor *)mapView:(MGLMapView *)mapView fillColorForPolygonAnnotation:(MGLPolygon *)annotation;
-
-/**
- Returns the line width to use when rendering a polyline annotation. Defaults to `3.0`.
-
- @param mapView The map view rendering the polygon annotation.
- @param annotation The annotation being rendered.
- @return A line width for the polyline.
- */
-- (CGFloat)mapView:(MGLMapView *)mapView lineWidthForPolylineAnnotation:(MGLPolyline *)annotation;
-
-/**
- Returns a Boolean value indicating whether the annotation is able to display extra information in a callout bubble.
-
- If the value returned is `YES`, a standard callout bubble is shown when the user taps a selected annotation. The callout uses the title and subtitle text from the associated annotation object. If there is no title text, though, the annotation will not show a callout. The callout also displays any custom callout views returned by the delegate for the left and right callout accessory views.
-
- If the value returned is `NO`, the value of the title and subtitle strings are ignored.
-
- @param mapView The map view that requested the annotation callout ability.
- @param annotation The object representing the annotation.
- @return A Boolean indicating whether the annotation should show a callout.
- */
-- (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id <MGLAnnotation>)annotation;
-
-/**
- Returns a callout view to display for the specified annotation.
-
- If this method is present in the delegate, it must return a new instance of a view dedicated to display the callout bubble. It will be configured by the map view. If this method is not present, or if it returns `nil`, a standard, two-line, bubble-like callout view is displayed by default.
-
- @param mapView The map view that requested the callout view.
- @param annotation The object representing the annotation.
- @return A view conforming to the `MGLCalloutView` protocol, or `nil` to use the default callout view.
- */
-- (nullable UIView <MGLCalloutView> *)mapView:(MGLMapView *)mapView calloutViewForAnnotation:(id <MGLAnnotation>)annotation;
-
-/**
- Returns the view to display on the left side of the standard callout bubble.
-
- The default value is treated as if `nil`. The left callout view is typically used to display information about the annotation or to link to custom information provided by your application.
-
- If the view you specify is also a descendant of the `UIControl` class, you can use the map view's delegate to receive notifications when your control is tapped. If it does not descend from `UIControl`, your view is responsible for handling any touch events within its bounds.
-
- @param mapView The map view presenting the annotation callout.
- @param annotation The object representing the annotation with the callout.
- @return The accessory view to display.
- */
-- (nullable UIView *)mapView:(MGLMapView *)mapView leftCalloutAccessoryViewForAnnotation:(id <MGLAnnotation>)annotation;
-
-/**
- Returns the view to display on the right side of the standard callout bubble.
-
- The default value is treated is if `nil`. The right callout view is typically used to link to more detailed information about the annotation. A common view to specify for this property is `UIButton` object whose type is set to `UIButtonTypeDetailDisclosure`.
-
- If the view you specify is also a descendant of the `UIControl` class, you can use the map view's delegate to receive notifications when your control is tapped. If it does not descend from `UIControl`, your view is responsible for handling any touch events within its bounds.
-
- @param mapView The map view presenting the annotation callout.
- @param annotation The object representing the annotation with the callout.
- @return The accessory view to display.
- */
-- (nullable UIView *)mapView:(MGLMapView *)mapView rightCalloutAccessoryViewForAnnotation:(id <MGLAnnotation>)annotation;
-
-#pragma mark Managing Annotations
-
-/**
- Tells the delegate that the user tapped one of the annotation's accessory buttons.
-
- Accessory views contain custom content and are positioned on either side of the annotation title text. If a view you specify is a descendant of the `UIControl` class, the map view calls this method as a convenience whenever the user taps your view. You can use this method to respond to taps and perform any actions associated with that control. For example, if your control displayed additional information about the annotation, you could use this method to present a modal panel with that information.
-
- If your custom accessory views are not descendants of the `UIControl` class, the map view does not call this method.
-
- @param mapView The map view containing the specified annotation.
- @param annotation The annotation whose button was tapped.
- @param control The control that was tapped.
- */
-- (void)mapView:(MGLMapView *)mapView annotation:(id <MGLAnnotation>)annotation calloutAccessoryControlTapped:(UIControl *)control;
-
-/**
- Tells the delegate that the user tapped on an annotation's callout view.
-
- @param mapView The map view containing the specified annotation.
- @param annotation The annotation whose callout was tapped.
- */
-- (void)mapView:(MGLMapView *)mapView tapOnCalloutForAnnotation:(id <MGLAnnotation>)annotation;
-
-#pragma mark Selecting Annotations
-
-/**
- Tells the delegate that one of its annotations was selected.
-
- You can use this method to track changes in the selection state of annotations.
-
- @param mapView The map view containing the annotation.
- @param annotation The annotation that was selected.
- */
-- (void)mapView:(MGLMapView *)mapView didSelectAnnotation:(id <MGLAnnotation>)annotation;
-
-/**
- Tells the delegate that one of its annotations was deselected.
-
- You can use this method to track changes in the selection state of annotations.
-
- @param mapView The map view containing the annotation.
- @param annotation The annotation that was deselected.
- */
-- (void)mapView:(MGLMapView *)mapView didDeselectAnnotation:(id <MGLAnnotation>)annotation;
-
-@end
-
NS_ASSUME_NONNULL_END
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index 3811c3b7b8..1ad758dc77 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -7,8 +7,7 @@
#import <OpenGLES/EAGL.h>
#include <mbgl/mbgl.hpp>
-#include <mbgl/annotation/point_annotation.hpp>
-#include <mbgl/annotation/shape_annotation.hpp>
+#include <mbgl/annotation/annotation.hpp>
#include <mbgl/sprite/sprite_image.hpp>
#include <mbgl/map/camera.hpp>
#include <mbgl/map/mode.hpp>
@@ -16,7 +15,8 @@
#include <mbgl/platform/darwin/reachability.h>
#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/storage/network_status.hpp>
-#include <mbgl/style/property_transition.hpp>
+#include <mbgl/style/transition_options.hpp>
+#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/math/wrap.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/constants.hpp>
@@ -26,6 +26,7 @@
#include <mbgl/util/chrono.hpp>
#import "Mapbox.h"
+#import "MGLFeature_Private.h"
#import "MGLGeometry_Private.h"
#import "MGLMultiPoint_Private.h"
#import "MGLOfflineStorage_Private.h"
@@ -40,6 +41,7 @@
#import "MGLAnnotationView_Private.h"
#import "MGLMapboxEvents.h"
#import "MGLCompactCalloutView.h"
+#import "MGLAnnotationContainerView.h"
#import <algorithm>
#import <cstdlib>
@@ -96,6 +98,8 @@ const CGFloat MGLAnnotationImagePaddingForHitTest = 5;
/// Distance from the callout’s anchor point to the annotation it points to.
const CGFloat MGLAnnotationImagePaddingForCallout = 1;
+const CGSize MGLAnnotationAccessibilityElementMinimumSize = CGSizeMake(10, 10);
+
/// Unique identifier representing a single annotation in mbgl.
typedef uint32_t MGLAnnotationTag;
@@ -232,6 +236,7 @@ public:
@property (nonatomic, getter=isDormant) BOOL dormant;
@property (nonatomic, readonly, getter=isRotationAllowed) BOOL rotationAllowed;
@property (nonatomic) MGLMapViewProxyAccessibilityElement *mapViewProxyAccessibilityElement;
+@property (nonatomic) MGLAnnotationContainerView *annotationContainerView;
@end
@@ -547,7 +552,6 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
_glView.delegate = self;
[_glView bindDrawable];
[self insertSubview:_glView atIndex:0];
-
_glView.contentMode = UIViewContentModeCenter;
// load extensions
@@ -1022,6 +1026,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
_displayLink.frameInterval = MGLTargetFrameInterval;
[_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
_needsDisplayRefresh = YES;
+ [self updateFromDisplayLink];
}
else if ( ! isVisible && _displayLink)
{
@@ -1773,9 +1778,9 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
// but safely updated.
if (annotation == [self annotationWithTag:annotationTag])
{
- const mbgl::LatLng latLng = MGLLatLngFromLocationCoordinate2D(annotation.coordinate);
+ const mbgl::Point<double> point = MGLPointFromLocationCoordinate2D(annotation.coordinate);
MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
- _mbglMap->updatePointAnnotation(annotationTag, { latLng, annotationImage.styleIconIdentifier.UTF8String ?: "" });
+ _mbglMap->updateAnnotation(annotationTag, mbgl::SymbolAnnotation { point, annotationImage.styleIconIdentifier.UTF8String ?: "" });
if (annotationTag == _selectedAnnotationTag)
{
[self deselectAnnotation:annotation animated:YES];
@@ -2015,6 +2020,13 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
id <MGLAnnotation> annotation = annotationContext.annotation;
+ // Let the annotation view serve as its own accessibility element.
+ MGLAnnotationView *annotationView = annotationContext.annotationView;
+ if (annotationView && annotationView.superview)
+ {
+ return annotationView;
+ }
+
// Lazily create an accessibility element for the found annotation.
if ( ! annotationContext.accessibilityElement)
{
@@ -2024,6 +2036,11 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
// Update the accessibility element.
MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
CGRect annotationFrame = [self frameOfImage:annotationImage.image centeredAtCoordinate:annotation.coordinate];
+ CGPoint annotationFrameCenter = CGPointMake(CGRectGetMidX(annotationFrame), CGRectGetMidY(annotationFrame));
+ CGRect minimumFrame = CGRectInset({ annotationFrameCenter, CGSizeZero },
+ -MGLAnnotationAccessibilityElementMinimumSize.width / 2,
+ -MGLAnnotationAccessibilityElementMinimumSize.height / 2);
+ annotationFrame = CGRectUnion(annotationFrame, minimumFrame);
CGRect screenRect = UIAccessibilityConvertFrameToScreenCoordinates(annotationFrame, self);
annotationContext.accessibilityElement.accessibilityFrame = screenRect;
annotationContext.accessibilityElement.accessibilityHint = NSLocalizedStringWithDefaultValue(@"ANNOTATION_A11Y_HINT", nil, nil, @"Shows more info", @"Accessibility hint");
@@ -2055,17 +2072,28 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
{
return 1;
}
- if ( ! [element isKindOfClass:[MGLAnnotationAccessibilityElement class]] &&
- element != self.attributionButton)
- {
- return NSNotFound;
- }
std::vector<MGLAnnotationTag> visibleAnnotations = [self annotationTagsInRect:self.bounds];
- if (element == self.attributionButton)
+
+ MGLAnnotationTag tag = MGLAnnotationTagNotFound;
+ if ([element isKindOfClass:[MGLAnnotationView class]])
+ {
+ id <MGLAnnotation> annotation = [(MGLAnnotationView *)element annotation];
+ tag = [self annotationTagForAnnotation:annotation];
+ }
+ else if ([element isKindOfClass:[MGLAnnotationAccessibilityElement class]])
+ {
+ tag = [(MGLAnnotationAccessibilityElement *)element tag];
+ }
+ else if (element == self.attributionButton)
{
return !!self.userLocationAnnotationView + visibleAnnotations.size();
}
+ else
+ {
+ return NSNotFound;
+ }
+
std::sort(visibleAnnotations.begin(), visibleAnnotations.end());
auto foundElement = std::find(visibleAnnotations.begin(), visibleAnnotations.end(),
((MGLAnnotationAccessibilityElement *)element).tag);
@@ -2306,14 +2334,14 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
[self willChangeValueForKey:@"visibleCoordinateBounds"];
mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets);
padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
- mbgl::AnnotationSegment segment;
- segment.reserve(count);
+ std::vector<mbgl::LatLng> latLngs;
+ latLngs.reserve(count);
for (NSUInteger i = 0; i < count; i++)
{
- segment.push_back({coordinates[i].latitude, coordinates[i].longitude});
+ latLngs.push_back({coordinates[i].latitude, coordinates[i].longitude});
}
- mbgl::CameraOptions cameraOptions = _mbglMap->cameraForLatLngs(segment, padding);
+ mbgl::CameraOptions cameraOptions = _mbglMap->cameraForLatLngs(latLngs, padding);
if (direction >= 0)
{
cameraOptions.angle = MGLRadiansFromDegrees(-direction);
@@ -2697,7 +2725,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
newAppliedClasses.insert(newAppliedClasses.end(), [appliedClass UTF8String]);
}
- mbgl::PropertyTransition transition { { MGLDurationInSeconds(transitionDuration) } };
+ mbgl::style::TransitionOptions transition { { MGLDurationInSeconds(transitionDuration) } };
_mbglMap->setClasses(newAppliedClasses, transition);
}
@@ -2793,16 +2821,13 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
if ( ! annotations) return;
[self willChangeValueForKey:@"annotations"];
- NSMutableArray *userPoints = [NSMutableArray array];
- std::vector<mbgl::PointAnnotation> points;
- NSMutableArray *userShapes = [NSMutableArray array];
- std::vector<mbgl::ShapeAnnotation> shapes;
-
NSMutableDictionary *annotationImagesForAnnotation = [NSMutableDictionary dictionary];
NSMutableDictionary *annotationViewsForAnnotation = [NSMutableDictionary dictionary];
BOOL delegateImplementsViewForAnnotation = [self.delegate respondsToSelector:@selector(mapView:viewForAnnotation:)];
BOOL delegateImplementsImageForPoint = [self.delegate respondsToSelector:@selector(mapView:imageForAnnotation:)];
+
+ NSMutableArray *newAnnotationViews = [[NSMutableArray alloc] initWithCapacity:annotations.count];
for (id <MGLAnnotation> annotation in annotations)
{
@@ -2810,8 +2835,22 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
if ([annotation isKindOfClass:[MGLMultiPoint class]])
{
- [(MGLMultiPoint *)annotation addShapeAnnotationObjectToCollection:shapes withDelegate:self];
- [userShapes addObject:annotation];
+ // The multipoint knows how to style itself (with the map view’s help).
+ MGLMultiPoint *multiPoint = (MGLMultiPoint *)annotation;
+ if (!multiPoint.pointCount) {
+ continue;
+ }
+
+ MGLAnnotationTag annotationTag = _mbglMap->addAnnotation([multiPoint annotationObjectWithDelegate:self]);
+ MGLAnnotationContext context;
+ context.annotation = annotation;
+ _annotationContextsByAnnotationTag[annotationTag] = context;
+ }
+ else if ([annotation isKindOfClass:[MGLMultiPolyline class]]
+ || [annotation isKindOfClass:[MGLMultiPolygon class]]
+ || [annotation isKindOfClass:[MGLShapeCollection class]])
+ {
+ continue;
}
else
{
@@ -2826,7 +2865,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
{
annotationViewsForAnnotation[annotationValue] = annotationView;
annotationView.center = [self convertCoordinate:annotation.coordinate toPointToView:self];
- [self.glView addSubview:annotationView];
+ [newAnnotationViews addObject:annotationView];
}
}
@@ -2861,22 +2900,11 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
annotationImagesForAnnotation[annotationValue] = annotationImage;
}
- [userPoints addObject:annotation];
- points.emplace_back(MGLLatLngFromLocationCoordinate2D(annotation.coordinate), symbolName.UTF8String ?: "");
- }
- }
+ MGLAnnotationTag annotationTag = _mbglMap->addAnnotation(mbgl::SymbolAnnotation {
+ MGLPointFromLocationCoordinate2D(annotation.coordinate),
+ symbolName.UTF8String ?: ""
+ });
- if (points.size())
- {
- // refactor this to build contexts above and just associate with tags here
-
- std::vector<MGLAnnotationTag> annotationTags = _mbglMap->addPointAnnotations(points);
-
- for (size_t i = 0; i < annotationTags.size(); ++i)
- {
- id<MGLAnnotation> annotation = userPoints[i];
- NSValue *annotationValue = [NSValue valueWithNonretainedObject:annotation];
-
MGLAnnotationContext context;
context.annotation = annotation;
MGLAnnotationImage *annotationImage = annotationImagesForAnnotation[annotationValue];
@@ -2884,13 +2912,11 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
if (annotationImage) {
context.imageReuseIdentifier = annotationImage.reuseIdentifier;
}
- MGLAnnotationView *annotationView = annotationViewsForAnnotation[annotationValue];
if (annotationView) {
context.annotationView = annotationView;
context.viewReuseIdentifier = annotationView.reuseIdentifier;
}
- MGLAnnotationTag annotationTag = annotationTags[i];
_annotationContextsByAnnotationTag[annotationTag] = context;
if ([annotation isKindOfClass:[NSObject class]]) {
NSAssert(![annotation isKindOfClass:[MGLMultiPoint class]], @"Point annotation should not be MGLMultiPoint.");
@@ -2899,25 +2925,34 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
}
}
- if (shapes.size())
- {
- std::vector<MGLAnnotationTag> annotationTags = _mbglMap->addShapeAnnotations(shapes);
-
- for (size_t i = 0; i < annotationTags.size(); ++i)
- {
- MGLAnnotationTag annotationTag = annotationTags[i];
- id <MGLAnnotation> annotation = userShapes[i];
-
- MGLAnnotationContext context;
- context.annotation = annotation;
- _annotationContextsByAnnotationTag[annotationTag] = context;
- }
- }
+ [self updateAnnotationContainerViewWithAnnotationViews:newAnnotationViews];
[self didChangeValueForKey:@"annotations"];
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
}
+- (void)updateAnnotationContainerViewWithAnnotationViews:(NS_ARRAY_OF(MGLAnnotationView *) *)annotationViews
+{
+ if (annotationViews.count == 0) return;
+
+ MGLAnnotationContainerView *newAnnotationContainerView;
+ if (self.annotationContainerView)
+ {
+ // reload any previously added views
+ newAnnotationContainerView = [MGLAnnotationContainerView annotationContainerViewWithAnnotationContainerView:self.annotationContainerView];
+ [self.annotationContainerView removeFromSuperview];
+ }
+ else
+ {
+ newAnnotationContainerView = [[MGLAnnotationContainerView alloc] initWithFrame:self.bounds];
+ }
+ newAnnotationContainerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+ newAnnotationContainerView.contentMode = UIViewContentModeCenter;
+ [newAnnotationContainerView addSubviews:annotationViews];
+ [_glView insertSubview:newAnnotationContainerView atIndex:0];
+ self.annotationContainerView = newAnnotationContainerView;
+}
+
/// Initialize and return a default annotation image that depicts a round pin
/// rising from the center, with a shadow slightly below center. The alignment
/// rect therefore excludes the bottom half.
@@ -3032,8 +3067,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
{
if ( ! annotations) return;
- std::vector<MGLAnnotationTag> annotationTagsToRemove;
- annotationTagsToRemove.reserve(annotations.count);
+ [self willChangeValueForKey:@"annotations"];
for (id <MGLAnnotation> annotation in annotations)
{
@@ -3048,8 +3082,6 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
MGLAnnotationView *annotationView = annotationContext.annotationView;
[annotationView removeFromSuperview];
-
- annotationTagsToRemove.push_back(annotationTag);
if (annotationTag == _selectedAnnotationTag)
{
@@ -3062,15 +3094,12 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
{
[(NSObject *)annotation removeObserver:self forKeyPath:@"coordinate" context:(void *)(NSUInteger)annotationTag];
}
- }
- if ( ! annotationTagsToRemove.empty())
- {
- [self willChangeValueForKey:@"annotations"];
- _mbglMap->removeAnnotations(annotationTagsToRemove);
- [self didChangeValueForKey:@"annotations"];
- UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
+ _mbglMap->removeAnnotation(annotationTag);
}
+
+ [self didChangeValueForKey:@"annotations"];
+ UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
}
- (void)addOverlay:(id <MGLOverlay>)overlay
@@ -3635,8 +3664,8 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
{
if ([pair.second.imageReuseIdentifier isEqualToString:reuseIdentifier])
{
- const mbgl::LatLng latLng = MGLLatLngFromLocationCoordinate2D(pair.second.annotation.coordinate);
- _mbglMap->updatePointAnnotation(pair.first, { latLng, iconIdentifier.UTF8String ?: "" });
+ const mbgl::Point<double> point = MGLPointFromLocationCoordinate2D(pair.second.annotation.coordinate);
+ _mbglMap->updateAnnotation(pair.first, mbgl::SymbolAnnotation { point, iconIdentifier.UTF8String ?: "" });
}
}
}
@@ -4183,6 +4212,57 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
}
}
+#pragma mark Data
+
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point
+{
+ return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:nil];
+}
+
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers
+{
+ mbgl::ScreenCoordinate screenCoordinate = { point.x, point.y };
+
+ mbgl::optional<std::vector<std::string>> optionalLayerIDs;
+ if (styleLayerIdentifiers)
+ {
+ __block std::vector<std::string> layerIDs;
+ layerIDs.reserve(styleLayerIdentifiers.count);
+ [styleLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop)
+ {
+ layerIDs.push_back(identifier.UTF8String);
+ }];
+ optionalLayerIDs = layerIDs;
+ }
+
+ std::vector<mbgl::Feature> features = _mbglMap->queryRenderedFeatures(screenCoordinate, optionalLayerIDs);
+ return MGLFeaturesFromMBGLFeatures(features);
+}
+
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect {
+ return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:nil];
+}
+
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers {
+ mbgl::ScreenBox screenBox = {
+ { CGRectGetMinX(rect), CGRectGetMinY(rect) },
+ { CGRectGetMaxX(rect), CGRectGetMaxY(rect) },
+ };
+
+ mbgl::optional<std::vector<std::string>> optionalLayerIDs;
+ if (styleLayerIdentifiers) {
+ __block std::vector<std::string> layerIDs;
+ layerIDs.reserve(styleLayerIdentifiers.count);
+ [styleLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) {
+ layerIDs.push_back(identifier.UTF8String);
+ }];
+ optionalLayerIDs = layerIDs;
+ }
+
+ std::vector<mbgl::Feature> features = _mbglMap->queryRenderedFeatures(screenBox, optionalLayerIDs);
+ return MGLFeaturesFromMBGLFeatures(features);
+}
+
#pragma mark - Utility -
- (void)animateWithDelay:(NSTimeInterval)delay animations:(void (^)(void))animations
@@ -4918,7 +4998,7 @@ void MGLPrepareCustomStyleLayer(void *context)
}
}
-void MGLDrawCustomStyleLayer(void *context, const mbgl::CustomLayerRenderParameters &params)
+void MGLDrawCustomStyleLayer(void *context, const mbgl::style::CustomLayerRenderParameters &params)
{
CGSize size = CGSizeMake(params.width, params.height);
CLLocationCoordinate2D centerCoordinate = CLLocationCoordinate2DMake(params.latitude, params.longitude);
@@ -4950,14 +5030,14 @@ void MGLFinishCustomStyleLayer(void *context)
{
NSAssert(identifier, @"Style layer needs an identifier");
MGLCustomStyleLayerHandlers *context = new MGLCustomStyleLayerHandlers(preparation, drawing, completion);
- _mbglMap->addCustomLayer(identifier.UTF8String, MGLPrepareCustomStyleLayer,
- MGLDrawCustomStyleLayer, MGLFinishCustomStyleLayer,
- context, otherIdentifier.UTF8String);
+ _mbglMap->addLayer(std::make_unique<mbgl::style::CustomLayer>(identifier.UTF8String, MGLPrepareCustomStyleLayer,
+ MGLDrawCustomStyleLayer, MGLFinishCustomStyleLayer, context),
+ otherIdentifier ? mbgl::optional<std::string>(otherIdentifier.UTF8String) : mbgl::optional<std::string>());
}
- (void)removeCustomStyleLayerWithIdentifier:(NSString *)identifier
{
- _mbglMap->removeCustomLayer(identifier.UTF8String);
+ _mbglMap->removeLayer(identifier.UTF8String);
}
- (void)setCustomStyleLayersNeedDisplay
diff --git a/platform/ios/src/MGLMapViewDelegate.h b/platform/ios/src/MGLMapViewDelegate.h
new file mode 100644
index 0000000000..39eb43d4ca
--- /dev/null
+++ b/platform/ios/src/MGLMapViewDelegate.h
@@ -0,0 +1,284 @@
+#import <UIKit/UIKit.h>
+
+#import "MGLTypes.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class MGLMapView;
+
+/** The MGLMapViewDelegate protocol defines a set of optional methods that you can use to receive map-related update messages. Because many map operations require the `MGLMapView` class to load data asynchronously, the map view calls these methods to notify your application when specific operations complete. The map view also uses these methods to request annotation marker symbology and to manage interactions with those markers. */
+@protocol MGLMapViewDelegate <NSObject>
+
+@optional
+
+#pragma mark Responding to Map Position Changes
+
+/**
+ Tells the delegate that the region displayed by the map view is about to change.
+
+ This method is called whenever the currently displayed map region will start changing.
+
+ @param mapView The map view whose visible region will change.
+ @param animated Whether the change will cause an animated effect on the map.
+ */
+- (void)mapView:(MGLMapView *)mapView regionWillChangeAnimated:(BOOL)animated;
+
+/**
+ Tells the delegate that the region displayed by the map view is changing.
+
+ This method is called whenever the currently displayed map region changes. During movement, this method may be called many times to report updates to the map position. Therefore, your implementation of this method should be as lightweight as possible to avoid affecting performance.
+
+ @param mapView The map view whose visible region is changing.
+ */
+- (void)mapViewRegionIsChanging:(MGLMapView *)mapView;
+
+/**
+ Tells the delegate that the region displayed by the map view just changed.
+
+ This method is called whenever the currently displayed map region has finished changing.
+
+ @param mapView The map view whose visible region changed.
+ @param animated Whether the change caused an animated effect on the map.
+ */
+- (void)mapView:(MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
+
+#pragma mark Loading the Map
+
+/**
+ Tells the delegate that the map view will begin to load.
+
+ This method is called whenever the map view starts loading, including when a new style has been set and the map must reload.
+
+ @param mapView The map view that is starting to load.
+ */
+- (void)mapViewWillStartLoadingMap:(MGLMapView *)mapView;
+
+/**
+ Tells the delegate that the map view has finished loading.
+
+ This method is called whenever the map view finishes loading, either after the initial load or after a style change has forced a reload.
+
+ @param mapView The map view that has finished loading.
+ */
+- (void)mapViewDidFinishLoadingMap:(MGLMapView *)mapView;
+
+// TODO
+- (void)mapViewDidFailLoadingMap:(MGLMapView *)mapView withError:(NSError *)error;
+
+// TODO
+- (void)mapViewWillStartRenderingMap:(MGLMapView *)mapView;
+
+// TODO
+- (void)mapViewDidFinishRenderingMap:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered;
+
+// TODO
+- (void)mapViewWillStartRenderingFrame:(MGLMapView *)mapView;
+
+// TODO
+- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered;
+
+#pragma mark Tracking User Location
+
+/**
+ Tells the delegate that the map view will begin tracking the user's location.
+
+ This method is called when the value of the `showsUserLocation` property changes to `YES`.
+
+ @param mapView The map view that is tracking the user's location.
+ */
+- (void)mapViewWillStartLocatingUser:(MGLMapView *)mapView;
+
+/**
+ Tells the delegate that the map view has stopped tracking the user's location.
+
+ This method is called when the value of the `showsUserLocation` property changes to `NO`.
+
+ @param mapView The map view that is tracking the user's location.
+ */
+- (void)mapViewDidStopLocatingUser:(MGLMapView *)mapView;
+
+/**
+ Tells the delegate that the location of the user was updated.
+
+ While the `showsUserLocation` property is set to `YES`, this method is called whenever a new location update is received by the map view. This method is also called if the map view's user tracking mode is set to `MGLUserTrackingModeFollowWithHeading` and the heading changes, or if it is set to `MGLUserTrackingModeFollowWithCourse` and the course changes.
+
+ This method is not called if the application is currently running in the background. If you want to receive location updates while running in the background, you must use the Core Location framework.
+
+ @param mapView The map view that is tracking the user's location.
+ @param userLocation The location object representing the user's latest location. This property may be `nil`.
+ */
+- (void)mapView:(MGLMapView *)mapView didUpdateUserLocation:(nullable MGLUserLocation *)userLocation;
+
+/**
+ Tells the delegate that an attempt to locate the user's position failed.
+
+ @param mapView The map view that is tracking the user's location.
+ @param error An error object containing the reason why location tracking failed.
+ */
+- (void)mapView:(MGLMapView *)mapView didFailToLocateUserWithError:(NSError *)error;
+
+/**
+ Tells the delegate that the map view's user tracking mode has changed.
+
+ This method is called after the map view asynchronously changes to reflect the new user tracking mode, for example by beginning to zoom or rotate.
+
+ @param mapView The map view that changed its tracking mode.
+ @param mode The new tracking mode.
+ @param animated Whether the change caused an animated effect on the map.
+ */
+- (void)mapView:(MGLMapView *)mapView didChangeUserTrackingMode:(MGLUserTrackingMode)mode animated:(BOOL)animated;
+
+#pragma mark Managing the Display of Annotations
+
+/**
+ Returns a view object to use for the marker for the specified point annotation object.
+
+ @param mapView The map view that requested the annotation view.
+ @param annotation The object representing the annotation that is about to be displayed.
+ @return The view object to display for the specified annotation or `nil` if you want to display the default marker image.
+ */
+- (nullable MGLAnnotationView *)mapView:(MGLMapView *)mapView viewForAnnotation:(id <MGLAnnotation>)annotation;
+
+/**
+ Returns an image object to use for the marker for the specified point annotation object.
+
+ @param mapView The map view that requested the annotation image.
+ @param annotation The object representing the annotation that is about to be displayed.
+ @return The image object to display for the specified annotation or `nil` if you want to display the default marker image.
+ */
+- (nullable MGLAnnotationImage *)mapView:(MGLMapView *)mapView imageForAnnotation:(id <MGLAnnotation>)annotation;
+
+/**
+ Returns the alpha value to use when rendering a shape annotation. Defaults to `1.0`.
+
+ @param mapView The map view rendering the shape annotation.
+ @param annotation The annotation being rendered.
+ @return An alpha value between `0` and `1.0`.
+ */
+- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation;
+
+/**
+ Returns the stroke color to use when rendering a shape annotation. Defaults to the map view’s tint color.
+
+ @param mapView The map view rendering the shape annotation.
+ @param annotation The annotation being rendered.
+ @return A color to use for the shape outline.
+ */
+- (UIColor *)mapView:(MGLMapView *)mapView strokeColorForShapeAnnotation:(MGLShape *)annotation;
+
+/**
+ Returns the fill color to use when rendering a polygon annotation. Defaults to the map view’s tint color.
+
+ @param mapView The map view rendering the polygon annotation.
+ @param annotation The annotation being rendered.
+ @return A color to use for the polygon interior.
+ */
+- (UIColor *)mapView:(MGLMapView *)mapView fillColorForPolygonAnnotation:(MGLPolygon *)annotation;
+
+/**
+ Returns the line width to use when rendering a polyline annotation. Defaults to `3.0`.
+
+ @param mapView The map view rendering the polygon annotation.
+ @param annotation The annotation being rendered.
+ @return A line width for the polyline.
+ */
+- (CGFloat)mapView:(MGLMapView *)mapView lineWidthForPolylineAnnotation:(MGLPolyline *)annotation;
+
+/**
+ Returns a Boolean value indicating whether the annotation is able to display extra information in a callout bubble.
+
+ If the value returned is `YES`, a standard callout bubble is shown when the user taps a selected annotation. The callout uses the title and subtitle text from the associated annotation object. If there is no title text, though, the annotation will not show a callout. The callout also displays any custom callout views returned by the delegate for the left and right callout accessory views.
+
+ If the value returned is `NO`, the value of the title and subtitle strings are ignored.
+
+ @param mapView The map view that requested the annotation callout ability.
+ @param annotation The object representing the annotation.
+ @return A Boolean indicating whether the annotation should show a callout.
+ */
+- (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id <MGLAnnotation>)annotation;
+
+/**
+ Returns a callout view to display for the specified annotation.
+
+ If this method is present in the delegate, it must return a new instance of a view dedicated to display the callout bubble. It will be configured by the map view. If this method is not present, or if it returns `nil`, a standard, two-line, bubble-like callout view is displayed by default.
+
+ @param mapView The map view that requested the callout view.
+ @param annotation The object representing the annotation.
+ @return A view conforming to the `MGLCalloutView` protocol, or `nil` to use the default callout view.
+ */
+- (nullable UIView <MGLCalloutView> *)mapView:(MGLMapView *)mapView calloutViewForAnnotation:(id <MGLAnnotation>)annotation;
+
+/**
+ Returns the view to display on the left side of the standard callout bubble.
+
+ The default value is treated as if `nil`. The left callout view is typically used to display information about the annotation or to link to custom information provided by your application.
+
+ If the view you specify is also a descendant of the `UIControl` class, you can use the map view's delegate to receive notifications when your control is tapped. If it does not descend from `UIControl`, your view is responsible for handling any touch events within its bounds.
+
+ @param mapView The map view presenting the annotation callout.
+ @param annotation The object representing the annotation with the callout.
+ @return The accessory view to display.
+ */
+- (nullable UIView *)mapView:(MGLMapView *)mapView leftCalloutAccessoryViewForAnnotation:(id <MGLAnnotation>)annotation;
+
+/**
+ Returns the view to display on the right side of the standard callout bubble.
+
+ The default value is treated is if `nil`. The right callout view is typically used to link to more detailed information about the annotation. A common view to specify for this property is `UIButton` object whose type is set to `UIButtonTypeDetailDisclosure`.
+
+ If the view you specify is also a descendant of the `UIControl` class, you can use the map view's delegate to receive notifications when your control is tapped. If it does not descend from `UIControl`, your view is responsible for handling any touch events within its bounds.
+
+ @param mapView The map view presenting the annotation callout.
+ @param annotation The object representing the annotation with the callout.
+ @return The accessory view to display.
+ */
+- (nullable UIView *)mapView:(MGLMapView *)mapView rightCalloutAccessoryViewForAnnotation:(id <MGLAnnotation>)annotation;
+
+#pragma mark Managing Annotations
+
+/**
+ Tells the delegate that the user tapped one of the annotation's accessory buttons.
+
+ Accessory views contain custom content and are positioned on either side of the annotation title text. If a view you specify is a descendant of the `UIControl` class, the map view calls this method as a convenience whenever the user taps your view. You can use this method to respond to taps and perform any actions associated with that control. For example, if your control displayed additional information about the annotation, you could use this method to present a modal panel with that information.
+
+ If your custom accessory views are not descendants of the `UIControl` class, the map view does not call this method.
+
+ @param mapView The map view containing the specified annotation.
+ @param annotation The annotation whose button was tapped.
+ @param control The control that was tapped.
+ */
+- (void)mapView:(MGLMapView *)mapView annotation:(id <MGLAnnotation>)annotation calloutAccessoryControlTapped:(UIControl *)control;
+
+/**
+ Tells the delegate that the user tapped on an annotation's callout view.
+
+ @param mapView The map view containing the specified annotation.
+ @param annotation The annotation whose callout was tapped.
+ */
+- (void)mapView:(MGLMapView *)mapView tapOnCalloutForAnnotation:(id <MGLAnnotation>)annotation;
+
+#pragma mark Selecting Annotations
+
+/**
+ Tells the delegate that one of its annotations was selected.
+
+ You can use this method to track changes in the selection state of annotations.
+
+ @param mapView The map view containing the annotation.
+ @param annotation The annotation that was selected.
+ */
+- (void)mapView:(MGLMapView *)mapView didSelectAnnotation:(id <MGLAnnotation>)annotation;
+
+/**
+ Tells the delegate that one of its annotations was deselected.
+
+ You can use this method to track changes in the selection state of annotations.
+
+ @param mapView The map view containing the annotation.
+ @param annotation The annotation that was deselected.
+ */
+- (void)mapView:(MGLMapView *)mapView didDeselectAnnotation:(id <MGLAnnotation>)annotation;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/ios/src/MGLMapView_Internal.h b/platform/ios/src/MGLMapView_Internal.h
index 0538dd0392..6225e11749 100644
--- a/platform/ios/src/MGLMapView_Internal.h
+++ b/platform/ios/src/MGLMapView_Internal.h
@@ -1,5 +1,8 @@
#import <Mapbox/Mapbox.h>
+/// Minimum size of an annotation’s accessibility element.
+extern const CGSize MGLAnnotationAccessibilityElementMinimumSize;
+
@interface MGLMapView (Internal)
/** Triggers another render pass even when it is not necessary. */
diff --git a/platform/ios/src/MGLMapboxEvents.m b/platform/ios/src/MGLMapboxEvents.m
index 5b195a3baa..5ddf4e2b57 100644
--- a/platform/ios/src/MGLMapboxEvents.m
+++ b/platform/ios/src/MGLMapboxEvents.m
@@ -123,7 +123,7 @@ const NSTimeInterval MGLFlushInterval = 180;
@property (nonatomic) MGLLocationManager *locationManager;
@property (nonatomic) NSTimer *timer;
@property (nonatomic) NSDate *instanceIDRotationDate;
-@property (nonatomic) NSDate *turnstileSendDate;
+@property (nonatomic) NSDate *nextTurnstileSendDate;
@end
@@ -315,7 +315,7 @@ const NSTimeInterval MGLFlushInterval = 180;
}
- (void)pushTurnstileEvent {
- if (self.turnstileSendDate && [[NSDate date] timeIntervalSinceDate:self.turnstileSendDate] < 0) {
+ if (self.nextTurnstileSendDate && [[NSDate date] timeIntervalSinceDate:self.nextTurnstileSendDate] < 0) {
return;
}
@@ -342,11 +342,25 @@ const NSTimeInterval MGLFlushInterval = 180;
return;
}
[strongSelf writeEventToLocalDebugLog:turnstileEventAttributes];
- NSTimeInterval twentyFourHourTimeInterval = 24 * 3600;
- strongSelf.turnstileSendDate = [[NSDate date] dateByAddingTimeInterval:twentyFourHourTimeInterval];
+ [strongSelf updateNextTurnstileSendDate];
}];
}
+- (void)updateNextTurnstileSendDate {
+ // Find the time a day from now (sometime tomorrow)
+ NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
+ NSDateComponents *dayComponent = [[NSDateComponents alloc] init];
+ dayComponent.day = 1;
+ NSDate *sometimeTomorrow = [calendar dateByAddingComponents:dayComponent toDate:[NSDate date] options:0];
+
+ // Find the start of tomorrow and use that as the next turnstile send date. The effect of this is that
+ // turnstile events can be sent as much as once per calendar day and always at the start of a session
+ // when a map load happens.
+ NSDate *startOfTomorrow = nil;
+ [calendar rangeOfUnit:NSCalendarUnitDay startDate:&startOfTomorrow interval:nil forDate:sometimeTomorrow];
+ self.nextTurnstileSendDate = startOfTomorrow;
+}
+
+ (void)pushEvent:(NSString *)event withAttributes:(MGLMapboxEventAttributes *)attributeDictionary {
[[MGLMapboxEvents sharedManager] pushEvent:event withAttributes:attributeDictionary];
}
diff --git a/platform/ios/src/Mapbox.h b/platform/ios/src/Mapbox.h
index 3b7361a756..bc22a5f955 100644
--- a/platform/ios/src/Mapbox.h
+++ b/platform/ios/src/Mapbox.h
@@ -14,11 +14,13 @@ FOUNDATION_EXPORT const unsigned char MapboxVersionString[];
#import "MGLClockDirectionFormatter.h"
#import "MGLCompassDirectionFormatter.h"
#import "MGLCoordinateFormatter.h"
-#import "MGLMapCamera.h"
+#import "MGLFeature.h"
#import "MGLGeometry.h"
+#import "MGLMapCamera.h"
#import "MGLMapView.h"
#import "MGLMapView+IBAdditions.h"
#import "MGLMapView+MGLCustomStyleLayerAdditions.h"
+#import "MGLMapViewDelegate.h"
#import "MGLMultiPoint.h"
#import "MGLOfflinePack.h"
#import "MGLOfflineRegion.h"
@@ -28,6 +30,7 @@ FOUNDATION_EXPORT const unsigned char MapboxVersionString[];
#import "MGLPolygon.h"
#import "MGLPolyline.h"
#import "MGLShape.h"
+#import "MGLShapeCollection.h"
#import "MGLStyle.h"
#import "MGLTilePyramidOfflineRegion.h"
#import "MGLTypes.h"
diff --git a/platform/linux/platform.gyp b/platform/linux/platform.gyp
index 98a1e253c9..7adf5337c4 100644
--- a/platform/linux/platform.gyp
+++ b/platform/linux/platform.gyp
@@ -14,6 +14,7 @@
'includes': [
'../../mbgl.gypi',
'../../test/test.gypi',
+ '../../benchmark/benchmark.gypi',
'../../bin/glfw.gypi',
'../../bin/render.gypi',
'../../bin/offline.gypi',
@@ -34,6 +35,19 @@
],
},
{
+ 'target_name': 'benchmark',
+ 'type': 'executable',
+
+ 'dependencies': [
+ 'benchmark-lib',
+ 'platform-lib',
+ ],
+
+ 'sources': [
+ '../../benchmark/src/main.cpp',
+ ],
+ },
+ {
'target_name': 'platform-lib',
'product_name': 'mbgl-platform-linux',
'type': 'static_library',
diff --git a/platform/linux/scripts/configure.sh b/platform/linux/scripts/configure.sh
index 8ae3b2816d..8f041d589a 100644
--- a/platform/linux/scripts/configure.sh
+++ b/platform/linux/scripts/configure.sh
@@ -2,6 +2,7 @@
CXX11ABI=$(scripts/check-cxx11abi.sh)
+UNIQUE_RESOURCE_VERSION=dev
PROTOZERO_VERSION=1.3.0
BOOST_VERSION=1.60.0
BOOST_LIBPROGRAM_OPTIONS_VERSION=1.60.0
@@ -20,6 +21,8 @@ RAPIDJSON_VERSION=1.0.2
GTEST_VERSION=1.7.0${CXX11ABI:-}
PIXELMATCH_VERSION=0.9.0
WEBP_VERSION=0.5.0
+EARCUT_VERSION=0.11
+BENCHMARK_VERSION=1.0.0
function print_opengl_flags {
CONFIG+=" 'opengl_cflags%': $(quote_flags $(pkg-config gl x11 --cflags)),"$LN
diff --git a/platform/node/CHANGELOG.md b/platform/node/CHANGELOG.md
index d69b9e404c..a8f1d5be72 100644
--- a/platform/node/CHANGELOG.md
+++ b/platform/node/CHANGELOG.md
@@ -1,3 +1,12 @@
+# 3.2.0
+
+- Switches to [earcut.hpp](https://github.com/mapbox/earcut.hpp) for tessellation ([#2444](https://github.com/mapbox/mapbox-gl-native/pull/2444))
+
+# 3.1.3
+
+- Fixes a leak in TexturePoolHolder ([#5141](https://github.com/mapbox/mapbox-gl-native/pull/5141))
+- Fixes a bug where a callback would be fired after an AsyncRequest had been cancelled ([#5162](https://github.com/mapbox/mapbox-gl-native/pull/5162))
+
# 3.1.2
- Fixes a race condition with animated transitions ([#4836](https://github.com/mapbox/mapbox-gl-native/pull/4836))
diff --git a/platform/node/README.md b/platform/node/README.md
index 1a18c61d01..50f53d72eb 100644
--- a/platform/node/README.md
+++ b/platform/node/README.md
@@ -9,15 +9,15 @@ Requires a modern C++ runtime that supports C++14.
By default, installs binaries. On these platforms no additional dependencies are needed.
- 64 bit OS X or 64 bit Linux
-- Node.js v4+
+- Node.js v4.x _(note: v5+ is known to have issues)_
-Just run:
+Run:
```
npm install mapbox-gl-native
```
-Other platforms will fall back to a source compile with `make node`. To compile this module, make sure all submodules are initialized with `git submodule update --init` and install the [external dependencies required to build from source](https://github.com/mapbox/mapbox-gl-native/blob/node-v2.1.0/INSTALL.md#2-installing-dependencies).
+Other platforms will fall back to a source compile with `make node`; see INSTALL.md in the repository root directory for prequisites.
## Testing
diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp
index 7ed826275f..165e27b669 100644
--- a/platform/node/src/node_map.cpp
+++ b/platform/node/src/node_map.cpp
@@ -188,7 +188,7 @@ NAN_METHOD(NodeMap::Load) {
}
try {
- nodeMap->map->setStyleJSON(style, ".");
+ nodeMap->map->setStyleJSON(style);
} catch (const std::exception &ex) {
return Nan::ThrowError(ex.what());
}
@@ -528,12 +528,13 @@ std::unique_ptr<mbgl::AsyncRequest> NodeMap::request(const mbgl::Resource& resou
Nan::HandleScope scope;
auto requestHandle = NodeRequest::Create(resource, callback_)->ToObject();
+ auto request = Nan::ObjectWrap::Unwrap<NodeRequest>(requestHandle);
auto callbackHandle = Nan::New<v8::Function>(NodeRequest::Respond, requestHandle);
v8::Local<v8::Value> argv[] = { requestHandle, callbackHandle };
Nan::MakeCallback(handle()->GetInternalField(1)->ToObject(), "request", 2, argv);
- return std::make_unique<mbgl::AsyncRequest>();
+ return std::make_unique<NodeRequest::NodeAsyncRequest>(request);
}
-}
+} // namespace node_mbgl
diff --git a/platform/node/src/node_request.cpp b/platform/node/src/node_request.cpp
index d1a40a9080..fa560ed4e7 100644
--- a/platform/node/src/node_request.cpp
+++ b/platform/node/src/node_request.cpp
@@ -45,6 +45,14 @@ v8::Handle<v8::Object> NodeRequest::Create(const mbgl::Resource& resource, mbgl:
NAN_METHOD(NodeRequest::Respond) {
using Error = mbgl::Response::Error;
+ // Move out of the object so callback() can only be fired once.
+ auto request = Nan::ObjectWrap::Unwrap<NodeRequest>(info.Data().As<v8::Object>());
+ auto callback = std::move(request->callback);
+ if (!callback) {
+ info.GetReturnValue().SetUndefined();
+ return;
+ }
+
mbgl::Response response;
if (info.Length() < 1) {
@@ -114,14 +122,39 @@ NAN_METHOD(NodeRequest::Respond) {
}
// Send the response object to the NodeFileSource object
- Nan::ObjectWrap::Unwrap<NodeRequest>(info.Data().As<v8::Object>())->callback(response);
+ callback(response);
info.GetReturnValue().SetUndefined();
}
////////////////////////////////////////////////////////////////////////////////////////////////
// Instance
+NodeRequest::NodeAsyncRequest::NodeAsyncRequest(NodeRequest* request_) : request(request_) {
+ assert(request);
+ // Make sure the JS object has a pointer to this so that it can remove its pointer in the
+ // destructor
+ request->asyncRequest = this;
+}
+
+NodeRequest::NodeAsyncRequest::~NodeAsyncRequest() {
+ if (request) {
+ // Remove the callback function because the AsyncRequest was canceled and we are no longer
+ // interested in the result.
+ request->callback = {};
+ request->asyncRequest = nullptr;
+ }
+}
+
NodeRequest::NodeRequest(mbgl::FileSource::Callback callback_)
- : callback(callback_) {}
+ : callback(callback_) {
+}
+NodeRequest::~NodeRequest() {
+ // When this object gets garbage collected, make sure that the AsyncRequest can no longer
+ // attempt to remove the callback function this object was holding (it can't be fired anymore).
+ if (asyncRequest) {
+ asyncRequest->request = nullptr;
+ }
}
+
+} // namespace node_mbgl
diff --git a/platform/node/src/node_request.hpp b/platform/node/src/node_request.hpp
index 8e57cb30ec..2d307a3f19 100644
--- a/platform/node/src/node_request.hpp
+++ b/platform/node/src/node_request.hpp
@@ -12,6 +12,7 @@
namespace node_mbgl {
class NodeFileSource;
+class NodeRequest;
class NodeRequest : public Nan::ObjectWrap {
public:
@@ -24,9 +25,17 @@ public:
static Nan::Persistent<v8::Function> constructor;
NodeRequest(mbgl::FileSource::Callback);
+ ~NodeRequest();
+
+ struct NodeAsyncRequest : public mbgl::AsyncRequest {
+ NodeAsyncRequest(NodeRequest*);
+ ~NodeAsyncRequest() override;
+ NodeRequest* request;
+ };
private:
mbgl::FileSource::Callback callback;
+ NodeAsyncRequest* asyncRequest = nullptr;
};
}
diff --git a/platform/node/test/js/map.test.js b/platform/node/test/js/map.test.js
index 12b17126f9..e8434bc774 100644
--- a/platform/node/test/js/map.test.js
+++ b/platform/node/test/js/map.test.js
@@ -220,6 +220,26 @@ test('Map', function(t) {
t.end();
});
+ t.test('returns an error delayed', function(t) {
+ var delay = 0;
+ var map = new mbgl.Map({
+ request: function(req, callback) {
+ delay += 100;
+ setTimeout(function() {
+ callback(new Error('not found'));
+ }, delay);
+ },
+ ratio: 1
+ });
+ map.load(style);
+ map.render({ zoom: 1 }, function(err, data) {
+ map.release();
+
+ t.ok(err, 'returns error');
+ t.end();
+ });
+ });
+
t.test('returns an error', function(t) {
var map = new mbgl.Map(options);
map.load(style);
diff --git a/platform/osx/CHANGELOG.md b/platform/osx/CHANGELOG.md
index df26619bac..f2e1be966f 100644
--- a/platform/osx/CHANGELOG.md
+++ b/platform/osx/CHANGELOG.md
@@ -3,8 +3,11 @@
## master
* Fixed an issue in which Mapbox.framework was nested inside another folder named Mapbox.framework. ([#4998](https://github.com/mapbox/mapbox-gl-native/pull/4998))
+* Added methods to MGLMapView for obtaining the underlying map data rendered by the current style, along with additional classes to represent complex geometry in that data. ([#5110](https://github.com/mapbox/mapbox-gl-native/pull/5110))
+* An MGLPolygon can now have interior polygons, representing holes knocked out of the overall shape. ([#5110](https://github.com/mapbox/mapbox-gl-native/pull/5110))
* Fixed a crash passing a mixture of point and shape annotations into `-[MGLMapView addAnnotations:]`. ([#5097](https://github.com/mapbox/mapbox-gl-native/pull/5097))
* Added new options to `MGLMapDebugMaskOptions` that show wireframes and the stencil buffer instead of the color buffer. ([#4359](https://github.com/mapbox/mapbox-gl-native/pull/4359))
+* Fixed a memory leak when using raster resources. ([#5141](https://github.com/mapbox/mapbox-gl-native/pull/5141))
## 0.1.0
diff --git a/platform/osx/app/Base.lproj/MainMenu.xib b/platform/osx/app/Base.lproj/MainMenu.xib
index 4afb3b244e..c80428ff00 100644
--- a/platform/osx/app/Base.lproj/MainMenu.xib
+++ b/platform/osx/app/Base.lproj/MainMenu.xib
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15E65" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
</dependencies>
diff --git a/platform/osx/app/Base.lproj/MapDocument.xib b/platform/osx/app/Base.lproj/MapDocument.xib
index 9a3db47df6..55d82d21d0 100644
--- a/platform/osx/app/Base.lproj/MapDocument.xib
+++ b/platform/osx/app/Base.lproj/MapDocument.xib
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15E65" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
</dependencies>
@@ -123,6 +123,12 @@
<action selector="removePin:" target="-1" id="w0R-0B-7mG"/>
</connections>
</menuItem>
+ <menuItem title="Select Features" id="za5-bY-mdf">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="selectFeatures:" target="-1" id="ikt-CZ-yZT"/>
+ </connections>
+ </menuItem>
</items>
<connections>
<outlet property="delegate" destination="-2" id="oHe-ZP-lyc"/>
diff --git a/platform/osx/app/MapDocument.m b/platform/osx/app/MapDocument.m
index 9bff4603e4..4274126747 100644
--- a/platform/osx/app/MapDocument.m
+++ b/platform/osx/app/MapDocument.m
@@ -14,6 +14,27 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
{ .latitude = -13.15589555, .longitude = -74.2178961777998 },
};
+NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotation>) *shapes) {
+ NSMutableArray *flattenedShapes = [NSMutableArray arrayWithCapacity:shapes.count];
+ for (id <MGLAnnotation> shape in shapes) {
+ NSArray *subshapes;
+ if ([shape isKindOfClass:[MGLMultiPolyline class]]) {
+ subshapes = [(MGLMultiPolyline *)shape polylines];
+ } else if ([shape isKindOfClass:[MGLMultiPolygon class]]) {
+ subshapes = [(MGLMultiPolygon *)shape polygons];
+ } else if ([shape isKindOfClass:[MGLShapeCollection class]]) {
+ subshapes = MBXFlattenedShapes([(MGLShapeCollection *)shape shapes]);
+ }
+
+ if (subshapes) {
+ [flattenedShapes addObjectsFromArray:subshapes];
+ } else {
+ [flattenedShapes addObject:shape];
+ }
+ }
+ return flattenedShapes;
+}
+
@interface MapDocument () <NSWindowDelegate, NSSharingServicePickerDelegate, NSMenuDelegate, MGLMapViewDelegate>
@property (weak) IBOutlet NSMenu *mapViewContextMenu;
@@ -436,9 +457,17 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
}
- (DroppedPinAnnotation *)pinAtPoint:(NSPoint)point {
+ NSArray *features = [self.mapView visibleFeaturesAtPoint:point];
+ NSString *title;
+ for (id <MGLFeature> feature in features) {
+ if (!title) {
+ title = [feature attributeForKey:@"name_en"] ?: [feature attributeForKey:@"name"];
+ }
+ }
+
DroppedPinAnnotation *annotation = [[DroppedPinAnnotation alloc] init];
annotation.coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
- annotation.title = @"Dropped Pin";
+ annotation.title = title ?: @"Dropped Pin";
_spellOutNumberFormatter.numberStyle = NSNumberFormatterSpellOutStyle;
if (_showsToolTipsOnDroppedPins) {
NSString *formattedNumber = [_spellOutNumberFormatter stringFromNumber:@(++_droppedPinCounter)];
@@ -455,6 +484,16 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
[self.mapView removeAnnotation:[self.mapView annotationAtPoint:point]];
}
+- (IBAction)selectFeatures:(id)sender {
+ [self selectFeaturesAtPoint:_mouseLocationForMapViewContextMenu];
+}
+
+- (void)selectFeaturesAtPoint:(NSPoint)point {
+ NSArray *features = [self.mapView visibleFeaturesAtPoint:point];
+ NSArray *flattenedFeatures = MBXFlattenedShapes(features);
+ [self.mapView addAnnotations:flattenedFeatures];
+}
+
#pragma mark User interface validation
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
@@ -512,6 +551,9 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
menuItem.hidden = annotationUnderCursor == nil;
return YES;
}
+ if (menuItem.action == @selector(selectFeatures:)) {
+ return YES;
+ }
if (menuItem.action == @selector(toggleTileBoundaries:)) {
BOOL isShown = self.mapView.debugMask & MGLMapDebugTileBoundariesMask;
menuItem.title = isShown ? @"Hide Tile Boundaries" : @"Show Tile Boundaries";
@@ -706,6 +748,10 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
}
}
+- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation {
+ return 0.8;
+}
+
@end
@interface ValidatedToolbarItem : NSToolbarItem
diff --git a/platform/osx/jazzy.yml b/platform/osx/jazzy.yml
index b1aca9bb45..9e160d050f 100644
--- a/platform/osx/jazzy.yml
+++ b/platform/osx/jazzy.yml
@@ -29,11 +29,24 @@ custom_categories:
- MGLAnnotation
- MGLAnnotationImage
- MGLMultiPoint
+ - MGLMultiPolygon
+ - MGLMultiPolyline
- MGLPointAnnotation
- MGLPolygon
- MGLPolyline
- MGLOverlay
- MGLShape
+ - MGLShapeCollection
+ - name: Map Data
+ children:
+ - MGLFeature
+ - MGLMultiPointFeature
+ - MGLMultiPolygonFeature
+ - MGLMultiPolylineFeature
+ - MGLPointFeature
+ - MGLPolygonFeature
+ - MGLPolylineFeature
+ - MGLShapeCollectionFeature
- name: Offline Maps
children:
- MGLOfflineRegion
diff --git a/platform/osx/osx.xcodeproj/project.pbxproj b/platform/osx/osx.xcodeproj/project.pbxproj
index 270b2e33d2..51d9f0671e 100644
--- a/platform/osx/osx.xcodeproj/project.pbxproj
+++ b/platform/osx/osx.xcodeproj/project.pbxproj
@@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */
52BECB0A1CC5A26F009CD791 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52BECB091CC5A26F009CD791 /* SystemConfiguration.framework */; };
+ DA0CD58E1CF56F5800A5F5A5 /* MGLFeatureTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA0CD58D1CF56F5800A5F5A5 /* MGLFeatureTests.mm */; };
DA35A2A41CC9EB1A00E826B2 /* MGLCoordinateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = DA35A2A31CC9EB1A00E826B2 /* MGLCoordinateFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA35A2A61CC9EB2700E826B2 /* MGLCoordinateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2A51CC9EB2700E826B2 /* MGLCoordinateFormatter.m */; };
DA35A2A81CC9F41600E826B2 /* MGLCoordinateFormatterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2A71CC9F41600E826B2 /* MGLCoordinateFormatterTests.m */; };
@@ -31,6 +32,11 @@
DA8933B81CCD2C2D00E68420 /* Foundation.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DA8933B61CCD2C2D00E68420 /* Foundation.stringsdict */; };
DAB6924A1CC75A31005AAB54 /* libmbgl-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */; };
DAC2ABC51CC6D343006D18C4 /* MGLAnnotationImage_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */; };
+ DACC22141CF3D3E200D220D9 /* MGLFeature.h in Headers */ = {isa = PBXBuildFile; fileRef = DACC22121CF3D3E200D220D9 /* MGLFeature.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ DACC22151CF3D3E200D220D9 /* MGLFeature.mm in Sources */ = {isa = PBXBuildFile; fileRef = DACC22131CF3D3E200D220D9 /* MGLFeature.mm */; };
+ DACC22181CF3D4F700D220D9 /* MGLFeature_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DACC22171CF3D4F700D220D9 /* MGLFeature_Private.h */; };
+ DAD165741CF4CD7A001FF4B9 /* MGLShapeCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = DAD165721CF4CD7A001FF4B9 /* MGLShapeCollection.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ DAD165751CF4CD7A001FF4B9 /* MGLShapeCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = DAD165731CF4CD7A001FF4B9 /* MGLShapeCollection.m */; };
DAE6C2E21CC304F900DB3429 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = DAE6C2E11CC304F900DB3429 /* Credits.rtf */; };
DAE6C2ED1CC3050F00DB3429 /* DroppedPinAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C2E41CC3050F00DB3429 /* DroppedPinAnnotation.m */; };
DAE6C2EE1CC3050F00DB3429 /* LocationCoordinate2DTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C2E61CC3050F00DB3429 /* LocationCoordinate2DTransformer.m */; };
@@ -141,6 +147,7 @@
/* Begin PBXFileReference section */
52BECB091CC5A26F009CD791 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
+ DA0CD58D1CF56F5800A5F5A5 /* MGLFeatureTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLFeatureTests.mm; path = ../../darwin/test/MGLFeatureTests.mm; sourceTree = "<group>"; };
DA35A2A31CC9EB1A00E826B2 /* MGLCoordinateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCoordinateFormatter.h; sourceTree = "<group>"; };
DA35A2A51CC9EB2700E826B2 /* MGLCoordinateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLCoordinateFormatter.m; sourceTree = "<group>"; };
DA35A2A71CC9F41600E826B2 /* MGLCoordinateFormatterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLCoordinateFormatterTests.m; path = ../../darwin/test/MGLCoordinateFormatterTests.m; sourceTree = "<group>"; };
@@ -167,6 +174,11 @@
DA8933B41CCD2C2500E68420 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Foundation.strings; sourceTree = "<group>"; };
DA8933B71CCD2C2D00E68420 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationImage_Private.h; sourceTree = "<group>"; };
+ DACC22121CF3D3E200D220D9 /* MGLFeature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature.h; sourceTree = "<group>"; };
+ DACC22131CF3D3E200D220D9 /* MGLFeature.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFeature.mm; sourceTree = "<group>"; };
+ DACC22171CF3D4F700D220D9 /* MGLFeature_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFeature_Private.h; sourceTree = "<group>"; };
+ DAD165721CF4CD7A001FF4B9 /* MGLShapeCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeCollection.h; sourceTree = "<group>"; };
+ DAD165731CF4CD7A001FF4B9 /* MGLShapeCollection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLShapeCollection.m; sourceTree = "<group>"; };
DAE6C2E11CC304F900DB3429 /* Credits.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = Credits.rtf; sourceTree = "<group>"; };
DAE6C2E31CC3050F00DB3429 /* DroppedPinAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DroppedPinAnnotation.h; sourceTree = "<group>"; };
DAE6C2E41CC3050F00DB3429 /* DroppedPinAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DroppedPinAnnotation.m; sourceTree = "<group>"; };
@@ -359,6 +371,80 @@
path = ../../darwin/resources;
sourceTree = "<group>";
};
+ DAD1657C1CF4CE6B001FF4B9 /* Formatters */ = {
+ isa = PBXGroup;
+ children = (
+ DA35A2BD1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.h */,
+ DA35A2BE1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.m */,
+ DA35A2AB1CCA091800E826B2 /* MGLCompassDirectionFormatter.h */,
+ DA35A2AC1CCA091800E826B2 /* MGLCompassDirectionFormatter.m */,
+ DA35A2A31CC9EB1A00E826B2 /* MGLCoordinateFormatter.h */,
+ DA35A2A51CC9EB2700E826B2 /* MGLCoordinateFormatter.m */,
+ );
+ name = Formatters;
+ sourceTree = "<group>";
+ };
+ DAD1657D1CF4CECB001FF4B9 /* Geometry */ = {
+ isa = PBXGroup;
+ children = (
+ DAE6C34B1CC31E0400DB3429 /* MGLAnnotation.h */,
+ DACC22121CF3D3E200D220D9 /* MGLFeature.h */,
+ DACC22171CF3D4F700D220D9 /* MGLFeature_Private.h */,
+ DACC22131CF3D3E200D220D9 /* MGLFeature.mm */,
+ DAE6C34C1CC31E0400DB3429 /* MGLGeometry.h */,
+ DAE6C36C1CC31E2A00DB3429 /* MGLGeometry_Private.h */,
+ DAE6C36D1CC31E2A00DB3429 /* MGLGeometry.mm */,
+ DAE6C34E1CC31E0400DB3429 /* MGLMultiPoint.h */,
+ DAE6C36F1CC31E2A00DB3429 /* MGLMultiPoint_Private.h */,
+ DAE6C3701CC31E2A00DB3429 /* MGLMultiPoint.mm */,
+ DAE6C3521CC31E0400DB3429 /* MGLOverlay.h */,
+ DAE6C3531CC31E0400DB3429 /* MGLPointAnnotation.h */,
+ DAE6C3761CC31E2A00DB3429 /* MGLPointAnnotation.m */,
+ DAE6C3541CC31E0400DB3429 /* MGLPolygon.h */,
+ DAE6C3771CC31E2A00DB3429 /* MGLPolygon.mm */,
+ DAE6C3551CC31E0400DB3429 /* MGLPolyline.h */,
+ DAE6C3781CC31E2A00DB3429 /* MGLPolyline.mm */,
+ DAE6C3561CC31E0400DB3429 /* MGLShape.h */,
+ DAE6C3791CC31E2A00DB3429 /* MGLShape.m */,
+ DAD165721CF4CD7A001FF4B9 /* MGLShapeCollection.h */,
+ DAD165731CF4CD7A001FF4B9 /* MGLShapeCollection.m */,
+ );
+ name = Geometry;
+ sourceTree = "<group>";
+ };
+ DAD1657E1CF4CF04001FF4B9 /* Offline Maps */ = {
+ isa = PBXGroup;
+ children = (
+ DAE6C34F1CC31E0400DB3429 /* MGLOfflinePack.h */,
+ DAE6C3711CC31E2A00DB3429 /* MGLOfflinePack_Private.h */,
+ DAE6C3721CC31E2A00DB3429 /* MGLOfflinePack.mm */,
+ DAE6C3501CC31E0400DB3429 /* MGLOfflineRegion.h */,
+ DAE6C3731CC31E2A00DB3429 /* MGLOfflineRegion_Private.h */,
+ DAE6C3511CC31E0400DB3429 /* MGLOfflineStorage.h */,
+ DAE6C3741CC31E2A00DB3429 /* MGLOfflineStorage_Private.h */,
+ DAE6C3751CC31E2A00DB3429 /* MGLOfflineStorage.mm */,
+ DAE6C3581CC31E0400DB3429 /* MGLTilePyramidOfflineRegion.h */,
+ DAE6C37B1CC31E2A00DB3429 /* MGLTilePyramidOfflineRegion.mm */,
+ );
+ name = "Offline Maps";
+ sourceTree = "<group>";
+ };
+ DAD1657F1CF4CF50001FF4B9 /* Categories */ = {
+ isa = PBXGroup;
+ children = (
+ DAE6C37D1CC31E2A00DB3429 /* NSBundle+MGLAdditions.h */,
+ DAE6C37E1CC31E2A00DB3429 /* NSBundle+MGLAdditions.m */,
+ DAE6C37F1CC31E2A00DB3429 /* NSException+MGLAdditions.h */,
+ DAE6C3801CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.h */,
+ DAE6C3811CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.m */,
+ DAE6C3821CC31E2A00DB3429 /* NSString+MGLAdditions.h */,
+ DAE6C3831CC31E2A00DB3429 /* NSString+MGLAdditions.m */,
+ DA35A2CD1CCAAED300E826B2 /* NSValue+MGLAdditions.h */,
+ DA35A2CE1CCAAED300E826B2 /* NSValue+MGLAdditions.m */,
+ );
+ name = Categories;
+ sourceTree = "<group>";
+ };
DAE6C31E1CC308BC00DB3429 /* Frameworks */ = {
isa = PBXGroup;
children = (
@@ -390,6 +476,7 @@
DA35A2C11CCA9F4A00E826B2 /* MGLClockDirectionFormatterTests.m */,
DA35A2B51CCA14D700E826B2 /* MGLCompassDirectionFormatterTests.m */,
DA35A2A71CC9F41600E826B2 /* MGLCoordinateFormatterTests.m */,
+ DA0CD58D1CF56F5800A5F5A5 /* MGLFeatureTests.mm */,
DAE6C3C81CC34BD800DB3429 /* MGLGeometryTests.mm */,
DAE6C3C91CC34BD800DB3429 /* MGLOfflinePackTests.m */,
DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */,
@@ -404,56 +491,19 @@
DAE6C3491CC31DF500DB3429 /* Foundation */ = {
isa = PBXGroup;
children = (
+ DAD1657F1CF4CF50001FF4B9 /* Categories */,
+ DAD1657C1CF4CE6B001FF4B9 /* Formatters */,
+ DAD1657D1CF4CECB001FF4B9 /* Geometry */,
+ DAD1657E1CF4CF04001FF4B9 /* Offline Maps */,
DAE6C34A1CC31E0400DB3429 /* MGLAccountManager.h */,
DAE6C36A1CC31E2A00DB3429 /* MGLAccountManager_Private.h */,
DAE6C36B1CC31E2A00DB3429 /* MGLAccountManager.m */,
- DAE6C34B1CC31E0400DB3429 /* MGLAnnotation.h */,
- DA35A2BD1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.h */,
- DA35A2BE1CCA9B1A00E826B2 /* MGLClockDirectionFormatter.m */,
- DA35A2AB1CCA091800E826B2 /* MGLCompassDirectionFormatter.h */,
- DA35A2AC1CCA091800E826B2 /* MGLCompassDirectionFormatter.m */,
- DA35A2A31CC9EB1A00E826B2 /* MGLCoordinateFormatter.h */,
- DA35A2A51CC9EB2700E826B2 /* MGLCoordinateFormatter.m */,
- DAE6C34C1CC31E0400DB3429 /* MGLGeometry.h */,
- DAE6C36C1CC31E2A00DB3429 /* MGLGeometry_Private.h */,
- DAE6C36D1CC31E2A00DB3429 /* MGLGeometry.mm */,
DAE6C34D1CC31E0400DB3429 /* MGLMapCamera.h */,
DAE6C36E1CC31E2A00DB3429 /* MGLMapCamera.mm */,
- DAE6C34E1CC31E0400DB3429 /* MGLMultiPoint.h */,
- DAE6C36F1CC31E2A00DB3429 /* MGLMultiPoint_Private.h */,
- DAE6C3701CC31E2A00DB3429 /* MGLMultiPoint.mm */,
- DAE6C34F1CC31E0400DB3429 /* MGLOfflinePack.h */,
- DAE6C3711CC31E2A00DB3429 /* MGLOfflinePack_Private.h */,
- DAE6C3721CC31E2A00DB3429 /* MGLOfflinePack.mm */,
- DAE6C3501CC31E0400DB3429 /* MGLOfflineRegion.h */,
- DAE6C3731CC31E2A00DB3429 /* MGLOfflineRegion_Private.h */,
- DAE6C3511CC31E0400DB3429 /* MGLOfflineStorage.h */,
- DAE6C3741CC31E2A00DB3429 /* MGLOfflineStorage_Private.h */,
- DAE6C3751CC31E2A00DB3429 /* MGLOfflineStorage.mm */,
- DAE6C3521CC31E0400DB3429 /* MGLOverlay.h */,
- DAE6C3531CC31E0400DB3429 /* MGLPointAnnotation.h */,
- DAE6C3761CC31E2A00DB3429 /* MGLPointAnnotation.m */,
- DAE6C3541CC31E0400DB3429 /* MGLPolygon.h */,
- DAE6C3771CC31E2A00DB3429 /* MGLPolygon.mm */,
- DAE6C3551CC31E0400DB3429 /* MGLPolyline.h */,
- DAE6C3781CC31E2A00DB3429 /* MGLPolyline.mm */,
- DAE6C3561CC31E0400DB3429 /* MGLShape.h */,
- DAE6C3791CC31E2A00DB3429 /* MGLShape.m */,
DAE6C3571CC31E0400DB3429 /* MGLStyle.h */,
DAE6C37A1CC31E2A00DB3429 /* MGLStyle.mm */,
- DAE6C3581CC31E0400DB3429 /* MGLTilePyramidOfflineRegion.h */,
- DAE6C37B1CC31E2A00DB3429 /* MGLTilePyramidOfflineRegion.mm */,
DAE6C3591CC31E0400DB3429 /* MGLTypes.h */,
DAE6C37C1CC31E2A00DB3429 /* MGLTypes.m */,
- DAE6C37D1CC31E2A00DB3429 /* NSBundle+MGLAdditions.h */,
- DAE6C37E1CC31E2A00DB3429 /* NSBundle+MGLAdditions.m */,
- DAE6C37F1CC31E2A00DB3429 /* NSException+MGLAdditions.h */,
- DAE6C3801CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.h */,
- DAE6C3811CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.m */,
- DAE6C3821CC31E2A00DB3429 /* NSString+MGLAdditions.h */,
- DAE6C3831CC31E2A00DB3429 /* NSString+MGLAdditions.m */,
- DA35A2CD1CCAAED300E826B2 /* NSValue+MGLAdditions.h */,
- DA35A2CE1CCAAED300E826B2 /* NSValue+MGLAdditions.m */,
);
name = Foundation;
path = ../darwin/src;
@@ -506,6 +556,7 @@
DAE6C3611CC31E0400DB3429 /* MGLOfflineStorage.h in Headers */,
DAE6C35E1CC31E0400DB3429 /* MGLMultiPoint.h in Headers */,
DAE6C3971CC31E2A00DB3429 /* NSBundle+MGLAdditions.h in Headers */,
+ DAD165741CF4CD7A001FF4B9 /* MGLShapeCollection.h in Headers */,
DAE6C3631CC31E0400DB3429 /* MGLPointAnnotation.h in Headers */,
DAC2ABC51CC6D343006D18C4 /* MGLAnnotationImage_Private.h in Headers */,
DAE6C35F1CC31E0400DB3429 /* MGLOfflinePack.h in Headers */,
@@ -528,6 +579,7 @@
DA35A2CF1CCAAED300E826B2 /* NSValue+MGLAdditions.h in Headers */,
DAE6C3A61CC31E9400DB3429 /* MGLMapViewDelegate.h in Headers */,
DAE6C38B1CC31E2A00DB3429 /* MGLOfflinePack_Private.h in Headers */,
+ DACC22141CF3D3E200D220D9 /* MGLFeature.h in Headers */,
DAE6C35C1CC31E0400DB3429 /* MGLGeometry.h in Headers */,
DAE6C35A1CC31E0400DB3429 /* MGLAccountManager.h in Headers */,
DAE6C35D1CC31E0400DB3429 /* MGLMapCamera.h in Headers */,
@@ -536,6 +588,7 @@
DAE6C3891CC31E2A00DB3429 /* MGLMultiPoint_Private.h in Headers */,
DAE6C3A51CC31E9400DB3429 /* MGLMapView+IBAdditions.h in Headers */,
DA35A2AD1CCA091800E826B2 /* MGLCompassDirectionFormatter.h in Headers */,
+ DACC22181CF3D4F700D220D9 /* MGLFeature_Private.h in Headers */,
DAE6C3671CC31E0400DB3429 /* MGLStyle.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -718,6 +771,7 @@
DAE6C3B71CC31EF300DB3429 /* MGLMapView.mm in Sources */,
DAE6C38C1CC31E2A00DB3429 /* MGLOfflinePack.mm in Sources */,
DAE6C3B11CC31EF300DB3429 /* MGLAnnotationImage.m in Sources */,
+ DACC22151CF3D3E200D220D9 /* MGLFeature.mm in Sources */,
DAE6C3B31CC31EF300DB3429 /* MGLAttributionButton.m in Sources */,
DAE6C3931CC31E2A00DB3429 /* MGLShape.m in Sources */,
DAE6C39D1CC31E2A00DB3429 /* NSString+MGLAdditions.m in Sources */,
@@ -738,6 +792,7 @@
DAE6C3851CC31E2A00DB3429 /* MGLAccountManager.m in Sources */,
DAE6C3921CC31E2A00DB3429 /* MGLPolyline.mm in Sources */,
DAE6C3B51CC31EF300DB3429 /* MGLCompassCell.m in Sources */,
+ DAD165751CF4CD7A001FF4B9 /* MGLShapeCollection.m in Sources */,
DA35A2AE1CCA091800E826B2 /* MGLCompassDirectionFormatter.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -754,6 +809,7 @@
DAE6C3D51CC34C9900DB3429 /* MGLOfflineStorageTests.m in Sources */,
DAE6C3D31CC34C9900DB3429 /* MGLOfflinePackTests.m in Sources */,
DA35A2A81CC9F41600E826B2 /* MGLCoordinateFormatterTests.m in Sources */,
+ DA0CD58E1CF56F5800A5F5A5 /* MGLFeatureTests.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1042,6 +1098,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
+ "$(variant_cflags)",
"$(geometry_cflags)",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test;
@@ -1059,6 +1116,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
+ "$(variant_cflags)",
"$(geometry_cflags)",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test;
@@ -1094,6 +1152,7 @@
DAAA17981CE13BAE00731EFE /* Release */,
);
defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
};
DAE6C3431CC30DB200DB3429 /* Build configuration list for PBXNativeTarget "dynamic" */ = {
isa = XCConfigurationList;
diff --git a/platform/osx/platform.gyp b/platform/osx/platform.gyp
index c3f94935d3..bbda61e7d9 100644
--- a/platform/osx/platform.gyp
+++ b/platform/osx/platform.gyp
@@ -8,6 +8,7 @@
'../../build/osx/config.gypi',
'../../mbgl.gypi',
'../../test/test.gypi',
+ '../../benchmark/benchmark.gypi',
'../../bin/glfw.gypi',
'../../bin/render.gypi',
'../../bin/offline.gypi',
@@ -27,6 +28,19 @@
],
},
{
+ 'target_name': 'benchmark',
+ 'type': 'executable',
+
+ 'dependencies': [
+ 'benchmark-lib',
+ 'platform-lib',
+ ],
+
+ 'sources': [
+ '../../benchmark/src/main.cpp',
+ ],
+ },
+ {
'target_name': 'platform-lib',
'product_name': 'mbgl-platform-osx',
'type': 'static_library',
diff --git a/platform/osx/scripts/configure.sh b/platform/osx/scripts/configure.sh
index f009bae4f6..2952ec2535 100644
--- a/platform/osx/scripts/configure.sh
+++ b/platform/osx/scripts/configure.sh
@@ -1,5 +1,6 @@
#!/usr/bin/env bash
+UNIQUE_RESOURCE_VERSION=dev
PROTOZERO_VERSION=1.3.0
BOOST_VERSION=1.60.0
BOOST_LIBPROGRAM_OPTIONS_VERSION=1.60.0
@@ -13,3 +14,5 @@ VARIANT_VERSION=1.1.0
RAPIDJSON_VERSION=1.0.2
GTEST_VERSION=1.7.0
PIXELMATCH_VERSION=0.9.0
+EARCUT_VERSION=0.11
+BENCHMARK_VERSION=1.0.0
diff --git a/platform/osx/src/MGLMapView.h b/platform/osx/src/MGLMapView.h
index 749b3561d2..5c7e75135b 100644
--- a/platform/osx/src/MGLMapView.h
+++ b/platform/osx/src/MGLMapView.h
@@ -35,6 +35,7 @@ typedef NS_OPTIONS(NSUInteger, MGLMapDebugMaskOptions) {
@protocol MGLAnnotation;
@protocol MGLMapViewDelegate;
@protocol MGLOverlay;
+@protocol MGLFeature;
/**
An interactive, customizable map view with an interface similar to the one
@@ -533,6 +534,11 @@ IB_DESIGNABLE
/**
Adds an annotation to the map view.
+ @note `MGLMultiPolyline`, `MGLMultiPolygon`, and `MGLShapeCollection` objects
+ cannot be added to the map view at this time. Any multipolyline,
+ multipolygon, or shape collection object that is passed into this method is
+ silently ignored.
+
@param annotation The annotation object to add to the receiver. This object
must conform to the `MGLAnnotation` protocol. The map view retains the
annotation object.
@@ -542,6 +548,11 @@ IB_DESIGNABLE
/**
Adds an array of annotations to the map view.
+ @note `MGLMultiPolyline`, `MGLMultiPolygon`, and `MGLShapeCollection` objects
+ cannot be added to the map view at this time. Any multipolyline,
+ multipolygon, or shape collection objects that are passed in are silently
+ ignored.
+
@param annotations An array of annotation objects. Each object in the array
must conform to the `MGLAnnotation` protocol. The map view retains each
individual annotation object.
@@ -687,6 +698,132 @@ IB_DESIGNABLE
*/
- (void)removeOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays;
+#pragma mark Accessing the Underlying Map Data
+
+/**
+ Returns an array of rendered map features that intersect with a given point.
+
+ This method may return features from any of the map’s style layers. To restrict
+ the search to a particular layer or layers, use the
+ `-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:` method. For more
+ information about searching for map features, see that method’s documentation.
+
+ @param point A point expressed in the map view’s coordinate system.
+ @return An array of objects conforming to the `MGLFeature` protocol that
+ represent features in the sources used by the current style.
+ */
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point NS_SWIFT_NAME(visibleFeatures(_:));
+
+/**
+ Returns an array of rendered map features that intersect with a given point,
+ restricted to the given style layers.
+
+ Each object in the returned array represents a feature rendered by the
+ current style and provides access to attributes specified by the relevant
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile sources</a>.
+ The returned array includes features specified in vector and GeoJSON tile
+ sources but does not include anything from raster, image, or video sources.
+
+ Only visible features are returned. For example, suppose the current style uses
+ the
+ <a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets source</a>,
+ but none of the specified style layers includes features that have the `maki`
+ property set to `bus`. If you pass a point corresponding to the location of a
+ bus stop into this method, the bus stop feature does not appear in the
+ resulting array. On the other hand, if the style does include bus stops, an
+ `MGLFeature` object representing that bus stop is returned and its
+ `attributes` dictionary has the `maki` key set to `bus` (along with other
+ attributes). The dictionary contains only the attributes provided by the
+ tile source; it does not include computed attribute values or rules about how
+ the feature is rendered by the current style.
+
+ The returned array is sorted by z-order, starting with the topmost rendered
+ feature and ending with the bottommost rendered feature. A feature that is
+ rendered multiple times due to wrapping across the antimeridian at low zoom
+ levels is included only once, subject to the caveat that follows.
+
+ Features come from tiled vector data or GeoJSON data that is converted to tiles
+ internally, so feature geometries are clipped at tile boundaries and features
+ may appear duplicated across tiles. For example, suppose the specified point
+ lies along a road that spans the screen. The resulting array includes those
+ parts of the road that lie within the map tile that contain the specified
+ point, even if the road extends into other tiles.
+
+ To find out the layer names in a particular style, view the style in
+ <a href="https://www.mapbox.com/studio/">Mapbox Studio</a>.
+
+ @param point A point expressed in the map view’s coordinate system.
+ @param styleLayerIdentifiers A set of strings that correspond to the names of
+ layers defined in the current style. Only the features contained in these
+ layers are included in the returned array.
+ @return An array of objects conforming to the `MGLFeature` protocol that
+ represent features in the sources used by the current style.
+ */
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(_:styleLayerIdentifiers:));
+
+/**
+ Returns an array of rendered map features that intersect with the given
+ rectangle.
+
+ This method may return features from any of the map’s style layers. To restrict
+ the search to a particular layer or layers, use the
+ `-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:` method. For more
+ information about searching for map features, see that method’s documentation.
+
+ @param rect A rectangle expressed in the map view’s coordinate system.
+ @return An array of objects conforming to the `MGLFeature` protocol that
+ represent features in the sources used by the current style.
+ */
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect NS_SWIFT_NAME(visibleFeatures(_:));
+
+/**
+ Returns an array of rendered map features that intersect with the given
+ rectangle, restricted to the given style layers.
+
+ Each object in the returned array represents a feature rendered by the
+ current style and provides access to attributes specified by the relevant
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile sources</a>.
+ The returned array includes features specified in vector and GeoJSON tile
+ sources but does not include anything from raster, image, or video sources.
+
+ Only visible features are returned. For example, suppose the current style uses
+ the
+ <a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets source</a>,
+ but none of the specified style layers includes features that have the `maki`
+ property set to `bus`. If you pass a rectangle containing the location of a bus
+ stop into this method, the bus stop feature does not appear in the resulting
+ array. On the other hand, if the style does include bus stops, an `MGLFeature`
+ object representing that bus stop is returned and its `attributes` dictionary
+ has the `maki` key set to `bus` (along with other attributes). The dictionary
+ contains only the attributes provided by the tile source; it does not include
+ computed attribute values or rules about how the feature is rendered by the
+ current style.
+
+ The returned array is sorted by z-order, starting with the topmost rendered
+ feature and ending with the bottommost rendered feature. A feature that is
+ rendered multiple times due to wrapping across the antimeridian at low zoom
+ levels is included only once, subject to the caveat that follows.
+
+ Features come from tiled vector data or GeoJSON data that is converted to tiles
+ internally, so feature geometries are clipped at tile boundaries and features
+ may appear duplicated across tiles. For example, suppose the specified
+ rectangle intersects with a road that spans the screen. The resulting array
+ includes those parts of the road that lie within the map tiles covering the
+ specified rectangle, even if the road extends into other tiles. The portion of
+ the road within each map tile is included individually.
+
+ To find out the layer names in a particular style, view the style in
+ <a href="https://www.mapbox.com/studio/">Mapbox Studio</a>.
+
+ @param rect A rectangle expressed in the map view’s coordinate system.
+ @param styleLayerIdentifiers A set of strings that correspond to the names of
+ layers defined in the current style. Only the features contained in these
+ layers are included in the returned array.
+ @return An array of objects conforming to the `MGLFeature` protocol that
+ represent features in the sources used by the current style.
+ */
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(_:styleLayerIdentifiers:));
+
#pragma mark Converting Geographic Coordinates
/**
diff --git a/platform/osx/src/MGLMapView.mm b/platform/osx/src/MGLMapView.mm
index 5b85ff7ec2..03b94c25ba 100644
--- a/platform/osx/src/MGLMapView.mm
+++ b/platform/osx/src/MGLMapView.mm
@@ -5,6 +5,7 @@
#import "MGLOpenGLLayer.h"
#import "MGLStyle.h"
+#import "MGLFeature_Private.h"
#import "MGLGeometry_Private.h"
#import "MGLMultiPoint_Private.h"
#import "MGLOfflineStorage_Private.h"
@@ -17,7 +18,7 @@
#import "MGLMapViewDelegate.h"
#import <mbgl/mbgl.hpp>
-#import <mbgl/annotation/point_annotation.hpp>
+#import <mbgl/annotation/annotation.hpp>
#import <mbgl/map/camera.hpp>
#import <mbgl/platform/darwin/reachability.h>
#import <mbgl/gl/gl.hpp>
@@ -480,9 +481,9 @@ public:
// match a valid annotation tag, the annotation will be unnecessarily
// but safely updated.
if (annotation == [self annotationWithTag:annotationTag]) {
- const mbgl::LatLng latLng = MGLLatLngFromLocationCoordinate2D(annotation.coordinate);
+ const mbgl::Point<double> point = MGLPointFromLocationCoordinate2D(annotation.coordinate);
MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
- _mbglMap->updatePointAnnotation(annotationTag, { latLng, annotationImage.styleIconIdentifier.UTF8String ?: "" });
+ _mbglMap->updateAnnotation(annotationTag, mbgl::SymbolAnnotation { point, annotationImage.styleIconIdentifier.UTF8String ?: "" });
if (annotationTag == _selectedAnnotationTag) {
[self deselectAnnotation:annotation];
}
@@ -1603,19 +1604,24 @@ public:
BOOL delegateHasImagesForAnnotations = [self.delegate respondsToSelector:@selector(mapView:imageForAnnotation:)];
- NSMutableArray *userPoints = [NSMutableArray array];
- std::vector<mbgl::PointAnnotation> points;
- NSMutableArray *userShapes = [NSMutableArray array];
- std::vector<mbgl::ShapeAnnotation> shapes;
- NSMutableArray *annotationImages = [NSMutableArray arrayWithCapacity:annotations.count];
-
for (id <MGLAnnotation> annotation in annotations) {
NSAssert([annotation conformsToProtocol:@protocol(MGLAnnotation)], @"Annotation does not conform to MGLAnnotation");
if ([annotation isKindOfClass:[MGLMultiPoint class]]) {
// The multipoint knows how to style itself (with the map view’s help).
- [(MGLMultiPoint *)annotation addShapeAnnotationObjectToCollection:shapes withDelegate:self];
- [userShapes addObject:annotation];
+ MGLMultiPoint *multiPoint = (MGLMultiPoint *)annotation;
+ if (!multiPoint.pointCount) {
+ continue;
+ }
+
+ MGLAnnotationTag annotationTag = _mbglMap->addAnnotation([multiPoint annotationObjectWithDelegate:self]);
+ MGLAnnotationContext context;
+ context.annotation = annotation;
+ _annotationContextsByAnnotationTag[annotationTag] = context;
+ } else if ([annotation isKindOfClass:[MGLMultiPolyline class]]
+ || [annotation isKindOfClass:[MGLMultiPolygon class]]
+ || [annotation isKindOfClass:[MGLShapeCollection class]]) {
+ continue;
} else {
MGLAnnotationImage *annotationImage = nil;
if (delegateHasImagesForAnnotations) {
@@ -1638,28 +1644,12 @@ public:
self.annotationImagesByIdentifier[annotationImage.reuseIdentifier] = annotationImage;
[self installAnnotationImage:annotationImage];
}
- [annotationImages addObject:annotationImage];
-
- [userPoints addObject:annotation];
- points.emplace_back(MGLLatLngFromLocationCoordinate2D(annotation.coordinate), symbolName.UTF8String ?: "");
-
- // Opt into potentially expensive tooltip tracking areas.
- if (annotation.toolTip.length) {
- _wantsToolTipRects = YES;
- }
- }
- }
-
- // Add any point annotations to mbgl and our own index.
- if (points.size()) {
- std::vector<MGLAnnotationTag> annotationTags = _mbglMap->addPointAnnotations(points);
-
- for (size_t i = 0; i < annotationTags.size(); ++i) {
- MGLAnnotationTag annotationTag = annotationTags[i];
- MGLAnnotationImage *annotationImage = annotationImages[i];
- annotationImage.styleIconIdentifier = @(points[i].icon.c_str());
- id <MGLAnnotation> annotation = userPoints[i];
-
+
+ MGLAnnotationTag annotationTag = _mbglMap->addAnnotation(mbgl::SymbolAnnotation {
+ MGLPointFromLocationCoordinate2D(annotation.coordinate),
+ symbolName.UTF8String ?: ""
+ });
+
MGLAnnotationContext context;
context.annotation = annotation;
context.imageReuseIdentifier = annotationImage.reuseIdentifier;
@@ -1669,23 +1659,14 @@ public:
NSAssert(![annotation isKindOfClass:[MGLMultiPoint class]], @"Point annotation should not be MGLMultiPoint.");
[(NSObject *)annotation addObserver:self forKeyPath:@"coordinate" options:0 context:(void *)(NSUInteger)annotationTag];
}
+
+ // Opt into potentially expensive tooltip tracking areas.
+ if (annotation.toolTip.length) {
+ _wantsToolTipRects = YES;
+ }
}
}
-
- // Add any shape annotations to mbgl and our own index.
- if (shapes.size()) {
- std::vector<MGLAnnotationTag> annotationTags = _mbglMap->addShapeAnnotations(shapes);
-
- for (size_t i = 0; i < annotationTags.size(); ++i) {
- MGLAnnotationTag annotationTag = annotationTags[i];
- id <MGLAnnotation> annotation = userShapes[i];
-
- MGLAnnotationContext context;
- context.annotation = annotation;
- _annotationContextsByAnnotationTag[annotationTag] = context;
- }
- }
-
+
[self didChangeValueForKey:@"annotations"];
[self updateAnnotationTrackingAreas];
@@ -1756,16 +1737,14 @@ public:
return;
}
- std::vector<MGLAnnotationTag> annotationTagsToRemove;
- annotationTagsToRemove.reserve(annotations.count);
-
+ [self willChangeValueForKey:@"annotations"];
+
for (id <MGLAnnotation> annotation in annotations) {
NSAssert([annotation conformsToProtocol:@protocol(MGLAnnotation)], @"Annotation does not conform to MGLAnnotation");
MGLAnnotationTag annotationTag = [self annotationTagForAnnotation:annotation];
NSAssert(annotationTag != MGLAnnotationTagNotFound, @"No ID for annotation %@", annotation);
- annotationTagsToRemove.push_back(annotationTag);
-
+
if (annotationTag == _selectedAnnotationTag) {
[self deselectAnnotation:annotation];
}
@@ -1779,10 +1758,10 @@ public:
![annotation isKindOfClass:[MGLMultiPoint class]]) {
[(NSObject *)annotation removeObserver:self forKeyPath:@"coordinate" context:(void *)(NSUInteger)annotationTag];
}
+
+ _mbglMap->removeAnnotation(annotationTag);
}
- [self willChangeValueForKey:@"annotations"];
- _mbglMap->removeAnnotations(annotationTagsToRemove);
[self didChangeValueForKey:@"annotations"];
[self updateAnnotationTrackingAreas];
@@ -2246,6 +2225,55 @@ public:
}
}
+#pragma mark Data
+
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point {
+ return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:nil];
+}
+
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers {
+ // Cocoa origin is at the lower-left corner.
+ mbgl::ScreenCoordinate screenCoordinate = { point.x, NSHeight(self.bounds) - point.y };
+
+ mbgl::optional<std::vector<std::string>> optionalLayerIDs;
+ if (styleLayerIdentifiers) {
+ __block std::vector<std::string> layerIDs;
+ layerIDs.reserve(styleLayerIdentifiers.count);
+ [styleLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) {
+ layerIDs.push_back(identifier.UTF8String);
+ }];
+ optionalLayerIDs = layerIDs;
+ }
+
+ std::vector<mbgl::Feature> features = _mbglMap->queryRenderedFeatures(screenCoordinate, optionalLayerIDs);
+ return MGLFeaturesFromMBGLFeatures(features);
+}
+
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect {
+ return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:nil];
+}
+
+- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers {
+ // Cocoa origin is at the lower-left corner.
+ mbgl::ScreenBox screenBox = {
+ { NSMinX(rect), NSHeight(self.bounds) - NSMaxY(rect) },
+ { NSMaxX(rect), NSHeight(self.bounds) - NSMinY(rect) },
+ };
+
+ mbgl::optional<std::vector<std::string>> optionalLayerIDs;
+ if (styleLayerIdentifiers) {
+ __block std::vector<std::string> layerIDs;
+ layerIDs.reserve(styleLayerIdentifiers.count);
+ [styleLayerIdentifiers enumerateObjectsUsingBlock:^(NSString * _Nonnull identifier, BOOL * _Nonnull stop) {
+ layerIDs.push_back(identifier.UTF8String);
+ }];
+ optionalLayerIDs = layerIDs;
+ }
+
+ std::vector<mbgl::Feature> features = _mbglMap->queryRenderedFeatures(screenBox, optionalLayerIDs);
+ return MGLFeaturesFromMBGLFeatures(features);
+}
+
#pragma mark Interface Builder methods
- (void)prepareForInterfaceBuilder {
diff --git a/platform/osx/src/Mapbox.h b/platform/osx/src/Mapbox.h
index a98aea9bcf..e4545e04bc 100644
--- a/platform/osx/src/Mapbox.h
+++ b/platform/osx/src/Mapbox.h
@@ -12,6 +12,7 @@ FOUNDATION_EXPORT const unsigned char MapboxVersionString[];
#import "MGLClockDirectionFormatter.h"
#import "MGLCompassDirectionFormatter.h"
#import "MGLCoordinateFormatter.h"
+#import "MGLFeature.h"
#import "MGLGeometry.h"
#import "MGLMapCamera.h"
#import "MGLMapView.h"
@@ -26,6 +27,7 @@ FOUNDATION_EXPORT const unsigned char MapboxVersionString[];
#import "MGLPolygon.h"
#import "MGLPolyline.h"
#import "MGLShape.h"
+#import "MGLShapeCollection.h"
#import "MGLStyle.h"
#import "MGLTilePyramidOfflineRegion.h"
#import "MGLTypes.h"
diff --git a/platform/qt/README.md b/platform/qt/README.md
index 56f9301b31..d763682717 100644
--- a/platform/qt/README.md
+++ b/platform/qt/README.md
@@ -1,6 +1,7 @@
# Mapbox Qt SDK
[![Travis](https://travis-ci.org/mapbox/mapbox-gl-native.svg?branch=master)](https://travis-ci.org/mapbox/mapbox-gl-native/builds)
+[![Bitrise](https://www.bitrise.io/app/96cfbc97e0245c22.svg?token=GxsqIOGPXhn0F23sSVSsYA&branch=master)](https://www.bitrise.io/app/96cfbc97e0245c22)
Provides [Qt](http://www.qt.io/) example applications and APIs via `QMapboxGL`
and `QQuickMapboxGL`:
diff --git a/platform/qt/include/qmapbox.hpp b/platform/qt/include/qmapbox.hpp
index f2cf363ea3..3200da2729 100644
--- a/platform/qt/include/qmapbox.hpp
+++ b/platform/qt/include/qmapbox.hpp
@@ -20,11 +20,9 @@ typedef quint32 AnnotationID;
typedef QList<AnnotationID> AnnotationIDs;
typedef QPair<Coordinate, QString> PointAnnotation;
-typedef QList<PointAnnotation> PointAnnotations;
// FIXME: We need to add support for custom style properties
typedef QPair<CoordinateSegments, QString> ShapeAnnotation;
-typedef QList<ShapeAnnotation> ShapeAnnotations;
enum NetworkMode {
Online, // Default
diff --git a/platform/qt/include/qmapboxgl.hpp b/platform/qt/include/qmapboxgl.hpp
index 3b10dadc9c..8ce6b02f47 100644
--- a/platform/qt/include/qmapboxgl.hpp
+++ b/platform/qt/include/qmapboxgl.hpp
@@ -165,15 +165,11 @@ public:
QStringList getClasses() const;
QMapbox::AnnotationID addPointAnnotation(const QMapbox::PointAnnotation &);
- QMapbox::AnnotationIDs addPointAnnotations(const QMapbox::PointAnnotations &);
-
QMapbox::AnnotationID addShapeAnnotation(const QMapbox::ShapeAnnotation &);
- QMapbox::AnnotationIDs addShapeAnnotations(const QMapbox::ShapeAnnotations &);
void updatePointAnnotation(QMapbox::AnnotationID, const QMapbox::PointAnnotation &);
void removeAnnotation(QMapbox::AnnotationID);
- void removeAnnotations(const QMapbox::AnnotationIDs &);
bool isRotating() const;
bool isScaling() const;
diff --git a/platform/qt/scripts/configure.sh b/platform/qt/scripts/configure.sh
index bb9df18038..4b855f7c58 100644
--- a/platform/qt/scripts/configure.sh
+++ b/platform/qt/scripts/configure.sh
@@ -2,6 +2,7 @@
CXX11ABI=$(scripts/check-cxx11abi.sh)
+UNIQUE_RESOURCE_VERSION=dev
PROTOZERO_VERSION=1.3.0
BOOST_VERSION=1.60.0
GEOMETRY_VERSION=0.5.0
@@ -15,6 +16,7 @@ SQLITE_VERSION=3.9.1
VARIANT_VERSION=1.1.0
ZLIB_VERSION=system
WEBP_VERSION=0.5.0
+EARCUT_VERSION=0.11
function print_default_flags {
CONFIG+=" 'cflags': $(quote_flags -fvisibility=hidden),"$LN
diff --git a/platform/qt/src/async_task.cpp b/platform/qt/src/async_task.cpp
index cfad70d8dd..c376c1c370 100644
--- a/platform/qt/src/async_task.cpp
+++ b/platform/qt/src/async_task.cpp
@@ -4,6 +4,8 @@
#include <mbgl/util/run_loop.hpp>
+#include <cassert>
+
namespace mbgl {
namespace util {
@@ -20,6 +22,8 @@ void AsyncTask::Impl::maySend() {
}
void AsyncTask::Impl::runTask() {
+ assert(runLoop == RunLoop::Get());
+
queued.clear();
task();
}
diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp
index dd4cab056d..144d545d3c 100644
--- a/platform/qt/src/qmapboxgl.cpp
+++ b/platform/qt/src/qmapboxgl.cpp
@@ -1,14 +1,15 @@
#include "qmapboxgl_p.hpp"
-#include <mbgl/annotation/point_annotation.hpp>
-#include <mbgl/annotation/shape_annotation.hpp>
+#include <mbgl/annotation/annotation.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/map/camera.hpp>
#include <mbgl/map/map.hpp>
+#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/sprite/sprite_image.hpp>
#include <mbgl/storage/network_status.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/geo.hpp>
+#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/traits.hpp>
#if QT_VERSION >= 0x050000
@@ -23,6 +24,7 @@
#include <QMargins>
#include <QString>
#include <QStringList>
+#include <QThreadStorage>
#include <memory>
@@ -67,6 +69,12 @@ static_assert(mbgl::underlying_type(QMapboxGL::MapChangeWillStartRenderingMap) =
static_assert(mbgl::underlying_type(QMapboxGL::MapChangeDidFinishRenderingMap) == mbgl::underlying_type(mbgl::MapChangeDidFinishRenderingMap), "error");
static_assert(mbgl::underlying_type(QMapboxGL::MapChangeDidFinishRenderingMapFullyRendered) == mbgl::underlying_type(mbgl::MapChangeDidFinishRenderingMapFullyRendered), "error");
+namespace {
+
+QThreadStorage<std::shared_ptr<mbgl::util::RunLoop>> loop;
+
+}
+
QMapboxGLSettings::QMapboxGLSettings()
: m_mapMode(QMapboxGLSettings::ContinuousMap)
, m_contextMode(QMapboxGLSettings::SharedGLContext)
@@ -159,8 +167,14 @@ void QMapboxGLSettings::setAccessToken(const QString &token)
QMapboxGL::QMapboxGL(QObject *parent_, const QMapboxGLSettings &settings)
: QObject(parent_)
- , d_ptr(new QMapboxGLPrivate(this, settings))
{
+ // Multiple QMapboxGL running on the same thread
+ // will share the same mbgl::util::RunLoop
+ if (!loop.hasLocalData()) {
+ loop.setLocalData(std::make_shared<mbgl::util::RunLoop>());
+ }
+
+ d_ptr = new QMapboxGLPrivate(this, settings);
}
QMapboxGL::~QMapboxGL()
@@ -362,81 +376,46 @@ QStringList QMapboxGL::getClasses() const
return classNames;
}
-mbgl::PointAnnotation fromPointAnnotation(const PointAnnotation &pointAnnotation) {
+mbgl::Annotation fromPointAnnotation(const PointAnnotation &pointAnnotation) {
const Coordinate &coordinate = pointAnnotation.first;
const QString &icon = pointAnnotation.second;
- return { { coordinate.first, coordinate.second }, icon.toStdString() };
+ return mbgl::SymbolAnnotation { mbgl::Point<double> { coordinate.second, coordinate.first }, icon.toStdString() };
}
AnnotationID QMapboxGL::addPointAnnotation(const PointAnnotation &pointAnnotation)
{
- return d_ptr->mapObj->addPointAnnotation(fromPointAnnotation(pointAnnotation));
-}
-
-AnnotationIDs QMapboxGL::addPointAnnotations(const PointAnnotations &pointAnnotations)
-{
- std::vector<mbgl::PointAnnotation> mbglPointAnnotations;
- mbglPointAnnotations.reserve(pointAnnotations.size());
-
- for (const PointAnnotation &pointAnnotation : pointAnnotations) {
- mbglPointAnnotations.emplace_back(fromPointAnnotation(pointAnnotation));
- }
-
- AnnotationIDs ids;
- for (const mbgl::AnnotationID &id : d_ptr->mapObj->addPointAnnotations(mbglPointAnnotations)) {
- ids << id;
- }
-
- return ids;
+ return d_ptr->mapObj->addAnnotation(fromPointAnnotation(pointAnnotation));
}
void QMapboxGL::updatePointAnnotation(AnnotationID id, const PointAnnotation &pointAnnotation)
{
- d_ptr->mapObj->updatePointAnnotation(id, fromPointAnnotation(pointAnnotation));
+ d_ptr->mapObj->updateAnnotation(id, fromPointAnnotation(pointAnnotation));
}
-mbgl::ShapeAnnotation fromQMapboxGLShapeAnnotation(const ShapeAnnotation &shapeAnnotation) {
+mbgl::Annotation fromQMapboxGLShapeAnnotation(const ShapeAnnotation &shapeAnnotation) {
const CoordinateSegments &segments = shapeAnnotation.first;
const QString &styleLayer = shapeAnnotation.second;
- mbgl::AnnotationSegments mbglAnnotationSegments;
- mbglAnnotationSegments.reserve(segments.size());
+ mbgl::Polygon<double> polygon;
+ polygon.reserve(segments.size());
for (const Coordinates &coordinates : segments) {
- mbgl::AnnotationSegment mbglAnnotationSegment;
- mbglAnnotationSegment.reserve(coordinates.size());
+ mbgl::LinearRing<double> linearRing;
+ linearRing.reserve(coordinates.size());
for (const Coordinate &coordinate : coordinates) {
- mbgl::LatLng mbglCoordinate(coordinate.first, coordinate.second);
- mbglAnnotationSegment.emplace_back(mbglCoordinate);
+ linearRing.emplace_back(mbgl::Point<double>(coordinate.first, coordinate.second));
}
- mbglAnnotationSegments.emplace_back(mbglAnnotationSegment);
+ polygon.emplace_back(linearRing);
}
- return { mbglAnnotationSegments, styleLayer.toStdString() };
+ return mbgl::StyleSourcedAnnotation { polygon, styleLayer.toStdString() };
}
AnnotationID QMapboxGL::addShapeAnnotation(const ShapeAnnotation &shapeAnnotation)
{
- return d_ptr->mapObj->addShapeAnnotation(fromQMapboxGLShapeAnnotation(shapeAnnotation));
-}
-
-AnnotationIDs QMapboxGL::addShapeAnnotations(const ShapeAnnotations &shapeAnnotations)
-{
- std::vector<mbgl::ShapeAnnotation> mbglShapeAnnotations;
- mbglShapeAnnotations.reserve(shapeAnnotations.size());
-
- for (const ShapeAnnotation &shapeAnnotation : shapeAnnotations) {
- mbglShapeAnnotations.emplace_back(fromQMapboxGLShapeAnnotation(shapeAnnotation));
- }
-
- AnnotationIDs ids;
- for (const mbgl::AnnotationID &id : d_ptr->mapObj->addShapeAnnotations(mbglShapeAnnotations)) {
- ids << id;
- }
-
- return ids;
+ return d_ptr->mapObj->addAnnotation(fromQMapboxGLShapeAnnotation(shapeAnnotation));
}
void QMapboxGL::removeAnnotation(AnnotationID annotationID)
@@ -444,18 +423,6 @@ void QMapboxGL::removeAnnotation(AnnotationID annotationID)
d_ptr->mapObj->removeAnnotation(annotationID);
}
-void QMapboxGL::removeAnnotations(const AnnotationIDs &annotationIDs)
-{
- std::vector<mbgl::AnnotationID> mbglAnnotationIds;
- mbglAnnotationIds.reserve(annotationIDs.size());
-
- for (const AnnotationID annotationID : annotationIDs) {
- mbglAnnotationIds.emplace_back(annotationID);
- }
-
- d_ptr->mapObj->removeAnnotations(mbglAnnotationIds);
-}
-
bool QMapboxGL::isRotating() const
{
return d_ptr->mapObj->isRotating();
@@ -497,7 +464,7 @@ void QMapboxGL::resize(const QSize& size)
QSize converted = size / d_ptr->getPixelRatio();
if (d_ptr->size == converted) return;
- glViewport(0, 0, size.width(), size.height());
+ glViewport(0, 0, converted.width(), converted.height());
d_ptr->size = converted;
d_ptr->mapObj->update(mbgl::Update::Dimensions);
@@ -590,20 +557,20 @@ void QMapboxGL::addCustomLayer(const QString &id,
void *context_,
char *before)
{
- d_ptr->mapObj->addCustomLayer(
+ d_ptr->mapObj->addLayer(std::make_unique<mbgl::style::CustomLayer>(
id.toStdString(),
- reinterpret_cast<mbgl::CustomLayerInitializeFunction>(initFn),
+ reinterpret_cast<mbgl::style::CustomLayerInitializeFunction>(initFn),
// This cast is safe as long as both mbgl:: and QMapbox::
// CustomLayerRenderParameters members remains the same.
- (mbgl::CustomLayerRenderFunction)renderFn,
- reinterpret_cast<mbgl::CustomLayerDeinitializeFunction>(deinitFn),
- context_,
- before == NULL ? nullptr : before);
+ (mbgl::style::CustomLayerRenderFunction)renderFn,
+ reinterpret_cast<mbgl::style::CustomLayerDeinitializeFunction>(deinitFn),
+ context_),
+ before ? mbgl::optional<std::string>(before) : mbgl::optional<std::string>());
}
void QMapboxGL::removeCustomLayer(const QString& id)
{
- d_ptr->mapObj->removeCustomLayer(id.toStdString());
+ d_ptr->mapObj->removeLayer(id.toStdString());
}
void QMapboxGL::render()
diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp
index 1e52f43363..fdbfb7f2c1 100644
--- a/platform/qt/src/qmapboxgl_p.hpp
+++ b/platform/qt/src/qmapboxgl_p.hpp
@@ -5,7 +5,6 @@
#include <mbgl/map/view.hpp>
#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/util/geo.hpp>
-#include <mbgl/util/run_loop.hpp>
#include <QMapboxGL>
#include <QObject>
@@ -34,8 +33,6 @@ public:
QMapboxGL *q_ptr = nullptr;
- mbgl::util::RunLoop loop;
-
std::unique_ptr<mbgl::DefaultFileSource> fileSourceObj;
std::unique_ptr<mbgl::Map> mapObj;