Algorithm 检查点是否位于简单多边形的内部

Algorithm 检查点是否位于简单多边形的内部,algorithm,swift,polygon,Algorithm,Swift,Polygon,我试图确定一个点是否位于多边形内部。我使用以下(Swift修改)算法: func包含(多边形:[点],测试:点)->Bool{ 让count=polygon.count 变量i:Int,j:Int var contains=false 对于(i=0,j=count-1;i=test.y)!=(多边形[j].y>=test.y))&& (test.x这里是javascript代码(易于理解,您可以在swift上重写)。它对我来说非常适合,几乎100%,即非常精确 function pointIsI

我试图确定一个点是否位于多边形内部。我使用以下(Swift修改)算法:

func包含(多边形:[点],测试:点)->Bool{
让count=polygon.count
变量i:Int,j:Int
var contains=false
对于(i=0,j=count-1;i=test.y)!=(多边形[j].y>=test.y))&&
(test.x这里是javascript代码(易于理解,您可以在swift上重写)。它对我来说非常适合,几乎100%,即非常精确

function pointIsInPoly(v, polygon) {
    var edge_error = 1.192092896e-07; // epsilon i.e ~0.000000192
    var x = 0;
    var y = 1;
    var i, j;
    var r = false;
    for (i = 0, j = polygon.length - 1; i < polygon.length; j = i++)
    {
        var pi = polygon[i];
        var pj = polygon[j];
        if (Math.abs(pi[y] - pj[y]) <= edge_error && Math.abs(pj[y] - v[y]) <= edge_error && (pi[x] >= v[x]) != (pj[x] >= v[x]))
        {   
            return true;
        }

        if ((pi[y] > v[y]) != (pj[y] > v[y]))
        {
            var c = (pj[x] - pi[x]) * (v[y] - pi[y]) / (pj[y] - pi[y]) + pi[x];
            if (Math.abs(v[x] - c) <= edge_error)
            {
                return true;
            }
            if (v[x] < c)
            {
                r = !r;
            }
        }
    }
    return r;
}
你的解决方案精度不高

function pointIsInPoly(v, polygon) {
    var edge_error = 1.192092896e-07; // epsilon i.e ~0.000000192
    var x = 0;
    var y = 1;
    var i, j;
    var r = false;
    for (i = 0, j = polygon.length - 1; i < polygon.length; j = i++)
    {
        var pi = polygon[i];
        var pj = polygon[j];
        if (Math.abs(pi[y] - pj[y]) <= edge_error && Math.abs(pj[y] - v[y]) <= edge_error && (pi[x] >= v[x]) != (pj[x] >= v[x]))
        {   
            return true;
        }

        if ((pi[y] > v[y]) != (pj[y] > v[y]))
        {
            var c = (pj[x] - pi[x]) * (v[y] - pi[y]) / (pj[y] - pi[y]) + pi[x];
            if (Math.abs(v[x] - c) <= edge_error)
            {
                return true;
            }
            if (v[x] < c)
            {
                r = !r;
            }
        }
    }
    return r;
}
函数点为多边形(v,多边形){
var edge_error=1.192092896e-07;//εi.e~0.000000192
var x=0;
变量y=1;
varⅠ,j;
var r=假;
对于(i=0,j=polygon.length-1;iv[y])!=(pj[y]>v[y]))
{
var c=(pj[x]-pi[x])*(v[y]-pi[y])/(pj[y]-pi[y])+pi[x];

如果(Math.abs(v[x]-c)如果这是用于iOS应用程序,请将多边形转换为UIBezierPath,然后使用函数
containtsPoint()
验证点是否位于该bezierpath的一侧

示例(iOS):

func包含(多边形:[CGPoint],测试:CGPoint)->Bool{
如果polygon.count返回true
}
var p=UIBezierPath()
设firstPoint=polygon[0]为CGPoint
p、 移动点(第一点)
对于1…polygon.count-1中的索引{
p、 addLineToPoint(多边形[索引]作为CGPoint)
}
p、 closePath()
返回p.containsPoint(测试)
}

这是一个改进的PNPoly算法的实现。我使用了它,它工作得很好

func isPointInsidePolygon(polygon: [CGPoint], test:CGPoint) -> Bool {
 var  i:Int, j:Int = polygon.count - 1
 var  contains = false

 for (i = 0; i < polygon.count; i++) {
    if (((polygon[i].y < test.y && polygon[j].y >= test.y) || (polygon[j].y < test.y && polygon[i].y >= test.y))
        && (polygon[i].x <= test.x || polygon[j].x <= test.x)) {
            contains ^= (polygon[i].x + (test.y - polygon[i].y) / (polygon[j].y - polygon[i].y) * (polygon[j].x - polygon[i].x) < test.x)
    }

    j = i
 }

 return contains
}
func isPointInsidePolygon(多边形:[CGPoint],测试:CGPoint)->Bool{
变量i:Int,j:Int=polygon.count-1
var contains=false
对于(i=0;i=test.y)| |(多边形[j].y=test.y))

&&(多边形[i].x也适用于我,所以我不知道问题出在哪里

我还对swift迭代器进行了轻微的修改:

func contains(polygon: [Point], test: Point) -> Bool {

  var pJ=polygon.last!
  var contains = false
  for pI in polygon {
    if ( ((pI.y >= test.y) != (pJ.y >= test.y)) &&
    (test.x <= (pJ.x - pI.x) * (test.y - pI.y) / (pJ.y - pI.y) + pI.x) ){
          contains = !contains
    }
    pJ=pI
  }
  return contains
}

MKPolygon
swift中的简单扩展:

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

很有意思的一点是,为什么选择这个特定的值作为边缘误差,以及修改这个值是如何影响结果的。-什么是“对我来说完美,几乎100%”的意思?:)边缘误差-它是ε,你可以将它更改为更小或更大的值,现在它是0.00000011920…“几乎100%”-表示此任务的所有解决方案都有一定的精度,但这一个非常精确。这里也有相同的问题…上面的坐标也会导致
true
No这不是针对iOS应用程序的-但是这项工作没有那么糟糕-了解
包含的是什么算法会很有趣()
函数正在使用可能我的问题没有澄清这一点-位于多边形边缘的点不应被视为位于内部,因此(40,40)应该实际计算为false。但是不要浪费时间去寻找另一个算法。更一般的问题已经用另一种方法解决了。虽然您描述的问题确实存在,但您对测试用例的描述看起来并不现实。
if
语句中的条件在
true
on point
(30,20)
和边
(40,20)-(40,40)
((polygon[i].y>=test.y)!=(polygon[j].y>=test.y))
零件已
为false
(20>=20)!=(40>=20)
false
。没有答案。这就是所谓的简并。浮点运算非常精确,因此事实上,根据您编写测试的方式,点可能位于多边形的内部或外部有一个模糊边界,即使所有方法在数学上都是正确的。这避免了使用
MKPolygonRenderer
并直接使用
MKPolygon
MKMapPointForCoordinate(coor)
现在是
MKMapPoint(coor)
contains(poly,Point(x:40,y:40))   -> true
contains(poly,Point(x:30,y:20))   -> false
contains(poly,Point(x:40,y:20))   -> true
contains(poly,Point(x:1,y:1))     -> true
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)
        }
    }
}