检测一个点是否在MKPolygon覆盖内

我想能够知道是否在一个MKPolygon内水龙头。

我有一个MKPolygon:

CLLocationCoordinate2D points[4]; points[0] = CLLocationCoordinate2DMake(41.000512, -109.050116); points[1] = CLLocationCoordinate2DMake(41.002371, -102.052066); points[2] = CLLocationCoordinate2DMake(36.993076, -102.041981); points[3] = CLLocationCoordinate2DMake(36.99892, -109.045267); MKPolygon* poly = [MKPolygon polygonWithCoordinates:points count:4]; [self.mapView addOverlay:poly]; //create UIGestureRecognizer to detect a tap UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(foundTap:)]; tapRecognizer.numberOfTapsRequired = 1; tapRecognizer.numberOfTouchesRequired = 1; [self.mapView addGestureRecognizer:tapRecognizer]; 

它只是科罗拉多州的基本轮廓。

我得到了龙头/长转换设置:

 -(IBAction)foundTap:(UITapGestureRecognizer *)recognizer { CGPoint point = [recognizer locationInView:self.mapView]; CLLocationCoordinate2D tapPoint = [self.mapView convertPoint:point toCoordinateFromView:self.view]; } 

但我不确定如何技术,如果我的抽头点是在MKPolygon。 似乎没有做这个检查的方法,所以我猜我需要将MKPolygon转换为CGRect并使用CGRectContainsPoint。

MKPolygon有一个.points的属性,但我似乎无法让他们退出。

有什么build议么?

编辑:

下面的两个解决scheme在iOS 6或更低版本中工作,但在iOS 7中中断。在iOS 7中, polygon.path属性allways返回NULL 。 安娜女士很善良, 在这里提供另一个SO问题的解决scheme 。 它涉及从多边形点创build自己的path传递到CGPathContainsPoint()

我的多边形图像:

在这里输入图像说明

我创build了这个MKPolygon类别,以防有人使用它。 似乎运作良好。 您必须考虑内部多边形(即多边形中的孔):

 @interface MKPolygon (PointInPolygon) -(BOOL) pointInPolygon:(CLLocationCoordinate2D) point mapView: (MKMapView*) mapView; @end @implementation MKPolygon (PointInPolygon) -(BOOL) pointInPolygon:(CLLocationCoordinate2D) point mapView: (MKMapView*) mapView { MKMapPoint mapPoint = MKMapPointForCoordinate(point); MKPolygonView * polygonView = (MKPolygonView*)[mapView viewForOverlay:self]; CGPoint polygonViewPoint = [polygonView pointForMapPoint:mapPoint]; return CGPathContainsPoint(polygonView.path, NULL, polygonViewPoint, NO) && ![self pointInInteriorPolygons:point mapView:mapView]; } -(BOOL) pointInInteriorPolygons:(CLLocationCoordinate2D) point mapView: (MKMapView*) mapView { return [self pointInInteriorPolygonIndex:0 point:point mapView:mapView]; } -(BOOL) pointInInteriorPolygonIndex:(int) index point:(CLLocationCoordinate2D) point mapView: (MKMapView*) mapView { if(index >= [self.interiorPolygons count]) return NO; return [[self.interiorPolygons objectAtIndex:index] pointInPolygon:point mapView:mapView] || [self pointInInteriorPolygonIndex:(index+1) point:point mapView:mapView]; } @end 

你的foundTap方法:

 -(IBAction)foundTap:(UITapGestureRecognizer *)recognizer { CGPoint point = [recognizer locationInView:self.mapView]; CLLocationCoordinate2D tapPoint = [self.mapView convertPoint:point toCoordinateFromView:self.view]; [self pointInsideOverlay:tapPoint]; if (isInside) { .... } } 

