Graphics 如何快速找到射线和m多段线之间的二维最近交点?

Graphics 如何快速找到射线和m多段线之间的二维最近交点?,graphics,geometry,computational-geometry,Graphics,Geometry,Computational Geometry,如何在二维光线之间找到最近的交点: x = x0 + t*cos(a), y = y0 + t*sin(a) 和m条多段线: {(x1,y1), (x2,y2), ..., (xn,yn)} 快点 我首先在所有线段和每个线段之间循环; {(x1,y1)、(x2,y2)}求解: x1 + u*(x2-x1) = x0 + t*cos(a) y1 + u*(y2-y1) = y0 + t*sin(a) 根据Cramer的规则,然后根据距离对交叉口进行排序,但速度很慢:-( 顺便说一句:x中的

如何在二维光线之间找到最近的交点:

x = x0 + t*cos(a), y = y0 + t*sin(a)
和m条多段线:

{(x1,y1), (x2,y2), ..., (xn,yn)}
快点

我首先在所有线段和每个线段之间循环;
{(x1,y1)、(x2,y2)}
求解:

x1 + u*(x2-x1) = x0 + t*cos(a)

y1 + u*(y2-y1) = y0 + t*sin(a)
根据Cramer的规则,然后根据距离对交叉口进行排序,但速度很慢:-(


顺便说一句:
x

中的多段线恰好是单调增加的,为了避免检查与所有线段的交点,需要一些空间分区,例如,。使用空间分区时,需要检查与空间分区的光线交点

在这种情况下,由于点按x坐标排序,因此可以使用方框
(最小x,最小y)-(最大x,最大y)进行空间分区
用于多段线的部分。根框是所有点的最小-最大值,对于多段线的第一部分和第二部分,它被拆分为两个框。部分中的段数相同或一个框有一个以上的段。此框拆分是递归进行的,直到框中只有一个段为止

若要检查光线相交,请从根框开始,并检查它是否与光线相交,如果大于,请选中相交的两个子框,然后先测试较近的子框,然后再测试较远的子框

“检查光线盒相交”是指检查光线是否在两个位置之间穿过轴对齐的线。这是针对4个框边界执行的。

坐标系转换 我建议您首先将设置转换为更简单的坐标:

  • 把你的观点理解为p=(x,y)
  • 将其移动
    (-x0,-y0)
    ,使光线现在从中心开始
  • 将其旋转
    -a
    ,使光线现在位于x轴上
  • 到目前为止,上述操作每点花费了四次加法和四次乘法:

    ca = cos(a) # computed only once
    sa = sin(a) # likewise
    
    x' = x - x0
    y' = y - y0
    x'' = x'*ca + y'*sa 
    y'' = y'*ca - x'*sa
    
    检查交叉口 现在您知道,如果多段线的
    y'
    值的符号发生变化,即
    y1'*y2'<0
    ,则多段线的一段将仅与射线相交。您甚至可以将
    x'
    值的计算推迟到该检查之后。此外,如果该段与x轴出现在x>0时,这只能在任一值大于零时发生,即
    x1'>0或x2'>0
    。如果两个
    x'
    都大于零,则您知道存在交点

    以下段落是可选的,如果您不理解,请不要担心,后面还有一个备选段落。
    如果一个
    x'
    为正,而另一个为负,则必须进一步检查。假设
    y'
    的符号从负变为正,即
    y1'<0
    。从
    p1'
    p2'
    的直线将在x>0处与x轴相交,当且仅当
    p1'
    形成的三角形时>,
    p2''
    原点为逆时针方向。您可以通过检查行列式的符号来确定三角形的方向
    x1'*y2'-x2'*y1'
    ,逆时针三角形为正。如果符号的方向不同,则方向也必须不同。因此把这些放在一起,你可以检查一下

    (x1'' * y2'' - x2'' * y1'') * y2'' > 0
    
    如果是这样的话,那么你就有了一个十字路口。注意到目前为止还没有涉及到昂贵的划分

    计算交点 由于您不仅要确定交叉点是否存在,还要实际找到一个特定的交叉点,因此现在必须计算该交叉点。我们称之为
    p3
    。它必须满足以下等式

    (x2'' - x3'')/(y2'' - y3'') = (x1'' - x3'')/(y1'' - y3'') and 
                           y3'' = 0
    
    导致

    x3'' = (x1'' * y1'' - x2'' * y2'')/(y1'' - y2'')
    
    与上一段中的三角形方向检查不同,您可以始终计算此
    x3''
    值,并在结果为负值时放弃任何结果。代码越少,分割越大。如果对性能有疑问,请进行基准测试

    要查找最接近光线原点的点,请使用最小的
    x3''
    值获取结果,然后将其转换回其原始位置:

    x3 = x3''*ca + x0
    y3 = x3''*sa + y0
    
    给你


    请注意,上面所有的假设都是正数或负数。如果你有零,这取决于你实际想要计算的内容的准确解释,以及你想要如何处理这些边界情况。

    谢谢你的透彻回答!嗨,安特。我想可能根每行应该包含一个边界框。然后每行包含一个边界框直线可以在上半部分和下半部分重复分割成一个边界框,直到树中最低层的每个框都包含一个线段?@Andy:我现在看到你有更多的多段线:-/是的,你可以每个多段线制作一个框,但我认为使用标准分区(例如BSP树)会更好关于所有线段的并集。我所描述的替代分区只是为了从已知的输入数据结构中获益。x值相同(或相似)吗对于所有多段线?x值的数量有限,且它们的间距从0到L相等。然而,一条多段线可能只覆盖该跨度的一个子范围;因此,x值不相同。可能有许多多段线,因此我认为BSP很好,但我不明白在没有线段交叉的情况下该如何工作框?如果线段穿过分隔线,则将其放置在两个框中。这样就不能保证叶框只有一个线段。当框中的线段数较少时,标准的做法是停止空间拆分。如果光线与叶框相交,则检查光线与叶框中所有线段的相交。