判断一个点是否在多边形内部的方法
- 面积和判别法:判断目标点与多边形的每条边组成的三角形面积和是否等于该多边形,相等则在多边形内部。
- 夹角和判别法:判断目标点与所有边的夹角和是否为360度,为360度则在多边形内部。
- 引射线法:从目标点出发引一条射线,看这条射线和多边形所有边的交点数目。如果有奇数个交点,则说明在内部,如果有偶数个交点,则说明在外部
首先讲解下射线法的原理
情况一,显示了具有 14 条边的严重凹陷多边形的典型情况
-
上图 显示了具有 14 条边的严重凹陷多边形的典型情况
-
红点是需要测试的点,以确定它是否位于多边形内。解决方案是将多边形的每一侧与测试点的Y(垂直)坐标进行比较,并编译节点列表,其中每个节点都是一条线超过测试点的Y阈值的点。
-
在此示例中,多边形的八条边穿过 Y 阈值,而其他六条边则不然。然后,如果测试点的每一侧都有奇数个节点,则它位于多边形内部;如果测试点的每一侧都有偶数个节点,则它位于多边形之外。在我们的示例中,测试点的左侧有五个节点,右侧有三个节点。由于 5 和 3 是奇数,因此我们的测试点位于多边形内部。
(注意:此算法不关心多边形是以顺时针还是逆时针方式
跟踪.
情况二,显示了多边形自身交叉时发生的情况。
在此示例中,十边形的线彼此相交。这种效果很像"独占或"或异或异或,因为汇编语言程序员都知道它。多边形中重叠的部分相互抵消。因此,测试点位于多边形之外,如其两侧的偶数个节点(两个和两个)所示。
情况三,六边形本身不重叠,但它确实有交叉的线
这不是问题;算法仍然工作正常。
情况四,显示了多边形的情况,其中一条边完全位于阈值上。
既然边a和边 b都触及阈值,那么它们是否应该同时生成一个节点?不,因为这样测试点的每一侧都会有两个节点,因此测试会说它在多边形之外,而显然不是!
必须将恰好位于 Y 阈值上的点视为属于阈值的一侧。假设我们任意决定 Y 阈值上的点将属于阈值的"高于"一侧。然后,端a生成一个节点,因为它有一个终结点低于阈值,而另一个终结点位于或高于阈值。端b不会生成节点,因为它的两个端点都位于或高于阈值,因此它不被视为跨阈值端。
情况五,显示了多边形的情况,其中一条边完全位于阈值上。
只需遵循有关情况四所述的规则即可。端c生成一个节点,因为它有一个终结点低于阈值,而其另一个终结点位于阈值或阈值之上。端d不会生成节点,因为它的两个终结点都位于阈值上或之上。而端e也不会生成节点,因为它的两个端点都位于阈值上或之上。
情况六,一个特殊情况。
-
多边形的一个内部角度正好触及测试点的 Y 阈值。这没关系。在上图中,只有一侧(以红色隐藏)在测试点的左侧生成一个节点,而在底部的示例中,三条边可以。无论哪种方式,该数字都是奇数,并且测试点将被视为在多边形内。
-
多边形边缘
如果测试点位于多边形的边界上,则此算法将提供不可预知的结果;即,结果可能是"内部"或"外部",具体取决于任意因素,例如多边形相对于坐标系的方向。(这通常不是问题,因为多边形的边缘无论如何都是无限薄的,并且落在边缘上的点可以向任何方向移动而不会损害多边形的外观
直线表达式
- 我们可以水平/垂直去做射线,容易理解。
代码示例
- 这是Nathan Mercer提供的效率改进。紫色代码消除了完全位于测试点右侧的边上的计算。虽然对于某些多边形,这可能偶尔会变慢,但对于大多数多边形来说,这可能更快。
- 另一个效率改进。内部的"if"语句被删除,取而代之的是独占 OR 操作
- 如果您有许多点需要针对同一(静态)多边形进行测试,这将非常有用
- 个非常聪明的优化