18

我希望能够判断水龙头是否在 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 属性,但我似乎无法让它们退出。

有什么建议么?

编辑:

以下两种解决方案都适用于 iOS 6 或更低版本,但会在 iOS 7 中中断。在 iOS 7 中,该polygon.path属性总是返回NULL. 安娜女士很友好地在这里提供了另一个 SO 问题的解决方案。它涉及从多边形点创建自己的路径以传递到CGPathContainsPoint().

我的多边形图像:

在此处输入图像描述

4

6 回答 6

12

我创建了这个 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
于 2013-03-05T23:02:59.967 回答
9

你的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;
        }
}
于 2012-04-19T15:44:38.593 回答
7

我从字符串中的 xml 文件中获取 MKPolygon 数据点。我将数据字符串解析为点数组并使用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)对象在字符串中,例如@"-89.860021,44.944266,0"

于 2015-06-16T07:12:57.823 回答
6

感谢@Steve Stomp,这是Swift 4.2的更新版本

extension MKPolygon {
    func contain(coor: CLLocationCoordinate2D) -> Bool {
        let polygonRenderer = MKPolygonRenderer(polygon: self)
        let currentMapPoint: MKMapPoint = MKMapPoint(coor)
        let polygonViewPoint: CGPoint = polygonRenderer.point(for: currentMapPoint)
        if polygonRenderer.path == nil {
            return false
        }else{
            return polygonRenderer.path.contains(polygonViewPoint)
        }
    }
}
于 2017-07-28T11:02:39.963 回答
5

确定一个点是否在任意多边形中并非易事,Apple 不将其作为 MKPolygon 的一部分提供也就不足为奇了。您可以访问这些点,这使您可以遍历边缘。

要确定点 p 是否在多边形 s 内,请将每条边视为 s 中的一条有向线段。如果来自 p 的任何固定方向(通常平行于 X 或 Y 轴)的射线与线段相交,则取射线与该有向线段的叉积的 Z 分量的符号。如果 Z 分量 > 0,则将 1 添加到计数器。如果小于 0,则减 1。实现这一点的技巧是避免当边缘几乎平行于光线或光线穿过顶点时出现问题(它只需要计数一次,而不是每条边缘一次) .

当您对 s 中的所有边执行此操作时,您将计算光线与多边形轮廓相交的次数,如果边是从左到右,则添加,如果它是从右到左,你减去了。如果结果总和为零,则您在多边形之外。否则你就在里面。

有许多可能的优化。其中之一是在更完整的测试之前进行快速边界框测试。另一个是在所有边上都有一个边界的数据结构,以简单地丢弃不与射线相交的边。

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

a.x * b.y - a.y * b.x

由于您只关心标志,因此您可以检查

a.x * b.y > a.y * b.x
于 2012-04-11T18:32:44.497 回答
5

这在#Swift 4.2 中对我有用:

extension MKPolygon {
    func isCoordinateInsidePolyon(coordinate: CLLocationCoordinate2D) -> Bool {
        let polygonRenderer = MKPolygonRenderer(polygon: self)
        let currentMapPoint: MKMapPoint = MKMapPoint(coor)
        let polygonViewPoint: CGPoint = polygonRenderer.point(for: currentMapPoint)
        if polygonRenderer.path == nil {
            return false
        }else{
            return polygonRenderer.path.contains(polygonViewPoint)
        }
    }
}
于 2016-09-25T19:15:52.767 回答