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?

Answers


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)

Need Your Help

R knitr: Possible to programmatically modify chunk labels?

r knitr

I'm trying to use knitr to generate a report that performs the same set of analyses on different subsets of a data set. The project contains two Rmd files: the first file is a master document that ...

Ruby Inspect readability?

ruby

Is there a way to make the output of inspect more readable?