Check whether a point is inside of a simple polygon

拥有回忆 提交于 2019-11-29 00:59:56

问题


I'm trying to determine whether a point is located inside of a polygon or not. I use the following (for Swift modified) algorithm from this website:

func contains(polygon: [Point], test: Point) -> Bool {
    let count = polygon.count
    var i: Int, j: Int
    var contains = false
    for (i = 0, j = count - 1; i < count; j = i++) {
        if ( ((polygon[i].y >= test.y) != (polygon[j].y >= test.y)) &&
            (test.x <= (polygon[j].x - polygon[i].x) * (test.y - polygon[i].y) /
                (polygon[j].y - polygon[i].y) + polygon[i].x) ) {
                    contains = !contains;
        }
    }
    return contains;
}

However, when having a simple polygon with the following coordinates: (x: 0, y: 40), (x: 0, y: 0), (x: 20, y: 0), (x: 20, y: 20), (x: 40, y: 20), (x: 40, y: 40), and check for the point (x: 30, y: 20) the result is true as the if-statement evaluates to true when i and j are 5 and 4 ((x: 40, y: 40) and (x: 40, y: 20)), though the point is only located at the border of the polygon. The function should actually only evaluate true if the point is really located in the polygon. Thanks for any help or improvements/adjustments of the algorithm!


回答1:


If this is for an iOS application, convert your polygon to a UIBezierPath, then use function containtsPoint() to verify if your point in in side that bezierpath

Example (iOS):

func contains(polygon: [CGPoint], test: CGPoint) -> Bool {
        if polygon.count <= 1 {
            return false //or if first point = test -> return true
        }

        var p = UIBezierPath()
        let firstPoint = polygon[0] as CGPoint

        p.moveToPoint(firstPoint)

        for index in 1...polygon.count-1 {
            p.addLineToPoint(polygon[index] as CGPoint)
        }

        p.closePath()

       return p.containsPoint(test)
    }



回答2:


Works for me too, so i don't the where is the problem

I've also made a slighted modified version to use swift iterators:

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
}

Here are the results with your array sample in playground:

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



回答3:


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



回答4:


Here is a improved implementation of PNPoly algorithm. I used it and it works fine.

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
}

for further query check: http://alienryderflex.com/polygon/




回答5:


Here is javascript code (easy to understand, you can rewrite on swift). It works perfectly for me, almost 100%, i.e. great precision.

Your solution have bad precision.

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


来源:https://stackoverflow.com/questions/29344791/check-whether-a-point-is-inside-of-a-simple-polygon

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!