I'm trying to make a MKMapView and add and overlay to it using coordinates.
It is not showing up in the mapView.
it seems to be compiling ok but when I open the mapView view in the storyboard I see the map of the world but there is no red overlay anywhere.
Here is my code.
my header
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreMotion/CoreMotion.h>
#import <MapKit/MapKit.h>
NS_ASSUME_NONNULL_BEGIN
#interface mapViewController : UIViewController<CLLocationManagerDelegate,MKMapViewDelegate>
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
#property(nonatomic, retain) MKPolygon *polygon;
#end
and my .m file
#import "mapViewController.h"
#interface mapViewController ()
#end
#implementation mapViewController
#synthesize mapView,locationManager,polygon;
- (void)viewDidLoad {
[super viewDidLoad];
mapView.delegate = self;
NSDictionary *d1=[NSDictionary dictionaryWithObjectsAndKeys:#"37.57111111",#"x",#"-109.52166667",#"y",nil];
NSDictionary *d2=[NSDictionary dictionaryWithObjectsAndKeys:#"32.01138889",#"x",#"-109.59000000",#"y",nil];
NSDictionary *d3=[NSDictionary dictionaryWithObjectsAndKeys:#"31.83166667",#"x",#"-111.95416667",#"y",nil];
NSDictionary *d4=[NSDictionary dictionaryWithObjectsAndKeys:#"32.34250000",#"x",#"-115.14333333",#"y",nil];
NSDictionary *d5=[NSDictionary dictionaryWithObjectsAndKeys:#"34.89722222",#"x",#"-115.47611111",#"y",nil];
NSDictionary *d6=[NSDictionary dictionaryWithObjectsAndKeys:#"37.32083333",#"x",#"-116.02027778",#"y",nil];
NSDictionary *d7=[NSDictionary dictionaryWithObjectsAndKeys:#"37.53305556",#"x",#"-114.73416667",#"y",nil];
NSDictionary *d8=[NSDictionary dictionaryWithObjectsAndKeys:#"37.53166667",#"x",#"-114.11277778",#"y",nil];
NSDictionary *d9=[NSDictionary dictionaryWithObjectsAndKeys:#"37.57111111",#"x",#"-109.52166667",#"y",nil];
NSArray *azcoord = [NSArray arrayWithObjects:d1,d2,d3,d4,d5,d6,d7,d8, nil];
CLLocationCoordinate2D coordinates[azcoord.count];
int coordinatesIndex = 0;
for (NSDictionary * c in azcoord) {
double x = [[c valueForKey:#"x"] doubleValue];
double y = [[c valueForKey:#"y"] doubleValue];
CLLocationCoordinate2D coordinate;
coordinate.latitude = y;
coordinate.longitude = x;
//Put this coordinate in the C array...
coordinates[coordinatesIndex] = coordinate;
coordinatesIndex++;
}
polygon = [MKPolygon polygonWithCoordinates:coordinates count:azcoord.count];
[self.mapView addOverlay:polygon];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
MKPolygonRenderer *renderer = [[MKPolygonRenderer alloc] initWithPolygon:polygon];
renderer.fillColor = [[UIColor redColor] colorWithAlphaComponent:1];
renderer.strokeColor = [[UIColor blackColor] colorWithAlphaComponent:0.7];
renderer.lineWidth = 2;
return renderer;
}
#end
what I am trying to do is draw an overlay for the state of Arizona. I've checked the coordinates and they are correct.
Eventually I want to create overlays for all states.
can anyone see where I'm going wrong?
I figured it out by changing my approach. Here is my code that is working.
first i create a CLLocationCoordinate2D array of my coordinates and make them into a polygon. then add to mapView.
CLLocationCoordinate2D points[7];
points [0] = CLLocationCoordinate2DMake(36.99910000, -109.04520000);
points [1] = CLLocationCoordinate2DMake(31.33460000, -109.05220000);
points [2] = CLLocationCoordinate2DMake(31.33700000, -111.07720000);
points [3] = CLLocationCoordinate2DMake(32.49410000, -114.81360000);
points [4] = CLLocationCoordinate2DMake(36.10660000, -114.75180000);
points [5] = CLLocationCoordinate2DMake(36.21600000, -114.03940000);
points [6] = CLLocationCoordinate2DMake(37.00150000, -114.04820000);
polygon = [MKPolygon polygonWithCoordinates:points count:7];
[self.mapView addOverlay:polygon];
then I render that to the map view.
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{ NSLog(#"YES!!!!!!!!!!!!!!!!!");
MKPolygonRenderer *renderer = [[MKPolygonRenderer alloc] initWithPolygon:polygon];
renderer.fillColor = [[UIColor redColor] colorWithAlphaComponent:0.2];
renderer.strokeColor = [[UIColor blackColor] colorWithAlphaComponent:0.7];
renderer.lineWidth = 1;
return renderer;
}
then I check to see if my location is inside the polygon.
CLLocationCoordinate2D sampleLocation = CLLocationCoordinate2DMake(myLatitude,myLongitude);//13,80 is the latlong of clear colored area of the MKPolygon in the below image.
MKMapPoint mapPoint = MKMapPointForCoordinate(sampleLocation);
CGPoint mapPointAsCGP = CGPointMake(mapPoint.x, mapPoint.y);
for (id<MKOverlay> polygon in mapView.overlays) {
if([polygon isKindOfClass:[MKPolygon class]]){
NSLog(#"YES<<<<<<<<<<<<<<<<<<");
MKPolygon *polygons = (MKPolygon*) polygon;
CGMutablePathRef mpr = CGPathCreateMutable();
MKMapPoint *polygonPoints = polygons.points;
for (int p=0; p < polygons.pointCount; p++){
MKMapPoint mp = polygonPoints[p];
if (p == 0)
CGPathMoveToPoint(mpr, NULL, mp.x, mp.y);
else
CGPathAddLineToPoint(mpr, NULL, mp.x, mp.y);
}
if(CGPathContainsPoint(mpr , NULL, mapPointAsCGP, TRUE)){
NSLog(#"YES?????????????????????????????????");
//do something else
}
CGPathRelease(mpr);
}
}
I at first didn't want to add a map view but then decided I need to and now that I have I like it.
Related
I'm struggling with a issue related to MapKit.
I create a list of MKPolygon based on my geofence's data from the server.
+ (MKPolygon *)polygonFromPoints:(NSArray *)points interiorPolygons:(NSArray *)polygons{
NSInteger numberOfCoordinates = [points count];
CLLocationCoordinate2D *polygonPoints = malloc(numberOfCoordinates * sizeof(CLLocationCoordinate2D));
NSInteger index = 0;
for (NSArray *pointArray in points) {
polygonPoints[index] = CLLocationCoordinate2DMake([pointArray[1] floatValue], [pointArray[0] floatValue]);
index++;
}
MKPolygon *polygon;
if (polygons) {
polygon = [MKPolygon polygonWithCoordinates:polygonPoints count:numberOfCoordinates interiorPolygons:polygons];
} else {
polygon = [MKPolygon polygonWithCoordinates:polygonPoints count:numberOfCoordinates];
}
free(polygonPoints);
return polygon; }
And add it to the map as MKOverlayRender
- (MKOverlayRenderer *) mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
if([overlay isKindOfClass: [MKCircle class]]){
MKCircleRenderer *circleRender = [[MKCircleRenderer alloc] initWithCircle:(MKCircle *)overlay];
circleRender.fillColor = [ [Common colorWithHexString:BlueGeoFence] colorWithAlphaComponent:0.3];
return circleRender;
}else if([overlay isKindOfClass: [MKPolygon class]]){
MKPolygonRenderer *polygonRenderer = [[MKPolygonRenderer alloc] initWithPolygon:(MKPolygon *)overlay];
polygonRenderer.fillColor = [ [Common colorWithHexString:BlueGeoFence] colorWithAlphaComponent:0.3];
return polygonRenderer;
}
return nil;
}
However, when i zoom in or change the map's position the overlays are cut and have some kind of blur effect.
Any idea how to solve this?
Thanks in advance
I was having the same issue. The source of the problem was that MKPolygon was being created with interior polygons that were not actually interior polygons. Check your data and ensure that your interior polygon coordinates are actually within the bounds of your larger polygon.
How can I find if the user zoomed in/out on my mapView (GMSMapView)?
I want to do that if the zoom is bigger than 14 all the markers on the map will disappear and if it's smaller all the markers will reload.
How can I do that?
Thanks!
The below code assumes that the view controller has a property of "markerArray" which holds all of the markers.
-(void)mapView:(GMSMapView *)mapView didChangeCameraPosition:(GMSCameraPosition*)position {
int zoom= mapView.camera.zoom;
if (zoom < 14) {
[mapView_ clear];
}
else{
[self displayAllMarkers];
}
}
-(void) displayAllMarkers{
for (BarObject *barMarker in markerArray){
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = barMarker.location; //
marker.icon = [GMSMarker markerImageWithColor:[UIColor blackColor]];
marker.map = mapView_;
}
}
I also searched for this answer over the summer, and here is what I found and ended up doing:
Create a category on MKMapView:
I named it MKMapView+ZoomLevel
.h
// MKMapView+ZoomLevel.h
#import <MapKit/MapKit.h>
#interface MKMapView (ZoomLevel)
- (int)currentZoomLevel;
#end
.m
// MKMapView+ZoomLevel.m
#import "MKMapView+ZoomLevel.h"
#define MERCATOR_OFFSET 268435456
#define MERCATOR_RADIUS 85445659.44705395
#define MAX_GOOGLE_LEVELS 20
#implementation MKMapView (ZoomLevel)
- (int)currentZoomLevel
{
CLLocationDegrees longitudeDelta = self.region.span.longitudeDelta;
CGFloat mapWidthInPixels = self.bounds.size.width*2;//2 is for retina display
double zoomScale = longitudeDelta * MERCATOR_RADIUS * M_PI / (180.0 * mapWidthInPixels);
double zoomer = MAX_GOOGLE_LEVELS - log2( zoomScale );
if ( zoomer < 0 ) zoomer = 0;
zoomer = round(zoomer);
return (int)zoomer;
}
#end
Then in your view controller:
#import "MKMapView+ZoomLevel.h
// insert logic here
double zoomLevel = [self.mapView currentZoomLevel];
if (zoomLevel > 14 ) {
// add code to hide or resize your annotations
for (id<MKAnnotation> annotation in self.mapView.annotations) {
if (![annotation isKindOfClass:[MKUserLocation class]]) {
[self.mapView removeAnnotation:annotation];
}
}
}
I'm new to iOS programming. I am trying to draw one line between two points not more than one line. This is what I tried so far;
#property (nonatomic, strong) MKPolylineView *lineView;
#property (nonatomic, strong) MKPolyline *line;
Create a polyline all location ;
-(void)allLocationRoute {
CLLocationCoordinate2D coordinates[record.toMoments.count];
int i = 0;
for (MomentEntity *currentEntity in record.toMoments.allObjects) {
coordinates[i].latitude = [currentEntity.latitude doubleValue];
coordinates[i].longitude = [currentEntity.longitude doubleValue];
i++;
}
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coordinates count:record.toMoments.allObjects.count];
[self.mapView addOverlay:polyline];
line = polyline;
}
MapView:
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id)overlay {
if ([overlay isKindOfClass:[MKPolyline class]]) {
self.lineView = [[MKPolylineView alloc]initWithPolyline:(MKPolyline*)overlay] ;
self.lineView.strokeColor = [[UIColor redColor] colorWithAlphaComponent:1];
self.lineView.lineWidth = 1;
return self.lineView;
}
return nil;
}
But as you can see from first picture red line makes zig-zag. Any help appreciated.
My app tracks GPS movement as a MKPolyline routepath on a MKMapView as an MKOverlayRenderer in the HomeVC, saves the data, and displays it later, as a saved routepath a few VCs deeper, on DisplayVC. I can confirm that the data is identical to the original data on the second VC, and the proper routeBounds are used when the map is shown, but the OverlayRenderer is never called on the second VC. Why not? I'm thinking delegate problems, but I can't find anything wrong.
Both homeVC.h
#interface homeVC : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate> {
and displayVC.h are the same, except for the name:
#interface displayVC : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate> {
CLLocationManager *locationManager;
// the data representing the route points
MKPolyline* _routePath;
// the view we create for the line on the map
MKPolylineView* _routePathVw;
// the rect that bounds the loaded points
MKMapRect _routeBounds;
}
#property (nonatomic, weak) IBOutlet MKMapView *mapView;
#end
And both homeVC.m and displayVC.m are set up the same:
- (void)viewDidLoad {
[super viewDidLoad];
// Add the Map
[_mapView setDelegate:self];
_mapView.mapType = MKMapTypeStandard;
}
Lots of good-working code here. Then,
-(void) buildRoute {
CLLocationCoordinate2D thisCoord;
int i = [arrayLa count] - 1; // keep growing the array size
MKMapPoint *tmpArr = realloc(pointArr, sizeof(CLLocationCoordinate2D)*(arrayLa.count));
pointArr = tmpArr;
thisCoord.latitude = [[arrayLa objectAtIndex:i] floatValue];
thisCoord.longitude = [[arrayLo objectAtIndex:i] floatValue];
MKMapPoint point = MKMapPointForCoordinate(thisCoord);
pointArr[i] = point;
// Reset Map View Boundaries
if( point.x > ne_Pt.x - 500 ) ne_Pt.x = point.x + 1000;
if( point.y > ne_Pt.y - 500 ) ne_Pt.y = point.y + 1000;
if( point.x < sw_Pt.x + 500 ) sw_Pt.x = point.x - 1000;
if( point.y < sw_Pt.y + 500 ) sw_Pt.y = point.y - 1000;
// create the polyline based on the C-array of map Points
_routePath = [MKPolyline polylineWithPoints:pointArr count:arrayLa.count];
_routeBounds = MKMapRectMake(sw_Pt.x, sw_Pt.y, ne_Pt.x-sw_Pt.x, ne_Pt.y-sw_Pt.y);
// add the routePath overlay to the map, if it isn't empty
if (recState == REC && _routePath != nil) {
// zoom in on the route with the fresh bounding box, routeBounds
[self zoomInOnRoute];
[_mapView addOverlay:_routePath];
}
}
-(void) zoomInOnRoute {
[_mapView setVisibleMapRect:_routeBounds];
}
#pragma mark MKMapViewDelegate
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolyline *route = overlay;
MKPolylineRenderer *routeRenderer = [[MKPolylineRenderer alloc] initWithPolyline:route];
routeRenderer.lineWidth = 3;
routeRenderer.strokeColor = [UIColor redColor];
return routeRenderer;
}
else return nil;
}
Can anyone help solve my problem?
Thanks!
It does look like a delegate issue. Have you tried putting a breakpoint on the addOverLay call just in case the 'if' is skipping it?
I do something similar and all works fine using MKOverlay and MKOverlayRender (based on the apple Breadcrumbs sample app but updated). The app displays a route that the user can save to CoreData. They can select from a table of saved routes and the route is rendered using MKOverlayRenderer.
Set the delegate
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.mapView setDelegate:self];
}
Create a MKOverlay and add to mapView
- (void)createRoute2
{
// Some CoreData stuff. Iterate through map points and create an overlay.
// Order by date ascending so we draw in sequential order
NSSortDescriptor *timeStampDescriptor = [[NSSortDescriptor alloc] initWithKey:#"pointDate" ascending:YES];
NSArray *sortDescriptors = #[timeStampDescriptor];
NSArray *routePts = [[self.selectedRoute mapDetail] sortedArrayUsingDescriptors:sortDescriptors];
// A long is a bit excessive just use an int is fine ( BUT might be a huge number of route points)
long nbrPts = routePts.count;
if (nbrPts < 2){
return;
}
CLLocationCoordinate2D mapPointLoc;
MKMapRect updateRect; // The map area
// Init the route
// FtfmapDetail is a managed object holding lat long (and other stuff)
FtfMapDetail *currentPt = (FtfMapDetail *)[routePts objectAtIndex:0];
mapPointLoc = CLLocationCoordinate2DMake([currentPt.latitude floatValue], [currentPt.longitude floatValue]);
// self.route is a subclassed MapOverlay
if (!self.route)
{
// BGSMapOverlay is a subclassed MapOverlay
self.route = [[BGSMapOverlay alloc] initWithCenterCoordinate:mapPointLoc];
[self.mapView addOverlay:self.route];
}
// Add subsequent points. Kick off the for loop at int position 1 not 0
for (int i=1; i <nbrPts; i++){
currentPt = (FtfMapDetail *)[routePts objectAtIndex:i];
mapPointLoc = CLLocationCoordinate2DMake([currentPt.latitude floatValue], [currentPt.longitude floatValue]);
// AddCoordinate is a method in MKOverlay subclass that returns a bounding MKMaprect for all points in MkOverlay
updateRect = [self.route addCoordinate:mapPointLoc];
}
MKCoordinateRegion region = MKCoordinateRegionForMapRect(self.route.boundingMapRectCompleteRoute);
[self.mapView setRegion:region animated:YES];
}
And make sure you add the delegate method
#pragma mark - MKMapView delegate
// self.routeViewRenderer is a sub-classed MKOverlayRendered (based on the Breadcrumbs app from apple CrumbPathView subclassed MKOverlayView)
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
if (!self.routeViewRenderer)
{
_routeViewRenderer = [[BGSMKOverlayRender alloc] initWithOverlay:overlay];
}
return self.routeViewRenderer;
}
Or it could be that you are not sending any coordinates to the MkPolyLine. In the following snippet if I uncomment the "NSArray *routeCoordinates = [[NSArray alloc]init];" to send a Nil array to the MKPolyLine then the code will run but the delegate doesn't get called. If routeCoordinates contains points then delegate is called and route displayed.
-(void)buildRouteOverlays
{
for (int i=0; i< _routeHeaders.count;i++)
{
_selectedRoute = (FtfMaps*) [_routeHeaders objectAtIndex:i];
NSLog(#"DEBUG route date : %#", _selectedRoute.dateMap);
NSArray *routeCoordinates = [self arrayRoutePointCoordinates];
// if a nil array is produce then MapOverlayRenerder is not called - nothing to render
// Test this by uncommenting:
// NSArray *routeCoordinates = [[NSArray alloc]init];
NSLog(#"DEBUG number of point in Route : %lu",(unsigned long)routeCoordinates.count);
// Just a quick test only process the first route
if (i==0){
MKPolyline *routePolyLine = [self polyLineFromArray:routeCoordinates];
[self.mapView addOverlay:routePolyLine];
}
}
}
-(MKPolyline*)polyLineFromArray:(NSArray*)routePoints
{
NSInteger pointsCount = routePoints.count;
CLLocationCoordinate2D pointsToUse[pointsCount];
for(int i = 0; i < pointsCount; i++) {
FtfMapDetail *mapPt = (FtfMapDetail *) [routePoints objectAtIndex:i];
pointsToUse[i] = CLLocationCoordinate2DMake([mapPt.latitude doubleValue], [mapPt.longitude doubleValue]);
}
MKPolyline *myPolyline = [MKPolyline polylineWithCoordinates:pointsToUse count:pointsCount];
return myPolyline;
}
#pragma mark MKMapViewDelegate
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolyline *route = overlay;
MKPolylineRenderer *routeRenderer = [[MKPolylineRenderer alloc] initWithPolyline:route];
routeRenderer.lineWidth = 3;
routeRenderer.strokeColor = [UIColor redColor];
return routeRenderer;
}
else return nil;
}
I want to do overlays on an MKMapView. So I created my custom object:
#interface Spot : NSObject
#property int spot_id;
#property CLLocationCoordinate2D coordinate;
#property float radius;
#property NSObject<MKOverlay> * overlay;
- (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(float)radius;
#end
There is a backend, that constantly updates the Spots and delivers them to the phone. So I have to:
Check if the currently rendered spots are still valid and there
If yes, have they moved or changed radius? If so, update them (move? / delete + redraw?!)
Delete if they don't exist anymore.
Is there a better way of keeping track of the overlays? Keeping an NSObject<MKoverlay> * reference attached to each spot and constantly reassigning it feels a bit strange to me.
It seems like there are three questions here:
How to detect changes in spots in your server?
The ugly way to do this would be iterate through your spots and see if the coordinate and/or radius changed. A little better would be to have the server update create, modify, and delete timestamps or some other identifier so the client would have the ability to retrieve all creations, modifications, and/or deletions since the last update. Best would be to marry that with some form of push notification, so the client would also be proactively notified of these changes.
This question is difficult to answer in the abstract. It depends a lot upon the capabilities of your server and the nature of the database (e.g. how many "spots", how frequently do they change, etc.). This impacts both the client-server architecture, but also the client implementation.
How to update the map when a spot changes?
This is a far easier question. Insertions and deletions are easy. You just do addOverlay: (or, in iOS 7, addOverlay:level: and removeOverlay:. For updates, while it's inelegant, I think the easiest way is to just remove the old overlay and add it back in and viewForOverlay will take care of the user interface for you.
What is the right structure of the Spot class?
Just as a thought, but it seems duplicative to have your coordinate and radius properties, and then have a id<MKOverlay> overlay object too (because that's presumably a MKCircle with the same two properties). If your overlays are going to be MKCircle objects, it might be easier to just have a Spot class, itself, to conform to MKOverlay:
#interface Spot : NSObject <MKOverlay>
#property (nonatomic) int spot_id;
#property (nonatomic) CLLocationCoordinate2D coordinate;
#property (nonatomic) CLLocationDistance radius;
#property (nonatomic, readonly) MKMapRect boundingMapRect;
- (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDistance)radius;
#end
Then, all you need to do is to implement boundingMapRect and intersectsMapRect:
- (MKMapRect) boundingMapRect
{
MKMapPoint point = MKMapPointForCoordinate(self.coordinate);
CLLocationDistance distance = self.radius * MKMetersPerMapPointAtLatitude(self.coordinate.latitude);
MKMapRect rect = MKMapRectMake(point.x, point.y, distance * 2.0, distance * 2.0);
rect = MKMapRectOffset(rect, -distance, -distance);
return rect;
}
- (BOOL)intersectsMapRect:(MKMapRect)mapRect
{
return MKMapRectIntersectsRect(mapRect, [self boundingMapRect]);
}
You might want to double-check that boundingMapRect logic, but I think it's right.
Then you can just add and remove Spot objects as overlays themselves. And all you need to do is to implement a viewForOverlay in your MKMapViewDelegate, for example, in iOS versions prior to 7, that would be:
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
if ([overlay isKindOfClass:[Spot class]])
{
Spot *spot = (id)overlay;
MKCircle *circle = [MKCircle circleWithCenterCoordinate:spot.coordinate
radius:spot.radius];
MKCircleView *overlayView = [[MKCircleView alloc] initWithCircle:circle];
overlayView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
overlayView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
overlayView.lineWidth = 3.0;
return overlayView;
}
return nil;
}
In iOS 7, that would be:
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
if ([overlay isKindOfClass:[Spot class]])
{
Spot *spot = (id)overlay;
MKCircle *circle = [MKCircle circleWithCenterCoordinate:spot.coordinate
radius:spot.radius];
MKCircleRenderer *renderer = [[MKCircleRenderer alloc] initWithCircle:circle];
renderer.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
renderer.lineWidth = 3;
return renderer;
}
return nil;
}
Another approach would be to define your Spot as:
#interface Spot : NSObject <MKOverlay>
#property (nonatomic) int spot_id;
#property (nonatomic, strong) MKCircle *overlay;
- (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDistance)radius;
And you could then just define boundingMapRect and coordinate return the appropriate values from the MKCircle (saving you from having to write your own):
- (MKMapRect)boundingMapRect
{
return [self.circle boundingMapRect];
}
- (CLLocationCoordinate2D)coordinate
{
return [self.circle coordinate];
}
Clearly the init method would change:
- (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDistance)radius;
{
self = [super init];
if (self) {
_spot_id = spot_id;
_circle = [MKCircle circleWithCenterCoordinate:coordinate radius:radius];
}
return self;
}
As would the viewForOverlay (iOS versions prior to 7.0) in the MKMapViewDelegate:
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
if ([overlay isKindOfClass:[SpotCircle class]])
{
SpotCircle *spot = (id)overlay;
MKCircleView *overlayView = [[MKCircleView alloc] initWithCircle:spot.circle];
overlayView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
overlayView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
overlayView.lineWidth = 3.0;
return overlayView;
}
return nil;
}
In iOS 7, that would be:
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
if ([overlay isKindOfClass:[SpotCircle class]])
{
SpotCircle *spot = (id)overlay;
MKCircleRenderer *renderer = [[MKCircleRenderer alloc] initWithCircle:spot.circle];
renderer.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
renderer.lineWidth = 3;
return renderer;
}
return nil;
}
I hope that helps.