summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinh Nguyễn <mxn@1ec5.org>2016-12-06 23:36:55 -0800
committerGitHub <noreply@github.com>2016-12-06 23:36:55 -0800
commit4c2aec2355b166174bd062b1d27f8f89fad6008c (patch)
tree5d840c4b0d79dc401fc84ffad70ef0d2478bc524
parent9f9422deb808ff5f77aa640c8222207fa6456e04 (diff)
downloadqtlocation-mapboxgl-4c2aec2355b166174bd062b1d27f8f89fad6008c.tar.gz
[ios, macos] More ways to reshape an MGLMultiPoint (#7251)
* [ios, macos] Completed API for mutating multipoints Added the complete set of methods for mutating the vertices of an MGLMultiPoint. Also rewrote MGLMultiPoint documentation to refer to vertices instead of points. * [ios, macos] Removed inaccurate MGLOverlay commentary This paragraph is full of references to features that exist in MKOverlay but not MGLOverlay. * [ios, macos] Lazily compute multipoint bounds Invalidate the bounds whenever the coordinates change, but don’t recompute the bounds until they’re requested. Simplified -intersectsOverlayBounds: for immutable overlay classes. Added a utility function for testing whether two MGLCoordinateBounds intersect, based on mbgl::LatLngBounds::intersects(). Removed unused color conversion code.
-rw-r--r--platform/darwin/src/MGLGeometry.h8
-rw-r--r--platform/darwin/src/MGLMultiPoint.h130
-rw-r--r--platform/darwin/src/MGLMultiPoint.mm97
-rw-r--r--platform/darwin/src/MGLOverlay.h8
-rw-r--r--platform/darwin/src/MGLPointCollection.mm13
-rw-r--r--platform/darwin/src/MGLPolygon.mm2
-rw-r--r--platform/darwin/src/MGLPolyline.mm2
-rw-r--r--platform/ios/CHANGELOG.md2
-rw-r--r--platform/macos/CHANGELOG.md2
9 files changed, 179 insertions, 85 deletions
diff --git a/platform/darwin/src/MGLGeometry.h b/platform/darwin/src/MGLGeometry.h
index e2a4d818b9..8e36b86d96 100644
--- a/platform/darwin/src/MGLGeometry.h
+++ b/platform/darwin/src/MGLGeometry.h
@@ -62,6 +62,14 @@ NS_INLINE BOOL MGLCoordinateBoundsEqualToCoordinateBounds(MGLCoordinateBounds bo
bounds1.ne.longitude == bounds2.ne.longitude);
}
+/** Returns `YES` if the two coordinate bounds intersect. */
+NS_INLINE BOOL MGLCoordinateBoundsIntersectsCoordinateBounds(MGLCoordinateBounds bounds1, MGLCoordinateBounds bounds2) {
+ return (bounds1.ne.latitude > bounds2.sw.latitude &&
+ bounds1.sw.latitude < bounds2.ne.latitude &&
+ bounds1.ne.longitude > bounds2.sw.longitude &&
+ bounds1.sw.longitude < bounds2.ne.longitude);
+}
+
/** Returns `YES` if the coordinate is within the coordinate bounds. */
NS_INLINE BOOL MGLCoordinateInCoordinateBounds(CLLocationCoordinate2D coordinate, MGLCoordinateBounds bounds) {
return (coordinate.latitude >= bounds.sw.latitude &&
diff --git a/platform/darwin/src/MGLMultiPoint.h b/platform/darwin/src/MGLMultiPoint.h
index 3431fc2483..ed40ee9cad 100644
--- a/platform/darwin/src/MGLMultiPoint.h
+++ b/platform/darwin/src/MGLMultiPoint.h
@@ -7,67 +7,133 @@ NS_ASSUME_NONNULL_BEGIN
/**
The `MGLMultiPoint` class is an abstract superclass used to define shapes
- composed of multiple points. You should not create instances of this class
+ composed of multiple vertices. You should not create instances of this class
directly. Instead, you should create instances of the `MGLPolyline` or
`MGLPolygon` classes. However, you can use the method and properties of this
- class to access information about the specific points associated with the line
- or polygon.
+ class to access information about the vertices of the line or polygon.
*/
@interface MGLMultiPoint : MGLShape
/**
- The array of coordinates associated with the shape.
+ The array of vertices associated with the shape.
- This C array is a pointer to a structure inside the multipoint object,
- which may have a lifetime shorter than the multipoint object and will
- certainly not have a longer lifetime. Therefore, you should copy the C
- array if it needs to be stored outside of the memory context in which you
- use this property.
+ This C array is a pointer to a structure inside the multipoint object, which
+ may have a lifetime shorter than the multipoint object and will certainly not
+ have a longer lifetime. Therefore, you should copy the C array if it needs to
+ be stored outside of the memory context in which you use this property.
*/
@property (nonatomic, readonly) CLLocationCoordinate2D *coordinates NS_RETURNS_INNER_POINTER;
-/** The number of coordinates associated with the shape. (read-only) */
+/** The number of vertices in the shape. */
@property (nonatomic, readonly) NSUInteger pointCount;
/**
- Retrieves one or more coordinates associated with the shape.
+ Retrieves the vertices of part of the shape.
- @param coords On input, you must provide a C array of structures large enough
- to hold the desired number of coordinates. On output, this structure
- contains the requested coordinate data.
- @param range The range of points you want. The `location` field indicates the
- first point you are requesting, with `0` being the first point, `1` being
- the second point, and so on. The `length` field indicates the number of
- points you want. The array in _`coords`_ must be large enough to accommodate
- the number of requested coordinates.
+ @param coords On input, you must provide a C array of `CLLocationCoordinate2D`
+ structures large enough to hold the desired number of coordinates. On
+ output, this structure contains the requested coordinate data.
+ @param range The range of vertices you want. The `location` field indicates
+ the first vertex you are requesting, with `0` being the first vertex, `1`
+ being the second vertex, and so on. The `length` field indicates the number
+ of vertices you want. The array in `coords` must be large enough to
+ accommodate the number of requested coordinates.
*/
- (void)getCoordinates:(CLLocationCoordinate2D *)coords range:(NSRange)range;
/**
- Updates one or more coordinates for the shape, which will instantaneously
- cause the shape to be redrawn if it is currently visible on the map.
+ Sets the shape’s vertices to the given C array of vertices.
- @param range The range of points to update. The `location` field indicates the
- first point you are replacing, with `0` being the first point, `1` being
- the second point, and so on. The `length` field indicates the number of
- points to update. The array in _`coords`_ must be equal in number to the
- length of the range. If you want to append to the existing coordinates
- array use `-[MGLMultiPoint appendCoordinates:count:]`.
@param coords The array of coordinates defining the shape. The data in this
- array is copied to the object.
+ array is copied to the shape’s `coordinates` property.
+ @param count The number of coordinates from the `coords` array.
*/
-- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords;
+- (void)setCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count;
+
+/**
+ Inserts the given vertices into the shape. If the shape is currently visible on
+ the map, it is redrawn immediately.
+
+ @param coords The array of coordinates to insert into the shape. The data in
+ this array is copied to the shape’s `coordinate` property.
+ @param count The number of items in the `coords` array.
+ @param index The zero-based index at which the first coordinate in `coords`
+ will appear in the `coordinates` property.
+ */
+- (void)insertCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count atIndex:(NSUInteger)index;
/**
- Appends one or more coordinates for the shape, which will instantaneously
- cause the shape to be redrawn if it is currently visible on the map.
+ Appends the given vertices to the shape. If the shape is currently visible on
+ the map, it is redrawn immediately.
@param coords The array of coordinates to add to the shape. The data in this
- array is copied to the new object.
+ array is copied to the shape’s `coordinate` property.
@param count The number of items in the `coords` array.
*/
- (void)appendCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count;
+/**
+ Replaces the vertices at the given range in the shape with the same number of
+ vertices from a given C array. If the shape is currently visible on the map, it
+ is redrawn immediately.
+
+ The number of coordinates in `coords` must be equal to the length of `range`.
+ If you want to insert or delete one or more vertices, use the
+ `-replaceCoordinatesInRange:withCoordinates:count:` method.
+
+ If `range` extends beyond the shape’s `coordinates` property, an
+ `NSRangeException` is raised. If you want to append new vertices to the shape,
+ use the `-appendCoordinates:count:` method.
+
+ @param range The range of vertices to replace. The `location` field indicates
+ the first vertex you are replacing, with `0` being the first vertex, `1`
+ being the second vertex, and so on. The `length` field indicates the number
+ of vertices to replace.
+ @param coords The array of coordinates defining part of the shape. The data in
+ this array is copied to the shape’s `coordinate` property.
+ */
+- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords;
+
+/**
+ Replaces the vertices at the given range in the shape with the specified number
+ of vertices from a given C array. If the shape is currently visible on the map,
+ it is redrawn immediately.
+
+ If `count` is greater than the `length` field of `range`, some vertices will
+ effectively be inserted into the shape. On the other hand, if `count` is less
+ than the `length` field of `range`, some vertices will effectively be removed.
+
+ If `range` extends beyond the shape’s `coordinates` property, an
+ `NSRangeException` is raised. If you want to append new vertices to the shape,
+ use the `-appendCoordinates:count:` method.
+
+ @param range The range of vertices to replace. The `location` field indicates
+ the first vertex you are replacing, with `0` being the first vertex, `1`
+ being the second vertex, and so on. The `length` field indicates the number
+ of vertices to replace.
+ @param coords The array of coordinates defining part of the shape. The data in
+ this array is copied to the shape’s `coordinates` property.
+ @param count The number of coordinates from the `coords` array to insert in
+ place of the coordinates in `range`. The sum of `range`’s length and this
+ count must not exceed the number of items currently in the `coordinates`
+ property.
+ */
+- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count;
+
+/**
+ Removes the vertices at the given range from the shape. If the shape is
+ currently visible on the map, it is redrawn immediately.
+
+ If `range` extends beyond the shape’s `coordinates` property, an
+ `NSRangeException` is raised.
+
+ @param range The range of vertices to remove. The `location` field indicates
+ the first vertex you are removing, with `0` being the first vertex, `1`
+ being the second vertex, and so on. The `length` field indicates the number
+ of vertices to remove.
+ */
+- (void)removeCoordinatesInRange:(NSRange)range;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm
index 57b57889f3..c49e970c6b 100644
--- a/platform/darwin/src/MGLMultiPoint.mm
+++ b/platform/darwin/src/MGLMultiPoint.mm
@@ -2,19 +2,12 @@
#import "MGLGeometry_Private.h"
#import "MGLTypes.h"
-#import <mbgl/util/geo.hpp>
-
-mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor)
-{
- if (!cgColor) return { 0, 0, 0, 0 };
- NSCAssert(CGColorGetNumberOfComponents(cgColor) >= 4, @"Color must have at least 4 components");
- const CGFloat *components = CGColorGetComponents(cgColor);
- return { (float)components[0], (float)components[1], (float)components[2], (float)components[3] };
-}
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/optional.hpp>
@implementation MGLMultiPoint
{
- MGLCoordinateBounds _bounds;
+ mbgl::optional<mbgl::LatLngBounds> _bounds;
std::vector<CLLocationCoordinate2D> _coordinates;
}
@@ -24,9 +17,11 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor)
if (self)
{
- NSAssert(count > 0, @"A multipoint must have coordinates");
+ if (!count) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"A multipoint must have at least one vertex."];
+ }
_coordinates = { coords, coords + count };
- [self computeBounds];
}
return self;
@@ -65,52 +60,87 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor)
std::copy(_coordinates.begin() + range.location, _coordinates.begin() + NSMaxRange(range), coords);
}
-- (void)appendCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count
-{
+- (void)setCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count {
+ if (!count) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"A multipoint must have at least one vertex."];
+ }
+
+ [self willChangeValueForKey:@"coordinates"];
+ _coordinates = { coords, coords + count };
+ _bounds = {};
+ [self didChangeValueForKey:@"coordinates"];
+}
+
+- (void)insertCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count atIndex:(NSUInteger)index {
+ if (!count) {
+ return;
+ }
+
+ if (index > _coordinates.size()) {
+ [NSException raise:NSRangeException
+ format:@"Invalid index %lu for existing coordinate count %ld",
+ (unsigned long)index, (unsigned long)[self pointCount]];
+ }
+
[self willChangeValueForKey:@"coordinates"];
- _coordinates.insert(_coordinates.end(), count, *coords);
- [self computeBounds];
+ _coordinates.insert(_coordinates.begin() + index, count, *coords);
+ _bounds = {};
[self didChangeValueForKey:@"coordinates"];
}
+- (void)appendCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count
+{
+ [self insertCoordinates:coords count:count atIndex:_coordinates.size()];
+}
+
- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords
{
- if (range.length == 0)
- {
+ [self replaceCoordinatesInRange:range withCoordinates:coords count:range.length];
+}
+
+- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count {
+ if (!count && !range.length) {
return;
}
- if (NSMaxRange(range) > _coordinates.size())
- {
+ if (NSMaxRange(range) > _coordinates.size()) {
[NSException raise:NSRangeException
format:@"Invalid range %@ for existing coordinate count %ld",
NSStringFromRange(range), (unsigned long)[self pointCount]];
}
[self willChangeValueForKey:@"coordinates"];
- std::copy(coords, coords + range.length, _coordinates.begin() + range.location);
- [self computeBounds];
+ std::copy(coords, coords + MIN(count, range.length), _coordinates.begin() + range.location);
+ if (count >= range.length) {
+ _coordinates.insert(_coordinates.begin() + NSMaxRange(range), coords, coords + count - range.length);
+ } else {
+ _coordinates.erase(_coordinates.begin() + range.location + count, _coordinates.begin() + NSMaxRange(range));
+ }
+ _bounds = {};
[self didChangeValueForKey:@"coordinates"];
}
-- (void)computeBounds
-{
- mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
- for (auto coordinate : _coordinates)
- {
- bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude));
- }
- _bounds = MGLCoordinateBoundsFromLatLngBounds(bounds);
+- (void)removeCoordinatesInRange:(NSRange)range {
+ CLLocationCoordinate2D coords;
+ [self replaceCoordinatesInRange:range withCoordinates:&coords count:0];
}
- (MGLCoordinateBounds)overlayBounds
{
- return _bounds;
+ if (!_bounds) {
+ mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
+ for (auto coordinate : _coordinates) {
+ bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude));
+ }
+ _bounds = bounds;
+ }
+ return MGLCoordinateBoundsFromLatLngBounds(*_bounds);
}
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds
{
- return MGLLatLngBoundsFromCoordinateBounds(_bounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds));
+ return MGLCoordinateBoundsIntersectsCoordinateBounds(self.overlayBounds, overlayBounds);
}
- (mbgl::Annotation)annotationObjectWithDelegate:(__unused id <MGLMultiPointDelegate>)delegate
@@ -122,7 +152,8 @@ mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor)
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; count = %lu; bounds = %@>",
- NSStringFromClass([self class]), (void *)self, (unsigned long)[self pointCount], MGLStringFromCoordinateBounds(_bounds)];
+ NSStringFromClass([self class]), (void *)self, (unsigned long)[self pointCount],
+ MGLStringFromCoordinateBounds(self.overlayBounds)];
}
@end
diff --git a/platform/darwin/src/MGLOverlay.h b/platform/darwin/src/MGLOverlay.h
index 48d10d9de1..1066a86d1e 100644
--- a/platform/darwin/src/MGLOverlay.h
+++ b/platform/darwin/src/MGLOverlay.h
@@ -17,14 +17,6 @@ NS_ASSUME_NONNULL_BEGIN
example, you could use an overlay to show the boundaries of a national park or
trace a bus route along city streets. This SDK defines several concrete classes
that conform to this protocol and define standard shapes.
-
- Because overlays are also annotations, they have similar usage pattern to
- annotations. When added to a map view using the `-addOverlay:` method, that
- view detects whenever the overlay’s defined region intersects the visible
- portion of the map. At that point, the map view asks its delegate to provide a
- special overlay view to draw the visual representation of the overlay. If you
- add an overlay to a map view as an annotation instead, it is treated as an
- annotation with a single point.
*/
@protocol MGLOverlay <MGLAnnotation>
diff --git a/platform/darwin/src/MGLPointCollection.mm b/platform/darwin/src/MGLPointCollection.mm
index f2bde38bc7..46b00b9a4d 100644
--- a/platform/darwin/src/MGLPointCollection.mm
+++ b/platform/darwin/src/MGLPointCollection.mm
@@ -8,10 +8,12 @@ NS_ASSUME_NONNULL_BEGIN
@implementation MGLPointCollection
{
- MGLCoordinateBounds _bounds;
+ MGLCoordinateBounds _overlayBounds;
std::vector<CLLocationCoordinate2D> _coordinates;
}
+@synthesize overlayBounds = _overlayBounds;
+
+ (instancetype)pointCollectionWithCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count
{
return [[self alloc] initWithCoordinates:coords count:count];
@@ -28,7 +30,7 @@ NS_ASSUME_NONNULL_BEGIN
{
bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude));
}
- _bounds = MGLCoordinateBoundsFromLatLngBounds(bounds);
+ _overlayBounds = MGLCoordinateBoundsFromLatLngBounds(bounds);
}
return self;
}
@@ -61,14 +63,9 @@ NS_ASSUME_NONNULL_BEGIN
std::copy(_coordinates.begin() + range.location, _coordinates.begin() + NSMaxRange(range), coords);
}
-- (MGLCoordinateBounds)overlayBounds
-{
- return _bounds;
-}
-
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds
{
- return MGLLatLngBoundsFromCoordinateBounds(_bounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds));
+ return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
}
- (mbgl::Geometry<double>)geometryObject
diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm
index f4d999b98b..e5bb977863 100644
--- a/platform/darwin/src/MGLPolygon.mm
+++ b/platform/darwin/src/MGLPolygon.mm
@@ -99,7 +99,7 @@
}
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
- return MGLLatLngBoundsFromCoordinateBounds(_overlayBounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds));
+ return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
}
- (mbgl::Geometry<double>)geometryObject {
diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm
index 5b6346f46a..ae6abc5280 100644
--- a/platform/darwin/src/MGLPolyline.mm
+++ b/platform/darwin/src/MGLPolyline.mm
@@ -79,7 +79,7 @@
}
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
- return MGLLatLngBoundsFromCoordinateBounds(_overlayBounds).intersects(MGLLatLngBoundsFromCoordinateBounds(overlayBounds));
+ return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
}
- (mbgl::Geometry<double>)geometryObject {
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index 1248af0c17..894c33510a 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -46,7 +46,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
### Annotations
-* Added new methods to MGLMultiPoint for changing or appending vertices along polyline annotations and the exteriors of polygon annotations. ([#6565](https://github.com/mapbox/mapbox-gl-native/pull/6565))
+* Added new methods to MGLMultiPoint for changing the vertices along a polyline annotation or the exterior of a polygon annotation. ([#6565](https://github.com/mapbox/mapbox-gl-native/pull/6565))
* Added new APIs to MGLMapView to query for visible annotations. Combined with `-[MGLMapView viewForAnnotation:]`, these APIs can be used to access all visible annotation views. ([6061](https://github.com/mapbox/mapbox-gl-native/pull/6061))
* Fixed an issue causing offscreen annotation views to be updated even when they were in the reuse queue. ([#5987](https://github.com/mapbox/mapbox-gl-native/pull/5987))
* Fixed an issue preventing MGLAnnotationView from animating when its coordinate changes. ([#6215](https://github.com/mapbox/mapbox-gl-native/pull/6215))
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index 37e51d7c58..1d5aa93638 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -32,7 +32,7 @@
### Annotations
* Added `showAnnotations:animated:` and `showAnnotations:edgePadding:animated:`, which moves the map viewport to show the specified annotations. ([#5749](https://github.com/mapbox/mapbox-gl-native/pull/5749))
-* Added new methods to MGLMultiPoint for changing or appending vertices along polyline annotations and the exteriors of polygon annotations. ([#6565](https://github.com/mapbox/mapbox-gl-native/pull/6565))
+* Added new methods to MGLMultiPoint for changing the vertices along a polyline annotation or the exterior of a polygon annotation. ([#6565](https://github.com/mapbox/mapbox-gl-native/pull/6565))
* Added new APIs to MGLMapView to query for visible annotations. ([6061](https://github.com/mapbox/mapbox-gl-native/pull/6061))
* Deprecated `-[MGLMapViewDelegate mapView:alphaForShapeAnnotation:]` in favor of specifying an alpha component via `-[MGLMapViewDelegate mapView:strokeColorForShapeAnnotation:]` or `-[MGLMapViewDelegate mapView:fillColorForPolygonAnnotation:]`. ([#6706](https://github.com/mapbox/mapbox-gl-native/pull/6706))
* Various method arguments that are represented as C arrays of `CLLocationCoordinate2D` instances have been marked `const` to streamline bridging to Swift. ([#7215](https://github.com/mapbox/mapbox-gl-native/pull/7215))