地理围栏 - 点在多边形内部/外部
我想确定一个多边形并实现一个算法来检查一个点是在多边形内部还是外部。
有谁知道是否有任何类似算法的示例?
I would like to determine a polygon and implement an algorithm which would check if a point is inside or outside the polygon.
Does anyone know if there is any example available of any similar algorithm?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
如果我没记错的话,该算法是通过测试点画一条水平线。 计算多边形中有多少条线相交才能到达您的点。
如果答案很奇怪,那么你就在里面。 如果答案是偶数,那么你就在外面。
编辑:是的,他说了什么(维基百科):
If i remember correctly, the algorithm is to draw a horizontal line through your test point. Count how many lines of of the polygon you intersect to reach your point.
If the answer is odd, you're inside. If the answer is even, you're outside.
Edit: Yeah, what he said (Wikipedia):
C# 代码
位置类
C# code
Location class
在搜索网络并尝试各种实现并将它们从 C++ 移植到 C# 后,我终于得到了我的代码:
isLeft 函数给我带来了舍入问题,我花了几个小时才意识到我做的转换是错误的,所以请原谅我的蹩脚if 块位于该函数的末尾。
顺便说一句,这是原始代码和文章:
http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm
After searching the web and trying various implementations and porting them from C++ to C# I finally got my code straight:
The isLeft function was giving me rounding problems and I spent hours without realizing that I was doing the conversion wrong, so forgive me for the lame if block at the end of that function.
BTW, this is the original code and article:
http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm
到目前为止,最好的解释和实现可以在
多边形缠绕数包含点
甚至在末尾有一个 C++ 实现解释得很好的文章。 该站点还包含一些针对其他基于几何的问题的出色算法/解决方案。
我修改并使用了 C++ 实现,并且还创建了 C# 实现。 您肯定想使用绕数算法,因为它比边缘交叉算法更准确,而且速度非常快。
By far the best explanation and implementation can be found at
Point In Polygon Winding Number Inclusion
There is even a C++ implementation at the end of the well explained article. This site also contains some great algorithms/solutions for other geometry based problems.
I have modified and used the C++ implementation and also created a C# implementation. You definitely want to use the Winding Number algorithm as it is more accurate than the edge crossing algorithm and it is very fast.
我认为有一个更简单、更有效的解决方案。
这是 C++ 中的代码。 我应该很简单地将它转换为 C#。
I think there is a simpler and more efficient solution.
Here is the code in C++. I should be simple to convert it to C#.
asp.Net C# 中的完整解决方案,您可以在此处查看完整的详细信息,您可以了解如何使用纬度和经度查找点(lat,lon)无论是在多边形内部还是外部?
文章参考链接
private static bool checkPointExistsInGeofencePolygon(字符串 latlnglist, 字符串 lat, 字符串 lng)
{
The complete solution in asp.Net C#, you can see the complete detail here, you can see how to find point(lat,lon) whether its inside or Outside the Polygon using the latitude and longitudes ?
Article Reference Link
private static bool checkPointExistsInGeofencePolygon(string latlnglist, string lat, string lng)
{
请注意(使用答案,因为我无法发表评论),如果您想使用多边形内的点进行地理围栏,那么您需要更改算法以使用球坐标。 -180 经度与 180 经度相同,在这种情况下,多边形内的点将被破坏。
Just a heads up (using answer as I can't comment), if you want to use point-in-polygon for geo fencing, then you need to change your algorithm to work with spherical coordinates. -180 longitude is the same as 180 longitude and point-in-polygon will break in such situation.
关于科伯斯的回答,我用更易读的干净代码解决了这个问题,并更改了跨越日期边界的经度:
Relating to kobers answer I worked it out with more readable clean code and changed the longitudes that crosses the date border:
我添加一个细节来帮助生活在地球南部的人们!
如果您在巴西(这就是我的情况),我们的 GPS 坐标都是负值。
所有这些算法都会给出错误的结果。
最简单的方法是使用所有点的纬度和经度的绝对值。 在这种情况下,扬·科伯斯基的算法是完美的。
I add one detail to help people who live in the... south of earth!!
If you're in Brazil (that's my case), our GPS coord are all negatives.
And all these algo give wrong results.
The easiest way if to use the absolute values of the Lat and Long of all point. And in that case Jan Kobersky's algo is perfect.
检查点是否在多边形内部 -
考虑具有顶点 a1、a2、a3、a4、a5 的多边形。 以下一组步骤应有助于确定点 P 位于多边形内部还是外部。
计算边 a1->a2 以及连接 a2 到 P 和 P 到 a1 的向量形成的三角形的向量面积。 类似地,计算每个可能的三角形的矢量面积,其中一条边作为多边形的边,另外两个将 P 连接到该边。
对于位于多边形内部的点,每个三角形都需要具有正面积。 即使其中一个三角形的面积为负,点 P 也会从多边形中突出。
为了计算给定表示 3 条边的向量的三角形面积,请参阅 http://www.jtaylor1142001.net/calcjat/Solutions/VCrossProduct/VCPATriangle.htm
Check if a point is inside a polygon or not -
Consider the polygon which has vertices a1,a2,a3,a4,a5. The following set of steps should help in ascertaining whether point P lies inside the polygon or outside.
Compute the vector area of the triangle formed by edge a1->a2 and the vectors connecting a2 to P and P to a1. Similarly, compute the vector area of the each of the possible triangles having one side as the side of the polygon and the other two connecting P to that side.
For a point to be inside a polygon, each of the triangles need to have positive area. Even if one of the triangles have a negative area then the point P stands out of the polygon.
In order to compute the area of a triangle given vectors representing its 3 edges, refer to http://www.jtaylor1142001.net/calcjat/Solutions/VCrossProduct/VCPATriangle.htm
如果你的多边形是凸的,这个问题就更容易了。 如果是这样,您可以对每条线进行简单的测试,看看该点是在该线的内部还是外部(在两个方向上延伸到无穷大)。 否则,对于凹多边形,从您的点到无穷远(在任何方向)绘制一条假想射线。 计算它跨越边界线的次数。 奇数表示该点在内部,偶数表示该点在外部。
最后一个算法比看起来更棘手。 当你的假想光线恰好击中多边形的顶点之一时,你必须非常小心会发生什么。
如果您的假想射线沿 -x 方向行进,则您可以选择仅对包含至少一个 y 坐标严格小于该点的 y 坐标的点的线进行计数。 这就是让大多数奇怪的边缘情况正常工作的方法。
The problem is easier if your polygon is convex. If so, you can do a simple test for each line to see if the point is on the inside or outside of that line (extending to infinity in both directions). Otherwise, for concave polygons, draw an imaginary ray from your point out to infinity (in any direction). Count how many times it crosses a boundary line. Odd means the point is inside, even means the point is outside.
This last algorithm is trickier than it looks. You will have to be very careful about what happens when your imaginary ray exactly hits one of the polygon's vertices.
If your imaginary ray goes in the -x direction, you can choose only to count lines that include at least one point whose y coordinate is strictly less than the y coordinate of your point. This is how you get most of the weird edge cases to work correctly.
如果您有一个简单的多边形(没有任何线交叉)并且没有孔,您也可以对多边形进行三角测量,您可能会在 GIS 应用程序中执行此操作来绘制 TIN,然后测试每个多边形中的点三角形。 如果多边形的边数较少但点数较多,则速度很快。
有关三角形中有趣的点,请参阅 链接文本
否则肯定使用缠绕规则与边缘交叉相比,边缘交叉对于边缘上的点确实存在问题,如果您的数据是从精度有限的 GPS 生成的,则很可能会出现这种问题。
If you have a simple polygon (none of the lines cross) and you don't have holes you can also triangulate the polygon, which you are probably going to do anyway in a GIS app to draw a TIN, then test for points in each triangle. If you have a small number of edges to the polygon but a large number of points this is fast.
For an interesting point in triangle see link text
Otherwise definately use the winding rule rather than edge crossing, edge crossing has real problems with points on edges, which if your data is generated form a GPS with limited precision is very likely.
多边形被定义为点对 A、B、C .... A 的顺序列表。
没有边 AB、BC ... 与任何其他边相交
确定框 Xmin、Xmax、Ymin、Ymax
情况 1 测试点 P 位于框外 情况
2 测试点 P 位于框内:
确定框的“直径”D box {[Xmin,Ymin] - [Xmax, Ymax]} (并添加一点额外的内容以避免与 D 在一侧可能发生的混淆)
确定所有边的梯度 M
找到与所有梯度 M 最不同的梯度 Mt
测试线从 P 以梯度 Mt 延伸距离 D。
将交点计数设置为零
对于每条边 AB、BC 测试 PD 与边的交点
从开始到但不包括结束。 增加交叉点的数量
如果需要。 请注意,从 P 到交点的距离为零表示 P 在一侧
奇数计数表示 P 在多边形内部
the polygon is defined as a sequential list of point pairs A, B, C .... A.
no side A-B, B-C ... crosses any other side
Determine box Xmin, Xmax, Ymin, Ymax
case 1 the test point P lies outside the box
case 2 the test point P lies inside the box:
Determine the 'diameter' D of the box {[Xmin,Ymin] - [Xmax, Ymax]} ( and add a little extra to avoid possible confusion with D being on a side)
Determine the gradients M of all sides
Find a gradient Mt most different from all gradients M
The test line runs from P at gradient Mt a distance D.
Set the count of intersections to zero
For each of the sides A-B, B-C test for the intersection of P-D with a side
from its start up to but NOT INCLUDING its end. Increment the count of intersections
if required. Note that a zero distance from P to the intersection indicates that P is ON a side
An odd count indicates P is inside the polygon
我在 Php 中翻译了 c# 方法,并添加了许多注释来理解代码。
PolygonHelps 的说明:
检查点是在多边形内部还是外部。 此过程使用 GPS 坐标,当多边形具有较小的地理区域时,它可以工作。
输入:
$poly:点数组:多边形顶点列表; [{Point}, {Point}, ...];
$point:要检查的点; 点:{“lat”=> "x.xxx", "lng" =>; “y.yyy”}
当 $c 为 false 时,与多边形交点的个数为偶数,因此该点在多边形之外;
当 $c 为 true 时,与多边形交点的数量为奇数,因此该点在多边形内部;< br>$n 是多边形中的顶点数;
对于多边形中的每个顶点,方法计算通过当前顶点和前一个顶点的线,并检查两条线是否有交点。
当交点时$c 发生变化存在。
因此,如果点在多边形内部,方法可以返回 true,否则返回 false。
I translated c# method in Php and I added many comments to understand code.
Description of PolygonHelps:
Check if a point is inside or outside of a polygon. This procedure uses gps coordinates and it works when polygon has a little geographic area.
INPUT:
$poly: array of Point: polygon vertices list; [{Point}, {Point}, ...];
$point: point to check; Point: {"lat" => "x.xxx", "lng" => "y.yyy"}
When $c is false, the number of intersections with polygon is even, so the point is outside of polygon;
When $c is true, the number of intersections with polygon is odd, so the point is inside of polygon;
$n is the number of vertices in polygon;
For each vertex in polygon, method calculates line through current vertex and previous vertex and check if the two lines have an intersection point.
$c changes when intersection point exists.
So, method can return true if point is inside the polygon, else return false.
Jan 的回答非常棒。
下面是使用 GeoCoordinate 类的相同代码。
...
Jan's answer is great.
Here is the same code using the GeoCoordinate class instead.
...
您可以尝试这个简单的类 https://github.com/xopbatgh/sb-polygon-pointer< /a>
处理起来很容易
(答案是我自己删除的,因为最初格式错误) >
You can try this simple class https://github.com/xopbatgh/sb-polygon-pointer
It is easy to deal with it
(answer was returned from deleted by myself because initially it was formatted wrong)