多边形中的点算法有时会给出错误的结果


Point in Polygon algorithm giving wrong results sometimes

我在StackOverflow上看到了一个"多边形中的点";我在PHP代码中实现的光线跟踪算法。大多数时候,它工作得很好,但在一些复杂的情况下,对于复杂的多边形和恶性点,它会失败,并且它会说该点不在多边形中。

例如:
您可以在这里找到我的Polygon和Point类:pointInPolygon方法在Polygon类中。在文件的末尾,有两个点应该位于给定的多边形内(在Google Earth上为True)。第二个运行良好,但第一个有缺陷:(.

您可以使用此KML文件在Google Earth上轻松检查多边形。

我去过那里:-)我还浏览了Stackoverflow的PiP建议,包括您的参考资料和本线程。不幸的是,没有一个建议(至少是我尝试过的建议)是完美的,对于现实生活中的场景来说是足够的:就像用户在谷歌地图上徒手绘制复杂的多边形一样;恶毒的";左右问题,负数等等。

PiP算法必须在所有情况下都能工作,即使多边形由数十万个点组成(如县边界、自然公园等)——无论"如何";疯狂的";多边形是.

所以我最终建立了一个新的算法,基于天文学应用程序的一些来源:

//Point class, storage of lat/long-pairs
class Point {
    public $lat;
    public $long;
    function Point($lat, $long) {
        $this->lat = $lat;
        $this->long = $long;
    }
}
//the Point in Polygon function
function pointInPolygon($p, $polygon) {
    //if you operates with (hundred)thousands of points
    set_time_limit(60);
    $c = 0;
    $p1 = $polygon[0];
    $n = count($polygon);
    for ($i=1; $i<=$n; $i++) {
        $p2 = $polygon[$i % $n];
        if ($p->long > min($p1->long, $p2->long)
            && $p->long <= max($p1->long, $p2->long)
            && $p->lat <= max($p1->lat, $p2->lat)
            && $p1->long != $p2->long) {
                $xinters = ($p->long - $p1->long) * ($p2->lat - $p1->lat) / ($p2->long - $p1->long) + $p1->lat;
                if ($p1->lat == $p2->lat || $p->lat <= $xinters) {
                    $c++;
                }
        }
        $p1 = $p2;
    }
    // if the number of edges we passed through is even, then it's not in the poly.
    return $c%2!=0;
}

说明性测试

$polygon = array(
    new Point(1,1), 
    new Point(1,4),
    new Point(4,4),
    new Point(4,1)
);
function test($lat, $long) {
    global $polygon;
    $ll=$lat.','.$long;
    echo (pointInPolygon(new Point($lat,$long), $polygon)) ? $ll .' is inside polygon<br>' : $ll.' is outside<br>';
}
test(2, 2);
test(1, 1);
test(1.5333, 2.3434);
test(400, -100);
test(1.01, 1.01);

输出:

2,2 is inside polygon 
1,1 is outside
1.5333,2.3434 is inside polygon 
400,-100 is outside
1.01,1.01 is inside polygon

我在几个网站上改用上述算法已经一年多了。不同于";SO算法";到目前为止还没有任何投诉。请点击此处查看(国家真菌学数据库,对不起丹麦人)。您可以绘制一个多边形,或者选择一个"多边形";kommune";(一个县)-最终将具有数千个点的多边形与数千个记录进行比较)。

更新注意,该算法针对的是可以非常精确(小数点后n位)的geodata/lat,lngs,因此考虑";在多边形中";作为多边形内的,而不是多边形边界上的。1,1被认为是外部的,因为它在边界上。1.000000000 1,1.01不是。

相关文章: