测试MKCircle是否与MKPolygon相交

时间:2013-09-06 18:19:51

标签: objective-c mapkit mkpolygon

我正在寻找测试MKPolygon是否与MKCircle相交的一些指导。目前我正在使用:

if ([circle intersectsMapRect:[poly boundingMapRect]]) {
                    //they do intersect
   }

我发现这会返回不准确的结果,只是b / c它在我的圆圈周围绘制一个矩形,因此给了我不应该的交叉点。

搜索主题会引导我Chad Saxon's polygon-polygon intersection project。如果我能以某种方式将我的MKCircle转换为多边形多边形,这可能很有用 - 这可能是可能的,但最终我相信这是解决这个问题的圆形方法。

我最终想知道在钻研我自己的自定义几何光线测试算法实现之前是否有一个我忽略的简单解决方案。

2 个答案:

答案 0 :(得分:6)

有几点想法:

  1. 如果您使用该多边形交叉项目,请注意它中有一些泄漏。我发出了一个拉取请求,修复了其中的一些(以及其他一些随机观察)。我也会谨慎地采用任何一个视图控制器代码(因为它还有其他问题),但是如果你对它所带来的各种限制(特别是顺时针限制,这不是真正的如果您只是确定它们是否相交,则会出现问题。

  2. 我没有将圆转换为一系列多边形,然后使用该多边形交集类,而是可以考虑采用另一种方法,利用您可以通过利用您可以查看的事实来检测圆的交点。多边形中相关点之间的距离和圆的半径。似乎问题有三个方面:

    • 如果任何多边形顶点与圆心之间的距离小于圆的半径,则多边形和圆相交。

      vertex inside circle

    • 多边形是否包含圆(这是特殊情况,其中多边形的所有边的距离都大于圆的半径,但圆和多边形仍明显相交)。通过使用CGPath检查多边形视图的CGPathContainsPoint是否包含圆的中心,可以轻松实现此目的。

      enter image description here

    • 唯一复杂的部分是检查多边形的任何一侧是否与圆相交,即多边形的两边和圆心之间的最小距离小于圆的半径;

      side inside circle

    为了计算每一边与圆心的距离,我可能因此遍历多边形的每一边以及面向圆的中心的那些边(即,圆的中心垂直于该圆,意味着一条垂直于多边形边的虚线,穿过圆的中心实际上穿过了线段),你可以:

    • Calculate the constants abc用于方程ax + by + c = 0的多边形的这一边,用于顶点之间的线段多边形(x 1 ,y 1 )和(x 2 ,y 2 ):

    • a =(y 1 - y 2

    • b =(x 2 - x 1

    • c =(x 1 y 2 - x 2 y 1

    • Calculate the distance from a point to a line,使用(x 0 ,y 0 )作为圆圈的中心:

      abs(ax0+by0+c)/sqrt(a^2+b^2)

    • 如果该距离小于圆的半径,则表示多边形与圆相交。

  3. 我把a sample project在github上使用了这个技术。

答案 1 :(得分:1)

对于那些在解决方案上得到一些实质内容的人来说,这里是一个有用的MKCircle扩展,我写的是检查一个点(在这种情况下是一个多边形点)是否在圆圈内。享受!

// MKCircle + PointInCircle.h

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface MKCircle (PointInCircle)

-(BOOL)coordInCircle:(CLLocationCoordinate2D)coord;

@end

// MKCircle + PointInCircle.m

#import "MKCircle+PointInCircle.h"

@implementation MKCircle (PointInCircle)

-(BOOL)coordInCircle:(CLLocationCoordinate2D)coord {

    CLLocation *locFrom = [[CLLocation alloc] initWithLatitude:self.coordinate.latitude longitude:self.coordinate.longitude];
    CLLocation *locTo = [[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude];

    double distance = [locFrom distanceFromLocation:locTo];
    BOOL isInside = (distance <= self.radius);

    return isInside;
}

@end