Detecting a point in a MKPolygon broke with iOS7 (CGPathContainsPoint)

In a SO question I asked earlier this year, I got this chunk of code:

MKPolygonView *polygonView = (MKPolygonView *)[self.mapView viewForOverlay:polygon];
MKMapPoint mapPoint = MKMapPointForCoordinate(tapCoord);
CGPoint polygonViewPoint = [polygonView pointForMapPoint:mapPoint];

if (CGPathContainsPoint(polygonView.path, NULL, polygonViewPoint, FALSE)) {
    // do stuff
}

This works great up until iOS7. It now always returns false and will not detect a point with the path.

I'm trying to find any documentation stating that the method change, but can't find any.

Any ideas why it broke? Or a new solution?


For some reason (possibly a bug), the path property returns NULL in the current release of iOS 7.

A workaround is to construct your own CGPathRef from the points of the polygon.
With this method, you don't need a reference to the MKPolygonView or the MKPolygonRenderer.

For example:

CGMutablePathRef mpr = CGPathCreateMutable();

MKMapPoint *polygonPoints = myPolygon.points;
//myPolygon is the MKPolygon

for (int p=0; p < myPolygon.pointCount; p++)
{
    MKMapPoint mp = polygonPoints[p];
    if (p == 0)
        CGPathMoveToPoint(mpr, NULL, mp.x, mp.y);
    else
        CGPathAddLineToPoint(mpr, NULL, mp.x, mp.y);
}

CGPoint mapPointAsCGP = CGPointMake(mapPoint.x, mapPoint.y);
//mapPoint above is the MKMapPoint of the coordinate we are testing.
//Putting it in a CGPoint because that's what CGPathContainsPoint wants.

BOOL pointIsInPolygon = CGPathContainsPoint(mpr, NULL, mapPointAsCGP, FALSE);

CGPathRelease(mpr);

This should work on iOS 6 as well.
However, you may want to do this manual construction only if the overlay view's path property returns NULL.


I was having the same issue. Solved it by calling invalidatePath on the MKPolygonRenderer before access the Path.


The issue with your code is that the method

- (MKOverlayView *)viewForOverlay:(id < MKOverlay >)overlay

has been deprecated in iOS 7 (See the doc), you should use this instead:

- (MKOverlayRenderer *)rendererForOverlay:(id < MKOverlay >)overlay

So, in order to make your code work properly in iOS 7 you have to replace:

MKPolygonView *polygonView = (MKPolygonView *)[self.mapView viewForOverlay:polygon];

with

MKPolygonRenderer *polygonView = (MKPolygonRenderer *)[self.mapView rendererForOverlay:polygon];

The problem with this is that - rendererForOverlay: is new in iOS 7, so this change make that your application do not run in previous versions. You can implement two version of the method and make call one or the other depending on the iOS version.

I haven't profile the performance of this in comparison with the @Anna solution


It's working straight on 7.1 but not on 7.0.

jdehlin response fixed the problem for me with 7.0, ie. calling [view invalidatePath] before each call to

CGPathContainsPoint(polygonView.path, NULL, polygonViewPoint, FALSE)