这里是一个方法来调用从以前检查点是否在覆盖内:

 -(void)pointInsideOverlay:(CLLocationCoordinate2D )tapPoint { isInside = FALSE; MKPolygonView *polygonView = (MKPolygonView *)[mapView viewForOverlay:polygonOverlay]; MKMapPoint mapPoint = MKMapPointForCoordinate(tapPoint); CGPoint polygonViewPoint = [polygonView pointForMapPoint:mapPoint]; BOOL mapCoordinateIsInPolygon = CGPathContainsPoint(polygonView.path, NULL, polygonViewPoint, NO); if ( !mapCoordinateIsInPolygon ) //we are finding points that are inside the overlay { isInside = TRUE; } } 

我从string中的xml文件获取MKPolygon数据点。 我将数据stringparsing为Array的点并使用方法在http://alienryderflex.com/polygon/中给出

这个对我有用….

 -(BOOL)isPoint:(CLLocationCoordinate2D)findLocation inPloygon:(NSArray*)polygon{ NSMutableArray *tempPolygon=[NSMutableArray arrayWithArray:polygon]; int i, j=(int)tempPolygon.count-1 ; bool oddNodes=NO; double x=findLocation.latitude; double y=findLocation.longitude; for (i=0; i<tempPolygon.count; i++) { NSString*coordString=[tempPolygon objectAtIndex:i]; NSArray*pointsOfCoordString=[coordString componentsSeparatedByString:@","]; CLLocationCoordinate2D point=CLLocationCoordinate2DMake([[pointsOfCoordString objectAtIndex:1] doubleValue], [[pointsOfCoordString objectAtIndex:0] doubleValue]); NSString*nextCoordString=[tempPolygon objectAtIndex:j]; NSArray*nextPointsOfCoordString=[nextCoordString componentsSeparatedByString:@","]; CLLocationCoordinate2D nextPoint=CLLocationCoordinate2DMake([[nextPointsOfCoordString objectAtIndex:1] doubleValue], [[nextPointsOfCoordString objectAtIndex:0] doubleValue]); if ((point.longitude<y && nextPoint.longitude>=y) || (nextPoint.longitude<y && point.longitude>=y)) { if (point.latitude+(y-point.longitude)/(nextPoint.longitude-point.longitude)*(nextPoint.latitude-point.latitude)<x) { oddNodes=!oddNodes; }} j=i; } return oddNodes; } 

我的多边形(NSArray)对象是在string例如@"-89.860021,44.944266,0"

确定一个点是否在一个任意的多边形是不平凡的,这是不令人惊讶,苹果不提供它作为MKPolygon的一部分。 您可以访问这些点,这使您可以迭代边缘。

为了确定一个点p是否在一个多边形s内,把每一个边看作是一个有向的线段。 如果从任意固定方向(通常平行于X或Y轴)的p的光线与该段相交,则取该光线叉积的Z分量与该有向线段的符号。 如果Z分量> 0,则向计数器加1。 如果它是<0,则减1。实现这一点的技巧是避免当边缘几乎平行于光线时,或者光线穿过顶点时(它只需要计数一次,而不是每个边缘一次) 。

当你对s中的所有边进行了这个操作后,就可以计算出光线与多边形轮廓相交的次数,如果边从左到右依次增加,并且从右向左,你减去。 如果得到的总和为零,那么你在多边形之外。 否则,你在里面。

有许多优化可能。 其中之一就是在更完整的testing之前做一个快速的边框testing。 另一种方法是在所有边上都有一个边界的数据结构,以平凡地丢弃不与射线相交的边。

编辑:AXB的Z分量(A与B的叉积)由下式给出:

 ax * by - ay * bx 

因为你所关心的是标志,你可以检查

 ax * by > ay * bx 

这里是迅速3更新版本感谢@Steve Stomp

 extension MKPolygon { func contains(coordinate: CLLocationCoordinate2D) -> Bool { let polygonRenderer = MKPolygonRenderer(polygon: self) let currentMapPoint: MKMapPoint = MKMapPointForCoordinate(coordinate) let polygonViewPoint: CGPoint = polygonRenderer.point(for: currentMapPoint) return polygonRenderer.path.contains(polygonViewPoint) } } 

这在Swift中适用于我:

 extension MKPolygon { func isCoordinateInsidePolyon(coordinate: CLLocationCoordinate2D) -> Bool { var inside = false let polygonRenderer = MKPolygonRenderer(polygon: self) let currentMapPoint: MKMapPoint = MKMapPointForCoordinate(coordinate) let polygonViewPoint: CGPoint = polygonRenderer.pointForMapPoint(currentMapPoint) if CGPathContainsPoint(polygonRenderer.path, nil, polygonViewPoint, true) { inside = true } return inside } }