寻找线/路径拦截
如果您认为线可以来自任何方向并且路径中的线段可以是任何配置,那么没有简单的解决方案。您需要对照线检查每个路径段
下图显示了三行 AD、BD 和 CD。 AD 线和 CD 线在 3 个位置截取路径,在 1 个位置截取 BD。
对于每条线段,最接近线段起点的点就是您要查找的点。
要找到这些点,我们必须首先定义一个点和线段。
// point
p.x = ?
p.y = ?
// line segment contains start and end points p1, p2
l.p1 = {x, y}
l.p2 = {x, y}
寻找线段上的最小单位距离
计算每个路径段截取的线段上的单位距离(如果有)。以最小单位距离 >= 0 截取线段的路径段将是第一个截点。您正在寻找的那个。
伪代码
以下显示了所需的步骤。根据线段检查每个路径段。首先检查路径是否与线段不平行。如果是这样,请检查截距是否在路径段上。如果是,请检查截距是否在线段上,并且是迄今为止找到的最接近线起点的截距。
// l is line segment
interceptFound = false // Semaphore to indicate point found
minUnitDist = 1 // unit dist of intercept
ix = 0 // intercept point
iy = 0
pathSeg // if needed the path segment that intercepted
vx1 = l.p2.x - l.p1.x // vector of line segment
vy1 = l.p2.y - l.p1.y
for each pathSegment // p path segment
vx2 = p.p2.x - p.p1.x // vector of path segment
vy2 = p.p2.y - p.p1.y
crossProd = vx1 * vy2 - vy1 * vx2
if crossProd != 0 // Check lines are not parallel
vx3 = l.p1.x - p.p1.x // Vector from start of l to start of p
vy3 = l.p1.y - p.p1.y
unit = (vx1 * vy3 - vy1 * vx3) / crossProd // unit dist on path segment
if unit >= 0 && unit <= 1 // Code Point A.
unit = (vx2 * vy3 - vy2 * vx3) / crossProd // unit dist on line segment
if unit >= 0 && unit <= minUnitDist // Is the intercept closest to start
interceptFound = true
minUnitDist = unit
pathSeg = p // store intercepting path segment
if interceptFound // Was a intercept found
ix = l.p1.x + vx1 * minUnitDist // Calculate intercept point
iy = l.p1.y + vy1 * minUnitDist
您可以预先计算上例中每个路径段vx2、vy2的向量,以节省一点时间(如果路径不随时间变化)
如果minUnitDist 为零,您也可以提前退出循环
这样比较快,不需要复杂的数据结构。大多数路径段将被剔除在// Code Point A
Axis Aligned Bounding Box检查
如果路径段的数量非常多,您可以执行 AABB 来避免上面示例中的一些数学运算。仅当路径点不随时间变化并且您在开始时为每个路径段计算一次边界框时,这将是一个好处
伪代码AABB检查
// l is a line segment
l.left = min(l.p1.x, l.p2.x)
l.right = max(l.p1.x, l.p2.x)
l.top = min(l.p1.y, l.p2.y)
l.bottom = max(l.p1.y, l.p2.y)
然后检查两个段是否可以拦截
// l and p are line segs with bounding boxes calculated
if l.left > p.right || l.right < p.left || l.top > p.bottom || l.bottom < p.top
// line segments do not intercept
else
// Line segments may intercept
如果您仍然发现解决方案太慢,您可以将路径段划分为相关(紧密连接)组,并在检查组中的路径段之前对每个组进行 AABB 测试。
您还可以考虑使用quad tree 来存储路径段,以进一步减少测试线路所需的路径段数。