【问题标题】:Point crossing path点交叉路径
【发布时间】:2019-12-28 19:13:36
【问题描述】:

我有一个问题,我需要在一个点(显然是在运动中)越过线路径时发出警报, 行路径是行的复杂集合 (y=ax+b)。

假设-

  • 我不知道“点”会从哪一侧越线。
  • 行路径可能非常复杂并包含许多行。

例如——

  1. 解决此问题的最佳方法是什么?
  2. 有谁知道是否有算法?

【问题讨论】:

  • 多少行。一种简单的方法是简单地检查折线的每条线的交点
  • 在什么意义上最好?
  • 您好,感谢重播,1.Many line 表示最多 200 行 2.在性能和准确性方面最好。
  • 200 并不算多,详尽的比较可能就足够了(或难以超越)。

标签: algorithm geometry gis computational-geometry


【解决方案1】:

寻找线/路径拦截

如果您认为线可以来自任何方向并且路径中的线段可以是任何配置,那么没有简单的解决方案。您需要对照线检查每个路径段

下图显示了三行 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

您可以预先计算上例中每个路径段vx2vy2的向量,以节省一点时间(如果路径不随时间变化)

如果minUnitDist 为零,您也可以提前退出循环

这样比较快,不需要复杂的数据结构。大多数路径段将被剔除在// Code Point A

AABB检查

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

更多边界框和Quad trees

如果您仍然发现解决方案太慢,您可以将路径段划分为相关(紧密连接)组,并在检查组中的路径段之前对每个组进行 AABB 测试。

您还可以考虑使用quad tree 来存储路径段,以进一步减少测试线路所需的路径段数。

【讨论】:

    【解决方案2】:

    要快速检查可能的交叉点,您可以将每条“线”的两个端点插入点轨迹方程(可能本身就是一条线段),格式为 px+qy+r=0。如果 px+qy+r 的符号不同,则可能存在交集。这种预筛选会很快。

    为了使其更快,您可以考虑将线条封闭在边界框的层次结构中。一种非常简单的方法是将行的每个边界框两两(按遍历顺序)分组,然后将这些组分组到 by to,依此类推。然后通过递归地比较轨迹的bounding box和hierarchy中的bounding box,就可以得到快速拒绝多条线。

    【讨论】:

      猜你喜欢
      • 2012-06-26
      • 1970-01-01
      • 1970-01-01
      • 2017-10-14
      • 2021-02-05
      • 2022-09-23
      • 2011-08-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多