地理围栏 - 在/外多边形内的点

58

我想确定一个多边形,并实现一个算法来检查一个点是否在多边形内部或外部。

有没有人知道是否有任何类似算法的可用示例?

16个回答

0

检查一个点是否在多边形内部 -

考虑具有顶点a1、a2、a3、a4、a5的多边形。以下一组步骤应该有助于确定点P是在多边形内还是外。

计算由边a1->a2和连接a2到P以及P到a1的向量形成的三角形的向量面积。同样,计算每个可能的三角形的向量面积,其中一个边为多边形的边缘,另外两个连接P到该边缘。

对于一个点来说,要想在多边形内部,每个三角形都需要有正面积。即使其中一个三角形有负面积,那么点P也会被认为在多边形外部。

为了计算给定表示其3条边的向量的三角形的面积,请参考http://www.jtaylor1142001.net/calcjat/Solutions/VCrossProduct/VCPATriangle.htm


0

如果你的多边形是凸的,那么问题就比较简单。对于每一条线段,你可以进行一个简单的测试,以确定点是在该线段内部还是外部(向两个方向无限延伸)。否则,对于凹多边形,从你的点引出一条虚拟射线,直到无限远处(任意方向)。计算它穿过多少条边界线。奇数表示点在内部,偶数表示点在外部。

最后一个算法比看起来要棘手得多。当你的虚拟射线恰好碰到多边形的顶点时,你必须非常小心。

如果你的虚拟射线向-x方向前进,你只需要计算包含至少一个y坐标严格小于你的点的点的线段。这是使大多数奇怪的边缘情况正确工作的方法。


0
如果你有一个简单的多边形(没有相交的线)且没有孔,你也可以将该多边形三角化,然后在每个三角形中测试点。如果多边形的边数很少但点数很多,则这样做速度很快,通常在GIS应用程序中用于绘制TIN。
对于三角形中的有趣点,请参见链接文本 否则一定要使用绕序规则而不是边交叉规则,因为边交叉规则在边缘上的点会有真正的问题,如果你的数据是由精度有限的GPS生成的话,这种情况很可能发生。

0
我将C#方法翻译成了PHP,并添加了许多注释以便理解代码。

PolygonHelps的描述:
检查点是否在多边形内部或外部。此过程使用GPS坐标,在多边形地理区域较小时有效。


输入:
$poly:Point数组:多边形顶点列表; [{Point}, {Point}, ...];
$point:要检查的点;Point: {"lat" => "x.xxx", "lng" => "y.yyy"}


当$c为false时,与多边形相交的次数是偶数,则该点在多边形外部;
当$c为true时,与多边形相交的次数是奇数,则该点在多边形内部;
$n是多边形中顶点的数量;
对于多边形中的每个顶点,方法计算通过当前顶点和前一个顶点的线,并检查这两条线是否有交点。
当交点存在时,$c发生改变。
因此,如果点在多边形内部,则方法可以返回true,否则返回false。
class PolygonHelps {

    public static function isPointInPolygon(&$poly, $point){

        $c = false; 
        $n = $j = count($poly);


        for ($i = 0, $j = $n - 1; $i < $n; $j = $i++){

            if ( ( ( ( $poly[$i]->lat <= $point->lat ) && ( $point->lat < $poly[$j]->lat ) ) 
                || ( ( $poly[$j]->lat <= $point->lat ) && ( $point->lat < $poly[$i]->lat ) ) ) 

            && ( $point->lng <   ( $poly[$j]->lng - $poly[$i]->lng ) 
                               * ( $point->lat    - $poly[$i]->lat ) 
                               / ( $poly[$j]->lat - $poly[$i]->lat ) 
                               +   $poly[$i]->lng ) ){

                $c = !$c;
            }
        }

        return $c;
    }
}

0

Jan的回答非常好。

这里是使用GeoCoordinate类的相同代码。

using System.Device.Location;

...

public static bool IsPointInPolygon(List<GeoCoordinate> poly, GeoCoordinate point)
{
    int i, j;
    bool c = false;
    for (i = 0, j = poly.Count - 1; i < poly.Count; j = i++)
    {
        if ((((poly[i].Latitude <= point.Latitude) && (point.Latitude < poly[j].Latitude))
                || ((poly[j].Latitude <= point.Latitude) && (point.Latitude < poly[i].Latitude)))
                && (point.Longitude < (poly[j].Longitude - poly[i].Longitude) * (point.Latitude - poly[i].Latitude)
                    / (poly[j].Latitude - poly[i].Latitude) + poly[i].Longitude))
            c = !c;
    }

    return c;
}

-1
你可以尝试使用这个简单的类 https://github.com/xopbatgh/sb-polygon-pointer 它很容易处理
  1. 只需将多边形坐标插入数组中
  2. 询问库是否在多边形内部具有所需点的纬度/经度
$polygonBox = [
    [55.761515, 37.600375],
    [55.759428, 37.651156],
    [55.737112, 37.649566],
    [55.737649, 37.597301],
];

$sbPolygonEngine = new sbPolygonEngine($polygonBox);

$isCrosses = $sbPolygonEngine->isCrossesWith(55.746768, 37.625605);

// $isCrosses is boolean

(答案被我删除了,因为最初格式错误)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接