Geometry 连接两条线段

Geometry 连接两条线段,geometry,Geometry,给定两条二维线段A和B,如何计算连接A和B的最短二维线段C的长度?包含您可能要查找的信息。论文(算法和Pascal代码): 快速提示:如果要基于点比较距离,则无需进行平方根运算 例如,要查看p-to-Q是否比Q-to-R小,只需检查(伪码): square(P.x-Q.x)+square(P.y-Q.y) >,在这两种方法中,可以使用这两种方法来检查线段交会,在使用寿命描述(参考链接)。< P>使用上面的一般思想和算法,这里是C++版本的一组方法,以获得2个任意2D段之间的最小距离。这将处理重叠

给定两条二维线段A和B,如何计算连接A和B的最短二维线段C的长度?

包含您可能要查找的信息。

论文(算法和Pascal代码):


快速提示:如果要基于点比较距离,则无需进行平方根运算

例如,要查看p-to-Q是否比Q-to-R小,只需检查(伪码):

square(P.x-Q.x)+square(P.y-Q.y)
对查找两条直线之间的最短距离有一个很好的简短描述,尽管@strager的链接中包含一些代码(用Fortran!)

认为您的两条线段a和B分别由两点表示:

线A由A1(x,y)和A2(x,y)表示

B行由B1(x,y)B2(x,y)表示

首先使用此算法检查两条线是否相交

如果它们相交,则两条直线之间的距离为零,连接它们的线段就是交点

如果它们不相交,请使用以下方法:计算以下各项之间的最短距离:

  • A1点和B线
  • A2点和B线
  • B1点和A线
  • 点B2和线A
  • 这四条线段中最短的一条就是你的答案。

    来世说,“首先用这个算法检查两条线是否相交”,但他没有说明他指的是什么算法。显然,重要的是线段的交点,而不是延长线;任何非平行线段(不包括未定义直线的重合端点)都将相交,但线段之间的距离不一定为零。所以我猜他的意思是“线段”而不是“直线”

    来世提供的链接是一种非常优雅的方法,可以找到直线(或线段或光线)上距离另一任意点最近的点。这用于查找从每个端点到另一条线段的距离(对于线段或光线,将计算参数u约束为不小于0,对于线段,约束为不大于1),但它不能处理一条线段上的一个内点比任意一个端点更近的可能性,因为它们实际上相交,因此需要额外检查相交

    至于确定线段交点的算法,一种方法是找到延长线的交点(如果平行,则完成),然后确定该点是否在两条线段内,例如通过从交点T到两个端点的向量点积:

    ((Tx-A1x)*(Tx-A2x))+((Ty-A1y)*(Ty-A2y))

    如果为负(或“零”),则T在A1和A2之间(或在一个端点)。类似地检查其他线段。如果其中一个大于“零”,则线段不相交。当然,这取决于首先找到扩展线的交点,这可能需要将每条线表示为一个方程,并通过高斯约化(etc)求解系统

    但可能有一种不必求解交点的更直接的方法,即取向量(B1-A1)和(B2-A1)的叉积以及向量(B1-A2)和(B2-A2)的叉积。如果这些叉积在同一方向,则A1和A2在B线的同一侧;如果它们位于相反方向,则它们位于线B的相对侧(如果为0,则其中一个或两个位于线B)。同样,检查向量(A1-B1)和(A2-B1)以及(A1-B2)和(A2-B2)的叉积。如果这些叉积中的任何一个为“零”,或者如果两条线段的端点落在另一条直线的相对边上,则线段本身必须相交,否则它们不相交

    当然,你需要一个简便的公式来计算两个向量坐标的叉积。或者如果你能确定角度(正或负),你就不需要实际的叉积,因为我们真正关心的是向量之间角度的方向(或者角度的正弦)。但我认为(在2-D中)叉积的公式很简单:

    交叉(V1,V2)=(V1x*V2y)-(V2x*V1y)

    这是三维叉积向量的z轴分量(其中x和y分量必须为零,因为初始向量位于平面z=0),因此您可以简单地查看符号(或“零”)

    P> >,在这两种方法中,可以使用这两种方法来检查线段交会,在使用寿命描述(参考链接)。

    < P>使用上面的一般思想和算法,这里是C++版本的一组方法,以获得2个任意2D段之间的最小距离。这将处理重叠段、平行段、相交段和非相交段。此外,它使用各种epsilon值来防止浮点不精确。最后,除了返回最小距离外,该算法还将为您提供线段1上距离线段2最近的点(如果线段相交,该点也是交点)。如果需要的话,返回[p3,p4]上最靠近[p1,p2]的点也很简单,但我将把它留给读者作为练习:)

    //顶点之间的最小距离(平方),即最小线段长度(平方)
    #定义EPSILON_MIN_顶点_距离_平方0.00000001
    //任意的小ε。如果您使用float而不是double,您可能希望将其更改为类似1E-7f的内容
    #定义EPSILON_TINY 1.0E-14
    //任意广义ε。适用于需要比EPSILON_TINY(大多数地方)更多“slop”的地方。
    //如果使用float而不是double,则可能需要将其更改为类似于1.1920的值
    
    square(P.x-Q.x) + square(P.y-Q.y) < square(Q.x-R.x) + square(Q.y-R.y)