如何检测两个段(在3d空间中)是否相交?

问题描述 投票:0回答:2

只检查,不需要找到点。坐标z不是0。堆栈溢出中的旧问题都是2d。提前致谢

python 3d intersect segment
2个回答
1
投票

有几种方法可以进行线 - 线交叉测试。经典的方法是使用线性代数(即求解线性矩阵系统),但从软件开发的角度来看,我更像是几何 - 代数方式,以Plucker坐标的形式,它只需要实现向量代数运算(即,交叉产品和点积产品比编码线性系统的矩阵运算更简单。

矢量代数解决方案

给定由点P1和P2限制的线段P和由点Q1和Q2限制的线段Q.

线的参数形式由下式给出:

P(t)= P1 + t(P2 - P1)

Q(t)= Q1 + t(Q2 - Q1)

其中t是区间[0 1]中的实数。

如果两条线相交,则以下等式成立:

P(t0)= Q(t1)

假设存在两个未知数t0和t1。扩展上面的等式,我们得到:

t0(P2-P1)-t1(Q2-Q1)= Q1-P1

为了避免处理矩阵代数,我们可以尝试使用向量代数和替换方法来解决系统:

t0(P2-P1)-t1(Q2-Q1)= Q1-P1

t0 = a + t1 b

t1 = C·(Q1 - (1-a)P1-a P2)/ | C | ^ 2

哪里:

a =(P2-P1)·(Q1-P1)/ | P2-P1 | ^ 2

b =(P2-P1)·(Q2-Q1)/ | P2-P1 | ^ 2

C = b(P2 - P1) - (Q2 - Q1)

其中(•)是点积。如果t0和t1都在区间[0 1]中,则存在交点P(t0)(或Q(t1))。

Plucker坐标方式

给定由点P1和P2限制的线段P和由点Q1和Q2限制的线段Q.

P行的Plucker坐标由一对3d矢量(Pd,Pm)给出:

Pd = P2-P1

Pm = P1×P2

其中Pm是P1和P2的交叉积。线Q的Plucker坐标(Qd,Qm)可以完全相同的方式计算。

如果它们是共面的,则线P和Q只能相交。线P和Q是共面的iif:

Pd•Qm + Qd•Pm = 0

其中(•)是点积。由于机器具有有限的精度,因此稳健的测试应检查不是零,而是少数。如果Pd×Qd = 0则线是平行的(这里0是零矢量)。同样,稳健的测试应该是(Pd×Qd)的平方长度很小的情况。

如果线不平行则它们是共面的并且它们的交叉点(在Plucker的行话中称为“meet”)将是重点:

x =((Pm•N)Qd - (Qm•N)Pd - (Pm•Qd)N)/(Pd×Qd)•N

其中N是任何坐标轴向量(即,(1,0,0)或(0,1,0)或(0,0,1)),使得(Pd×Qd)·N不为零。

如果P和Q都没有通过原点,那么它们的Plucker坐标Pm和Qm将分别为非零,以下的sinpler公式将起作用

X = PM×GM /钯•了Gm

有关Plucker坐标的介绍,请参阅:

https://en.m.wikipedia.org/wiki/Plücker_coordinates

http://www.realtimerendering.com/resources/RTNews/html/rtnv11n1.html#art3

对于一般的交叉公式,请参阅:“推论6”:

http://web.cs.iastate.edu/~cs577/handouts/plucker-coordinates.pdf

线性代数方法

给定由点P1和P2限制的线段P和由点Q1和Q2限制的线段Q.

线的参数形式由下式给出:

P(t)= P1 + t(P2 - P1)

Q(t)= Q1 + t(Q2 - Q1)

其中t是区间[0 1]中的实数。

如果两条线相交,则以下等式成立:

P(t0)= Q(t1)

假设存在两个未知数t0和t1。扩展上面的等式,我们得到:

t0(P2-P1)-t1(Q2-Q1)= Q1-P1

我们可以通过在矩阵代数中表达上述方程来求解t0和t1:

A x = B.

其中A是3x2矩阵,第一列中的矢量坐标为(P2-P1),第二列中的矢量坐标为(Q2-Q1); x是未知数t0和t1的2x1列向量,B是坐标为向量(Q1-P1)的3x1列向量。

经典地,系统可以通过计算矩阵A的伪逆来求解,由A ^ +表示:

A ^ + =(A ^ T A)^ - 1 A ^ T.

见:https://en.m.wikipedia.org/wiki/Generalized_inverse

幸运的是,Python中的任何矩阵包都应该能够非常容易地计算上述计算,也可能非常有效。

如果将A与其伪逆A ^ +相乘等于单位矩阵I,即(A A ^ +)== I,那么就有一个唯一的答案(交集),你可以得到它计算以下产品:

x = A ^ + B.

当然,如果你不能首先计算伪逆,例如,因为(A ^ T A)是单数(即行列式为零),则不存在交集。

由于我们正在处理段,如果x0和x1都在区间[0 1]中,则交点位于点P(x0)或Q(x1)。


0
投票

我可以告诉你可以使用的数学(虽然它有点复杂)。您以参数形式为每条线编写等式。然后找到每一行的参数。见下面的例子:

(a1,a2,a3)________________(b1,b2,b3)
A                           B 


and second line 
(c1,c2,c3)________________(d1,d2,d3)
C                            D

因此,对于第一行,等式将是A + t(BA)(这实际上表示t在0和1之间的线段上的点)和对于第二行的C + s(DC)其中t和s是其值之间的参数0和1表示点位于线段上。 (0是A,1是B)这里A表示(a1,a2,a3)因此你可以将两个等式用于交点(如果有的话)并找到满足三个等式的t和s:

  a1+t(b1-a1)=c1+s(d1-c1)
  a2+t(b2-a2)=c2+s(d2-c2)
  a3+t(b3-a3)=c3+s(d3-c3)

t和s应位于0和1之间,以使该点真正位于线段上。所以我希望你能得到它:)代码:

#input a1,a2,a3 and all the other components here. 

#define all constants required for solving t and s
A=b1-a1
B=c1-d1
C=c1-a1
D=b2-a2
E=c2-d2
F=c2-a2

#find t and s using formula
t=(C*E-F*B)/(E*A-B*D)
s=(D*C-A*F)/(D*B-A*E)

#check if third equation is also satisfied(we have 3 equations and 2 variable
if ((t*(b3-a3)+s*(c3-d3))==c3-a3):
    if(0<=t<=1 and 0<=s<=1):
       print('line segments intersect')
    else:
       print ('line segments intersect on being produced')

这是代码段.hope你终于明白了:)

© www.soinside.com 2019 - 2024. All rights reserved.