空间中两条线段之间的最短距离
设空间中有两条线段 AB 和 CD ,设 A 点的坐标为
(
,
zyx
1
,
1
)
1
, B 点的坐标为
(
x
2
,
y
2
,
z
2
)
,C 点的坐标为
(
x
3
,
,
zy
3
3
)
, D 点的坐标为
(
x
4
,
y
4
,
z
4
)
。
设 P 是直线 AB 上的一点, P 点的坐标
(
ZYX
,
,
)
可以表示为
)
x
1
)
y
1
)
z
0s
当参数 0<=s<=1 时,P 是线段 AB 上的点;当参数
当参数
时, P 是 AB 延长线上的点。
(
xs
(
ys
(
zs
X
Y
Z
x
1
y
1
z
1s
。
2
2
2
1
1
时,P 是 BA 延长线上的点;
设 Q 是直线 CD 上的一点,Q 点的坐标
(
WVU
,
,
)
可以表示为
3
xU
V
y
3
zW
3
(
xt
(
yt
(
zt
4
4
4
x
3
y
z
3
3
)
)
)
。
当参数 0<=t<=1 时,Q 是线段 CD 上的点;当参数
0t
时,Q 是 DC 延长线上的
点;当参数
1t
时,Q 是 CD 延长线上的点。
P ,Q 两点之间的距离为
距离的平方为
PQ
(
UX
)
2
(
VY
)
2
(
WZ
)
2
。
),(
tsf
2PQ
(
UX
)
2
(
VY
)
2
(
WZ
)
2
[(
x
1
x
3
)
(
xs
2
x
1
)
(
xt
4
x
3
2
)]
[(
y
1
y
3
)
(
ys
2
y
1
)
(
yt
4
y
3
2
)]
[(
z
1
z
3
)
(
zs
2
z
1
)
(
zt
4
z
3
2
)]
。
要求直线 AB ,CD 之间的最短距离,也就是要求
),(
tsf
的最小值。
对
),(
tsf
分别求关于 s ,t 的偏导数,并令偏导数为 0 :
展开并整理后,得到下列方程组:
),(
tsf
s
),(
tsf
t
0
0
2
x
[(
2
)(
x
x
3
4
)(
x
x
1
2
)(
x
x
3
4
[(
x
4
)(
x
x
(
)
x
1
)
(
y
2
(
)
y
1
3
)
(
y
2
2
)
x
3
)
y
1
(
3
4
2
)
y
y
2
1
)(
y
y
1
4
)(
y
y
1
2
)(
y
y
1
(
y
y
3
)(
y
2
)
(
z
z
2
1
)
(
z
y
3
2
(
)
y
z
3
(
)
y
z
2
3
(
z
z
4
)
(
z
y
4
y
2
])
s
z
1
z
z
1
2
])
t
z
3
4
1
1
3
3
4
)(
z
4
)(
z
2
)(
z
4
1
z
z
z
3
3
3
)]
t
)
)]
s
)(
z
4
z
3
)
3
[(
[(
x
x
1
2
(
x
x
1
x
x
1
2
(
x
1
x
3
如果从这个方程组求出的参数 s ,t 的值满足 0<=s<=1,0<=t<=1 ,说明 P 点落在
线段 AB 上,Q 点落在线段 CD 上,这时 PQ 的长度
UX
就是线段 AB 与 CD 的最短距离。
PQ
(
2
)
(
VY
)
2
(
WZ
)
2
float DistanceLineToLine( const osg::Vec3d& p1,const osg::Vec3d& p2,const osg::Vec3d&
p3,const osg::Vec3d& p4 )
{
float distance;
float x1 = p1.x(); //A点坐标(x1,y1,z1)
float y1 = p1.y();
float z1 = p1.z();
float x2 = p2.x(); //B点坐标(x2,y2,z2)
float y2 = p2.y();
float z2 = p2.z();
float x3 = p3.x(); //C点坐标(x3,y3,z3)
float y3 = p3.y();
float z3 = p3.z();
float x4 = p4.x(); //D点坐标(x4,y4,z4)
float y4 = p4.y();
float z4 = p4.z();
float a = (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1);
float b = -((x2-x1)*(x4-x3)+(y2-y1)*(y4-y3)+(z2-z1)*(z4-z3));
float c = -((x1-x2)*(x1-x3)+(y1-y2)*(y1-y3)+(z1-z2)*(z1-z3));
float d = -((x2-x1)*(x4-x3)+(y2-y1)*(y4-y3)+(z2-z1)*(z4-z3));
float e = (x4-x3)*(x4-x3)+(y4-y3)*(y4-y3)+(z4-z3)*(z4-z3);
float f = -((x1-x3)*(x4-x3)+(y1-y3)*(y4-y3)+(z1-z3)*(z4-z3));
if ((a*e-b*d)==0&&(b*d-a*e)==0) //平行
{
float d1 = (p1-p3).length();
float d2 = (p1-p4).length();
distance = (d1
distance = (d1
点向直线 AB 作垂线的垂足点。
用
x
y
z
x
1
y
1
z
1
(
xt
2
(
yt
(
zt
2
2
)
x
1
)
y
1
)
z
1
代入平面方程,化简后解得
)
x
y
)
2
(
z
1
(
z
1
z
2
z
2
)
)(
z
1
0
z
2
)
。
(
x
1
t
x
0
)(
x
1
x
2
y
1
x
1
(
(
2
)
2
y
(
y
1
)(
y
0
1
y
2
)
2
然后,将上面得到的 t 的值代入直线方程,得到
(
xt
(
yt
(
zt
X
Y
Z
x
1
y
1
z
1
2
2
2
)
x
1
)
y
1
)
z
1
。
(
ZYX
,
,
)
就是垂足点 Q 的坐标。
线段 PQ 的长度,也就是 P 点到直线 AB 的垂直距离为
PQ
(
xX
0
2
)
(
Y
y
0
2
)
(
Z
z
0
2
)
。
如果前面求出的参数 t 的值满足
0
t
1
,说明垂足 Q 点落在线段 AB 上,这
时 PQ 的长度就是 P 点到线段 AB 的最短距离。
如果前面求出的参数 t 的值满足
0t
,说明垂足 Q 点不落在线段 AB 上,而
是落在 BA 的延长线上,这时, P 点到线段 AB 的最短距离,就是 P 点到 A 点的
距离,即
PA
(
x
1
x
0
2
)
(
y
1
y
0
2
)
(
z
1
z
0
2
)
。
如果前面求出的参数 t 的值满足
1t
,说明垂足 Q 点不落在线段 AB 上,而是
落在 AB 的延长线上,这时,P 点到线段 AB 的最短距离,就是 P 点到 B 点的距
离,即
PB
(
x
2
x
0
2
)
(
y
2
y
0
2
)
(
z
2
z
0
2
)
。
float DistancePointToLine( const osg::Vec3d& star, const osg::Vec3d& end,const osg::Vec3d&
center )
{
float distance;
float x0 = center.x();//P点坐标(x0,y0,z0)
float y0 = center.y();
float z0 = center.z();
float x1 = star.x(); //A点坐标(x1,y1,z1)
float y1 = star.y();
float z1 = star.z();
float x2 = end.x();//B点坐标(x2,y2,z2)
float y2 = end.y();
float z2 = end.z();
float t = ((x1-x0)*(x1-x2)+(y1-y0)*(y1-y2)+(z1-z0)*(z1-z2))
/((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2));
if (0<=t&&t<=1)//垂足Q点落在线段AB上
{
float X = x1+t*(x2-x1);
float Y = y1+t*(y2-y1);
float Z = z1+t*(z2-z1);
osg::Vec3d Q(X,Y,Z);
distance = (Q-center).length();
}
if (t<0) //垂足Q点不落在线段AB上,而是落在BA的延长线上
{
distance = (star-center).length();
}
if (t>1) //垂足Q点不落在线段AB上,而是落在AB的延长线上
{
distance = (end-center).length();
}
return distance;
}