#import "MGLPolygon.h" #import "MGLMultiPoint_Private.h" #import "MGLGeometry_Private.h" #import "MGLPolygon+MGLAdditions.h" #import #import @implementation MGLPolygon @dynamic overlayBounds; + (instancetype)polygonWithCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count { return [self polygonWithCoordinates:coords count:count interiorPolygons:nil]; } + (instancetype)polygonWithCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count interiorPolygons:(NSArray *)interiorPolygons { return [[self alloc] initWithCoordinates:coords count:count interiorPolygons:interiorPolygons]; } - (instancetype)initWithCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count interiorPolygons:(NSArray *)interiorPolygons { if (self = [super initWithCoordinates:coords count:count]) { if (interiorPolygons.count) { _interiorPolygons = interiorPolygons; } } return self; } - (instancetype)initWithCoder:(NSCoder *)decoder { self = [super initWithCoder:decoder]; if (self) { _interiorPolygons = [decoder decodeObjectOfClass:[NSArray class] forKey:@"interiorPolygons"]; } return self; } - (void)encodeWithCoder:(NSCoder *)coder { [super encodeWithCoder:coder]; [coder encodeObject:self.interiorPolygons forKey:@"interiorPolygons"]; } - (BOOL)isEqual:(id)other { if (self == other) return YES; if (![other isKindOfClass:[MGLPolygon class]]) return NO; MGLPolygon *otherPolygon = (MGLPolygon *)other; return ([super isEqual:otherPolygon] && [[self geoJSONDictionary] isEqualToDictionary:[otherPolygon geoJSONDictionary]]); } - (NSUInteger)hash { return [super hash] + [[self geoJSONDictionary] hash]; } - (CLLocationCoordinate2D)coordinate { // pole of inaccessibility auto poi = mapbox::polylabel([self polygon]); return MGLLocationCoordinate2DFromPoint(poi); } - (mbgl::LinearRing)ring { NSUInteger count = self.pointCount; CLLocationCoordinate2D *coordinates = self.coordinates; mbgl::LinearRing result; result.reserve(self.pointCount); for (NSUInteger i = 0; i < count; i++) { result.push_back(mbgl::Point(coordinates[i].longitude, coordinates[i].latitude)); } return result; } - (mbgl::Polygon)polygon { mbgl::Polygon geometry; geometry.push_back(self.ring); for (MGLPolygon *polygon in self.interiorPolygons) { geometry.push_back(polygon.ring); } return geometry; } - (mbgl::Geometry)geometryObject { return [self polygon]; } - (mbgl::Annotation)annotationObjectWithDelegate:(id )delegate { mbgl::FillAnnotation annotation { [self polygon] }; annotation.opacity = { static_cast([delegate alphaForShapeAnnotation:self]) }; annotation.outlineColor = { [delegate strokeColorForShapeAnnotation:self] }; annotation.color = { [delegate fillColorForPolygonAnnotation:self] }; return annotation; } - (NSDictionary *)geoJSONDictionary { return @{@"type": @"Polygon", @"coordinates": self.mgl_coordinates}; } @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; } - (instancetype)initWithCoder:(NSCoder *)decoder { if (self = [super initWithCoder:decoder]) { _polygons = [decoder decodeObjectOfClass:[NSArray class] forKey:@"polygons"]; } return self; } - (void)encodeWithCoder:(NSCoder *)coder { [super encodeWithCoder:coder]; [coder encodeObject:_polygons forKey:@"polygons"]; } - (BOOL)isEqual:(id)other { if (self == other) return YES; if (![other isKindOfClass:[MGLMultiPolygon class]]) return NO; MGLMultiPolygon *otherMultiPolygon = other; return [super isEqual:other] && [self.polygons isEqualToArray:otherMultiPolygon.polygons]; } - (NSUInteger)hash { NSUInteger hash = [super hash]; for (MGLPolygon *polygon in self.polygons) { hash += [polygon hash]; } return hash; } - (CLLocationCoordinate2D)coordinate { MGLPolygon *firstPolygon = self.polygons.firstObject; return firstPolygon.coordinate; } - (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds { return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds); } - (mbgl::MultiPolygon)multiPolygon { mbgl::MultiPolygon multiPolygon; multiPolygon.reserve(self.polygons.count); for (MGLPolygon *polygon in self.polygons) { mbgl::Polygon geometry; geometry.push_back(polygon.ring); for (MGLPolygon *interiorPolygon in polygon.interiorPolygons) { geometry.push_back(interiorPolygon.ring); } multiPolygon.push_back(geometry); } return multiPolygon; } - (mbgl::Geometry)geometryObject { return [self multiPolygon]; } - (NSDictionary *)geoJSONDictionary { NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.polygons.count]; for (MGLPolygonFeature *feature in self.polygons) { [coordinates addObject: feature.mgl_coordinates]; } return @{@"type": @"MultiPolygon", @"coordinates": coordinates}; } @end