在iOS7中,使用CGPathContainsPoint检测MKPolygon中的点出现问题

12
在今年早些时候我曾在一个SO问题中发表了这个代码块:
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
}

这个方法在iOS7之前运行良好。现在它总是返回false,并且无法检测到路径上的点。

我正在尝试查找任何说明该方法已更改的文档,但找不到任何信息。

有什么想法是为什么它出问题了吗?还是有一个新的解决方案吗?

4个回答

22

由于某种原因(可能是错误),在当前版本的iOS 7中,path属性返回NULL

一种解决方法是从多边形的points中构建自己的CGPathRef
使用这种方法,您不需要引用MKPolygonViewMKPolygonRenderer

例如:

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);

这个也适用于iOS 6。
但是,如果遮盖视图的path属性返回NULL,您可能只想进行手动构建。


仅作记录:在iOS 6中,如果MKPolygon不可见,则polygon.path属性将返回NULL。这个解决方案非常有效,非常感谢Anna女士! - Padin215
1
这个很好用。需要注意的是,“CGPoint mapPointAsCGP = CGPointMake(mapPoint.x, mapPoint.y);” 这一行非常关键;我的代码之前使用了“CGPoint polygonViewPoint = [overlayView pointForMapPoint:mapPoint];”,但在iOS7中似乎也有问题。 - sethpollack
1
@sethpollack:mapPointAsCGP只是为了避免编译器警告,因为您正在传递一个MKMapPoint,而需要的是CGPoint(它不会改变传递的值--它只是将它们放在CGPoint结构体中)。pointForMapPoint之所以在这里无法工作,是因为路径是使用MKMapPoint单位构建的,因此我们要测试的点也必须以MKMapPoint单位而不是实际屏幕CGPoint单位表示。 - user467105
如代码示例中所述:“//mapPoint above is the MKMapPoint of the coordinate we are testing.” 因此,您需要使用“MKMapPointForCoordinate”函数将注释的“coordinate”转换为“MKMapPoint”。所有“CG”内容仅因为我们正在使用核心图形功能(而不是实际的CGPoint)。 - user467105
@Anna- 谢谢你。这里戴着笨蛋帽子。我该如何将 MKMapPoint 强制转换为 CGPoint,以使 CGPathContainsPoint 测试能够正常运行 - 编译器报错? - CocoaEv
显示剩余3条评论

2
你的代码问题在于方法。
- (MKOverlayView *)viewForOverlay:(id < MKOverlay >)overlay

iOS 7中已停用(请参阅文档),您应该改用此选项:

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

因此,为了使您的代码在iOS 7中正常工作,您需要替换以下内容:
MKPolygonView *polygonView = (MKPolygonView *)[self.mapView viewForOverlay:polygon];

使用

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

这样做的问题是- rendererForOverlay:在iOS 7中是新的,所以这个改变会导致你的应用程序不能在之前的版本中运行。你可以实现两个版本的方法,并根据iOS版本调用其中一个。 我还没有与@Anna的解决方案进行性能分析比较

1
问题在于,在iOS 7中,MKPolygonView/MKPolygonRenderer的“path”属性返回null(即使使用rendererForOverlay)。 在您的经验中,调用rendererForOverlay后,MKPolygonRenderer中的“path”是否具有值? - user467105
是的,在我的情况下,除非将作为参数发送的“polygon”添加到地图视图中,否则使用“rendererForOverlay”路径返回一个非空值。 - tkanzakic

2
我遇到了同样的问题。在访问路径之前,在MKPolygonRenderer上调用invalidatePath来解决它。

1

它在7.1上直接工作,但在7.0上不行。

jdehlin的回复为我解决了7.0的问题,即在每次调用之前调用[view invalidatePath]

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接