Testing 检查点是否位于凸四边形内或凸四边形上的最有效方法

Testing 检查点是否位于凸四边形内或凸四边形上的最有效方法,testing,geometry,polygon,Testing,Geometry,Polygon,我正在尝试找出最有效/最快速的方法,将大量凸四边形(四个给定的x,y点)添加到数组/列表中,然后对照这些四边形检查一个点是否在这些四边形的边界之内或之上 我最初尝试使用光线投射,但认为这有点过分了,因为我知道我所有的多边形都是四边形,它们也都是凸的 目前,我正在将每个四边形拆分为共享一条边的两个三角形,然后使用它们的面积检查该点是否位于这两个三角形中的每一个三角形上 比如说 三角形ABC和测试点P。 如果(areaPAB+areaPAC+areaPBC==areaABC){返回true;} 这看

我正在尝试找出最有效/最快速的方法,将大量凸四边形(四个给定的x,y点)添加到数组/列表中,然后对照这些四边形检查一个点是否在这些四边形的边界之内或之上

我最初尝试使用光线投射,但认为这有点过分了,因为我知道我所有的多边形都是四边形,它们也都是凸的

目前,我正在将每个四边形拆分为共享一条边的两个三角形,然后使用它们的面积检查该点是否位于这两个三角形中的每一个三角形上

比如说 三角形ABC和测试点P。 如果(areaPAB+areaPAC+areaPBC==areaABC){返回true;}

这看起来可能运行得有点慢,因为我需要计算4个不同三角形的面积来运行检查,如果四边形的第一个三角形返回false,我必须再获得4个面积。(我在检查中加入了一点ε,以弥补浮点错误)

我希望有一种更快的方法,可能需要对四边形进行一次点检查,而不是将其拆分为两个三角形

我试图通过将多边形放入数组[,]来减少检查次数。添加多边形时,它会检查最小和最大x和y值,然后使用这些值将同一多边形放置到正确的阵列位置。根据可用多边形检查点时,它会从列表数组中检索适当的列表

我一直在搜索类似的问题,我认为我现在使用的可能是最快的方法来确定一个点是否在三角形中,但我希望有更好的方法来测试一个始终是凸的四边形。我查过的每个多边形测试似乎都是针对一个有许多边或是不规则形状的多边形进行的


感谢您花时间阅读我的长篇大论问题,这是一个简单的问题。

我相信最快的方法是:

1:通过叉积符号查找所有向量对的相互方向(DirectedEdge CheckedPoint)。如果四个标志都相同,则点在内侧

附加:对于每个边

EV[i] = V[i+1] - V[i], where V[] - vertices in order
PV[i] = P - V[i]
Cross[i] = CrossProduct(EV[i], PV[i]) = EV[i].X * PV[i].Y - EV[i].Y * PV[i].X
如果点p位于相对于第i条边(V[i]-V[i+1])的左半平面上,则交叉[i]值为正值,否则为负值。如果所有交叉[]值均为正值,则点p位于四边形内,顶点按逆时针顺序排列。如果所有交叉[]值均为负值,则点p位于四边形内,顶点按顺时针顺序排列。如果值具有不同的符号,则点位于四边形之外

如果四元集对于许多点查询是相同的,那么dmuir建议为每条边预先计算统一的线方程。均匀线方程是a*x+b*y+c=0。(a,b)是边的法向量。这个方程有一个重要的性质:表达式的符号 (a*P.x+b*Y+c)确定点P所在的半平面(如叉积)

2:将四边形拆分为2个三角形,并对每个三角形使用向量方法:以基向量表示检查点向量

P = a*V1+b*V2

当a,b>=0及其和时,点在内部。如果你能负担得起存储每个四边形的每个边的方程,那么你可以在MBo的答案上节省一点时间


例如,如果四边形的每条边都有一个向内指向的法向量N和一个常数d(对于边上的一个顶点p为N.p),则当且仅当每条边的N.x>=d时,点x位于四边形中。因此,每边有两次乘法、一次加法和一次比较,每个点最多需要执行4次测试。此技术适用于任何凸多边形。

谢谢您的建议。我尝试了你的第二种方法,它的计算量比我目前使用的方法要少,但几乎没有。我希望你能多解释一下你的第一种方法,也许我可以将它与存储dmuir提到的边方程结合使用,看看我是否能得到更好的结果。谢谢你在原始帖子中的澄清。我应用了你的公式,它似乎比其他方法运行得更快,但我遇到了一个问题。我需要检查返回真,即使一个点位于边缘上,而不仅仅是在边缘内。有没有什么方法可以让我用ε来调整?目前我实现它的方式如下。因为我将始终且仅永远在多边形中有4个点,而不是[I],我只是手动声明并填充四个EV和PV,并使用浮点对交叉结果执行相同的操作。然后检查所有4个交叉结果是否都>0或<0。似乎将0的支票改为一个较小的数字似乎有效,但我想知道这是否是一种不正确的方式。再次感谢你的帮助!由于我们只需要登录方法1,一些微小的优化将是将EV[i].X*PV[i].Y直接与EV[i].Y*PV[i].X进行比较,而不首先进行扩散,然后检查符号(可能编译到相同的指令,也可能编译到相同的指令),当一个符号与第一个符号不同时退出。该测试是否也允许直线上的点注册为多边形内的点?在检查测试点之前,请您详细说明我需要为每个边做什么来存储它?