Java中Area与Line相交检测及两点视线检测方案咨询
嘿,看来你之前把Line转成小宽度Area的路子因为斜率问题走不通了,这确实是个容易踩的坑——毕竟非水平/垂直的线段转成窄Area时,很容易出现边界判断不准的情况。下面给你几个更靠谱的实现思路:
1. 基于多边形边的逐段相交检测(通用方案)
首先要明确:你的Area本质上应该是一个闭合多边形(不管是凸还是凹),那我们可以把问题拆解成线段与多边形的相交判断,步骤如下:
- 第一步:先判断Line的两个端点是否有至少一个在Area内部。如果是,直接判定相交(毕竟端点在区域里,线段肯定和区域有交集)。
- 第二步:如果两个端点都不在Area内部,那就遍历Area的每条边,逐一判断这条Line和Area的边是否存在线段级别的相交。只要有一组边和Line相交,就说明二者相交。
这里的线段相交判断可以用经典的叉积法,核心逻辑是:
对于两条线段AB和CD,计算两个叉积:cross1 = (B.x - A.x) * (C.y - A.y) - (B.y - A.y) * (C.x - A.x)cross2 = (B.x - A.x) * (D.y - A.y) - (B.y - A.y) * (D.x - A.x)
如果cross1和cross2的符号不同,说明点C和D在线段AB的两侧;再反过来计算线段CD相对于AB的叉积,若符号也不同,就说明两条线段相交。
2. 结合射线法的综合判断
这个方法是点在多边形内判断的延伸:
- 先检查Line的端点是否在Area内部(和方法1第一步一样)。
- 若端点都不在内部,再判断Line是否穿过Area的边界:遍历Area的每条边,只要Line和某条边相交,就判定相交;另外还要注意一种特殊情况——Line完全被包含在Area内部?不过这种情况其实第一步的端点判断已经覆盖了(端点在内部的话直接返回相交)。
3. 分离轴定理(SAT,适合凸Area)
如果你的Area是凸多边形,分离轴定理是效率很高的方案:
分离轴定理的核心是:两个凸形状不相交的充要条件是存在一条轴,使得两个形状在这条轴上的投影没有重叠。
对于线段和凸多边形,需要检查的轴包括:
- 线段的垂直方向轴
- 多边形每条边的垂直方向轴
对每个轴,分别计算线段和多边形在该轴上的投影区间,如果所有轴的投影区间都有重叠,那么线段和多边形相交;只要有一个轴的投影不重叠,就说明不相交。
为什么不推荐转小宽度Area的方案?
你之前尝试的方法问题在于:当Line的斜率非0或无穷大时,小宽度的Area的边界是平行于Line的两条线段,这时候如果Line刚好擦过原Area的边角,很容易因为宽度的问题出现误判(要么漏检,要么把不相交的情况判定为相交),而且这种方法的计算量也比直接的线段-多边形相交检测大。
内容的提问来源于stack exchange,提问作者callan

