diff --git a/platform/darwin/src/MGLMultiPoint.h b/platform/darwin/src/MGLMultiPoint.h index 69c72958427..5a37e25cc3f 100644 --- a/platform/darwin/src/MGLMultiPoint.h +++ b/platform/darwin/src/MGLMultiPoint.h @@ -48,17 +48,26 @@ NS_ASSUME_NONNULL_BEGIN cause the shape to be redrawn if it is currently visible on the map. @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. You can append to an existing array of coordinates - by specifying a range with a `location` at the end of the existing array - and/or a `length` which extends past the end of the existing array. The array - in _`coords`_ must be equal in number to the length of the range. + 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 object. */ - (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(CLLocationCoordinate2D *)coords; +/** + 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. + + @param coords The array of coordinates to add to the shape. The data in this + array is copied to the new object. + @param count The number of items in the `coords` array. + */ +- (void)appendCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count; + @end NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm index 17a61ed0816..66ce27614a8 100644 --- a/platform/darwin/src/MGLMultiPoint.mm +++ b/platform/darwin/src/MGLMultiPoint.mm @@ -14,8 +14,8 @@ @implementation MGLMultiPoint { - size_t _count; MGLCoordinateBounds _bounds; + std::vector _coordinates; } - (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count @@ -24,45 +24,23 @@ - (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUI if (self) { - [self setupWithCoordinates:coords count:count]; + NSAssert(count > 0, @"A multipoint must have coordinates"); + _coordinates = { coords, coords + count }; + [self computeBounds]; } return self; } -- (void)setupWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count -{ - if (_coordinates) free(_coordinates); - - _count = count; - _coordinates = (CLLocationCoordinate2D *)malloc(_count * sizeof(CLLocationCoordinate2D)); - - mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty(); - - for (NSUInteger i = 0; i < _count; i++) - { - _coordinates[i] = coords[i]; - bounds.extend(mbgl::LatLng(coords[i].latitude, coords[i].longitude)); - } - - _bounds = MGLCoordinateBoundsFromLatLngBounds(bounds); -} - -- (void)dealloc -{ - free(_coordinates); -} - - (CLLocationCoordinate2D)coordinate { - assert(_count > 0); - - return CLLocationCoordinate2DMake(_coordinates[0].latitude, _coordinates[0].longitude); + NSAssert([self pointCount] > 0, @"A multipoint must have coordinates"); + return _coordinates.at(0); } - (NSUInteger)pointCount { - return _count; + return _coordinates.size(); } + (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingPointCount @@ -70,59 +48,59 @@ - (NSUInteger)pointCount return [NSSet setWithObjects:@"coordinates", nil]; } +- (CLLocationCoordinate2D *)coordinates +{ + return _coordinates.data(); +} + - (void)getCoordinates:(CLLocationCoordinate2D *)coords range:(NSRange)range { - if (range.location + range.length > _count) + if (range.location + range.length > [self pointCount]) { [NSException raise:NSRangeException format:@"Invalid coordinate range %@ extends beyond current coordinate count of %zu", - NSStringFromRange(range), _count]; + NSStringFromRange(range), [self pointCount]]; } - NSUInteger index = 0; + std::copy(_coordinates.begin() + range.location, _coordinates.begin() + NSMaxRange(range), coords); +} - for (NSUInteger i = range.location; i < range.location + range.length; i++) - { - coords[index] = _coordinates[i]; - index++; - } +- (void)appendCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count +{ + [self willChangeValueForKey:@"coordinates"]; + _coordinates.insert(_coordinates.end(), count, *coords); + [self computeBounds]; + [self didChangeValueForKey:@"coordinates"]; } - (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(CLLocationCoordinate2D *)coords { - if ((coords >= _coordinates && coords < _coordinates + _count) || - (coords + range.length >= _coordinates && coords + range.length < _coordinates + _count)) - { - [NSException raise:NSRangeException format:@"Reuse of existing coordinates array %p not supported", coords]; - } - else if (range.length == 0) + if (range.length == 0) { - [NSException raise:NSRangeException format:@"Empty coordinate range %@", NSStringFromRange(range)]; + return; } - else if (range.location > _count) + + if (NSMaxRange(range) > _coordinates.size()) { [NSException raise:NSRangeException format:@"Invalid range %@ for existing coordinate count %zu", - NSStringFromRange(range), _count]; + NSStringFromRange(range), [self pointCount]]; } [self willChangeValueForKey:@"coordinates"]; - if (NSMaxRange(range) <= _count) - { - // replacing existing coordinate(s) - memcpy(_coordinates + range.location, coords, range.length * sizeof(CLLocationCoordinate2D)); - } - else + std::copy(coords, coords + range.length, _coordinates.begin() + range.location); + [self computeBounds]; + [self didChangeValueForKey:@"coordinates"]; +} + +- (void)computeBounds +{ + mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty(); + for (auto coordinate : _coordinates) { - // appending new coordinate(s) - NSUInteger newCount = NSMaxRange(range); - CLLocationCoordinate2D *newCoordinates = (CLLocationCoordinate2D *)malloc(newCount * sizeof(CLLocationCoordinate2D)); - memcpy(newCoordinates, _coordinates, fmin(_count, range.location) * sizeof(CLLocationCoordinate2D)); - memcpy(newCoordinates + range.location, coords, range.length * sizeof(CLLocationCoordinate2D)); - [self setupWithCoordinates:newCoordinates count:newCount]; - free(newCoordinates); + bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude)); } - [self didChangeValueForKey:@"coordinates"]; + _bounds = MGLCoordinateBoundsFromLatLngBounds(bounds); } - (MGLCoordinateBounds)overlayBounds @@ -144,7 +122,7 @@ - (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p; count = %lu; bounds = %@>", - NSStringFromClass([self class]), (void *)self, (unsigned long)_count, MGLStringFromCoordinateBounds(_bounds)]; + NSStringFromClass([self class]), (void *)self, (unsigned long)[self pointCount], MGLStringFromCoordinateBounds(_bounds)]; } @end diff --git a/platform/darwin/src/MGLPointCollection.mm b/platform/darwin/src/MGLPointCollection.mm index 5871915b5d8..adf3cc3d409 100644 --- a/platform/darwin/src/MGLPointCollection.mm +++ b/platform/darwin/src/MGLPointCollection.mm @@ -8,8 +8,8 @@ @implementation MGLPointCollection { - size_t _count; MGLCoordinateBounds _bounds; + std::vector _coordinates; } + (instancetype)pointCollectionWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count @@ -22,17 +22,12 @@ - (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUI self = [super init]; if (self) { - _count = count; - _coordinates = (CLLocationCoordinate2D *)malloc(_count * sizeof(CLLocationCoordinate2D)); - + _coordinates = { coords, coords + count }; mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty(); - - for (NSUInteger i = 0; i < count; i++) + for (auto coordinate : _coordinates) { - _coordinates[i] = coords[i]; - bounds.extend(mbgl::LatLng(coords[i].latitude, coords[i].longitude)); + bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude)); } - _bounds = MGLCoordinateBoundsFromLatLngBounds(bounds); } return self; @@ -40,32 +35,30 @@ - (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUI - (NSUInteger)pointCount { - return _count; + return _coordinates.size(); +} + +- (CLLocationCoordinate2D *)coordinates +{ + return _coordinates.data(); } - (CLLocationCoordinate2D)coordinate { - assert(_count > 0); - - return CLLocationCoordinate2DMake(_coordinates[0].latitude, _coordinates[0].longitude); + NSAssert([self pointCount] > 0, @"A multipoint must have coordinates"); + return _coordinates.at(0); } - (void)getCoordinates:(CLLocationCoordinate2D *)coords range:(NSRange)range { - if (range.location + range.length > _count) + if (range.location + range.length > [self pointCount]) { [NSException raise:NSRangeException format:@"Invalid coordinate range %@ extends beyond current coordinate count of %zu", - NSStringFromRange(range), _count]; - } - - NSUInteger index = 0; - - for (NSUInteger i = range.location; i < range.location + range.length; i++) - { - coords[index] = _coordinates[i]; - index++; + NSStringFromRange(range), [self pointCount]]; } + + std::copy(_coordinates.begin() + range.location, _coordinates.begin() + NSMaxRange(range), coords); } - (MGLCoordinateBounds)overlayBounds @@ -104,7 +97,7 @@ - (NSDictionary *)geoJSONDictionary - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p; count = %lu>", - NSStringFromClass([self class]), (void *)self, (unsigned long)_count]; + NSStringFromClass([self class]), (void *)self, (unsigned long)[self pointCount]]; } @end