三维(3D)中线段与点之间的最短距离
Shortest distance between a line segement and a point in three dimensions (3D)
我一直在 MATLAB 中使用一个优秀的线程构建程序,该线程描述了如何在 2D 中找到点和线段之间的最短距离 (Shortest distance between a point and a line segment)。我需要一个函数,其功能与之前回答的问题基本相同,但在 3D 而不是 2D 和 MATLAB 中。
None 对之前 post 的回答的最热门评论中有 MATLAB,所以我在理解这段代码的幕后发生的事情时遇到了一些困难。也许你们中一些更聪明或更熟练的人可以帮助我将其转换为 3D MATLAB 代码?
线段将定义为两个点 S1 (x1,y1,z1) 和 S2 (x2,y2,z2),并且该点只是一个坐标 Pnt (x3,y3,z3)。
编辑:这里似乎有点混乱。我的意思是线段不是无限线。我附上了我正在使用的代码。我想补充一点,我修改过的这段代码最初是作为上述链接线程中评论的一部分编写的,原作者 Peter Karasev 值得称赞。照原样,代码在 2D 中工作,我在 3 行中注释了它,这是使其成为 3D 的开始(vz、uz 和 lenSqr)。我的具体问题是我真的不明白 detP 在数学上发生了什么,以及我如何使 detP 和随后的 if 语句在 3D 中工作。
输入如上文中原始问题文本中所定义。
function r = PointToLineSegment3D( S1, S2, Pnt )
% r = PointToLineSegment3D( S1, S2, Pnt )
vx = S1(1)-Pnt(1);
vy = S1(2)-Pnt(2);
% vz = S1(3)-Pnt(3);
ux = S2(1)-S1(1);
uy = S2(2)-S1(2);
% uz = S2(3)-S1(3);
lenSqr= (ux*ux+uy*uy); % +uz*uz
detP= -vx*ux + -vy*uy;
if( detP < 0 )
r = norm(S1-Pnt,2);
elseif( detP > lenSqr )
r = norm(S2-Pnt,2);
else
r = abs(ux*vy-uy*vx)/sqrt(lenSqr);
end
end
只需将A
和B
和P
定义为列向量即可。那么直线 AB
上的任何点 X
的形式为
X = A+t*(B-A)
对于 t
的某些值。
当然直线XP
必须垂直于直线AB
,这意味着对应的标量积必须为零:
0 == (A+t*(B-A) - P)' * (B-A) == (A-P)'*(B-A)+t*norm(B-A)^2
这意味着
t = (A-P)'*(B-A) / norm(B-A)^2
那么只要计算距离XP
就是
d = norm(X-P)
所以
d = norm(A+t*(B-A)-P)
所以你只需要使用我在这里发布的第三行和第五行代码,如果我没弄错的话你就可以开始了。
对于发现此问题的未来用户,这是我为在 MATLAB 中处理 3D 而编写的代码。这仅适用于线段的无限线。
function r = PointToLineSegment3D( S1, S2, Pnt )
% r = PointToLineSegment3D( S1, S2, Pnt )
vx = S1(1)-Pnt(1);
vy = S1(2)-Pnt(2);
vz = S1(3)-Pnt(3);
ux = S2(1)-S1(1);
uy = S2(2)-S1(2);
uz = S2(3)-S1(3);
lenSqr= (ux*ux+uy*uy+uz*uz)
detP= -vx*ux + -vy*uy + -vz*uz;
if( detP < 0 )
r = norm(S1-Pnt,2);
elseif( detP > lenSqr )
r = norm(S2-Pnt,2);
else
r =norm( abs(cross((S2-S1),(S1-Pnt)))/sqrt(lenSqr));
end
end
C++ 我不确定它是不是正确的答案,但有时它可以工作)
测试数据:Pnt=[1 1 1]; S1=[0 0 0]; S2=[0 3 3]; ans=1.0
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<vector>
#include<iterator>
#include <iomanip>
using namespace std;
int main()
{
double vx,vy,vz,ux,uy,uz,r=0,lenSqr,detP, c,tmp;
int i;
vector<double>copy;
vector<double>Pnt;
vector<double>S1;
vector<double>S2;
for(i=0; i<9; i++)
{
cin>>c;
copy.push_back(c);
}
for(i=0; i<3; i++)
{
Pnt.insert(Pnt.begin(), copy[i]);
// cout<<copy[i]<<endl;
}
copy.erase(copy.begin(),copy.begin()+3);
copy.shrink_to_fit();
for(i=0; i<3; i++)
{
S1.insert(S1.begin(), copy[i]);
}
copy.erase(copy.begin(),copy.begin()+3);
copy.shrink_to_fit();
for(i=0; i<3; i++)
{
S2.insert(S2.begin(), copy[i]);
copy.erase(copy.begin());
}
copy.shrink_to_fit();
/*
vector<float>Pnt(3,1.0);
//for(i=0; i<3; i++)
//cout<<Pnt[i];
vector<float>S1(3,0.0);
//for(i=0; i<3; i++)
//cout<<S1[i];
vector<float>S2;
S2.insert(S2.begin(), 3.0);
S2.insert(S2.begin(), 3.0);
S2.insert(S2.begin(), 0.0);
//for(int i=0; i<3; i++)
//cout<<S2[i];
//cout<<endl;
*/
vx = S1[0]-Pnt[0];
vy = S1[1]-Pnt[1];
vz = S1[2]-Pnt[2];
//cout<<"V: "<<vx<<vy<<vz<<endl;
ux = S2[0]-S1[0];
uy = S2[1]-S1[1];
uz = S2[2]-S1[2];
//cout<<"U: "<<ux<<uy<<uz<<endl;
lenSqr= (ux*ux+uy*uy+uz*uz);
//cout<<"lenSqr "<<lenSqr<<endl;
detP= (-vx*ux ) + (-vy*uy) + (-vz*uz);
//cout<<"detP "<<detP<<endl;
if( detP < 0 )
{
// r = norm(S1-Pnt,2)
for(i=0; i<3; i++)
{
tmp=pow((S1[i]-Pnt[i]),2);
r += tmp;
// cout<<"r: "<<r;
}
r = sqrt(r);
cout<<fixed<<r;
}
else if( detP > lenSqr )
{
// r = norm(S2-Pnt,2);
for(i=0; i<3; i++)
{
tmp=pow((S2[i]-Pnt[i]),2);
r += tmp;
// cout<<"r: "<<r;
}
r = sqrt(r);
cout<<fixed<<r;
}
//if(detP <= lenSqr || detP>=0)
else
{
// r =norm( abs(cross((S2-S1),(S1-Pnt)))/sqrt(lenSqr));
float i1,j1,k1;
i1 = uz*vy-uy*vz;
j1 = ux*vz-uz*vx;
k1 = uy*vx-ux*vy;
//cout<<"I J k: "<<i1<<j1<<k1<<endl;
r=sqrt(pow(i1,2)+pow(j1,2)+pow(k1,2))/sqrt(lenSqr);
cout<<fixed<<r;
}
return 0;
}
我一直在 MATLAB 中使用一个优秀的线程构建程序,该线程描述了如何在 2D 中找到点和线段之间的最短距离 (Shortest distance between a point and a line segment)。我需要一个函数,其功能与之前回答的问题基本相同,但在 3D 而不是 2D 和 MATLAB 中。
None 对之前 post 的回答的最热门评论中有 MATLAB,所以我在理解这段代码的幕后发生的事情时遇到了一些困难。也许你们中一些更聪明或更熟练的人可以帮助我将其转换为 3D MATLAB 代码?
线段将定义为两个点 S1 (x1,y1,z1) 和 S2 (x2,y2,z2),并且该点只是一个坐标 Pnt (x3,y3,z3)。
编辑:这里似乎有点混乱。我的意思是线段不是无限线。我附上了我正在使用的代码。我想补充一点,我修改过的这段代码最初是作为上述链接线程中评论的一部分编写的,原作者 Peter Karasev 值得称赞。照原样,代码在 2D 中工作,我在 3 行中注释了它,这是使其成为 3D 的开始(vz、uz 和 lenSqr)。我的具体问题是我真的不明白 detP 在数学上发生了什么,以及我如何使 detP 和随后的 if 语句在 3D 中工作。
输入如上文中原始问题文本中所定义。
function r = PointToLineSegment3D( S1, S2, Pnt )
% r = PointToLineSegment3D( S1, S2, Pnt )
vx = S1(1)-Pnt(1);
vy = S1(2)-Pnt(2);
% vz = S1(3)-Pnt(3);
ux = S2(1)-S1(1);
uy = S2(2)-S1(2);
% uz = S2(3)-S1(3);
lenSqr= (ux*ux+uy*uy); % +uz*uz
detP= -vx*ux + -vy*uy;
if( detP < 0 )
r = norm(S1-Pnt,2);
elseif( detP > lenSqr )
r = norm(S2-Pnt,2);
else
r = abs(ux*vy-uy*vx)/sqrt(lenSqr);
end
end
只需将A
和B
和P
定义为列向量即可。那么直线 AB
上的任何点 X
的形式为
X = A+t*(B-A)
对于 t
的某些值。
当然直线XP
必须垂直于直线AB
,这意味着对应的标量积必须为零:
0 == (A+t*(B-A) - P)' * (B-A) == (A-P)'*(B-A)+t*norm(B-A)^2
这意味着
t = (A-P)'*(B-A) / norm(B-A)^2
那么只要计算距离XP
就是
d = norm(X-P)
所以
d = norm(A+t*(B-A)-P)
所以你只需要使用我在这里发布的第三行和第五行代码,如果我没弄错的话你就可以开始了。
对于发现此问题的未来用户,这是我为在 MATLAB 中处理 3D 而编写的代码。这仅适用于线段的无限线。
function r = PointToLineSegment3D( S1, S2, Pnt )
% r = PointToLineSegment3D( S1, S2, Pnt )
vx = S1(1)-Pnt(1);
vy = S1(2)-Pnt(2);
vz = S1(3)-Pnt(3);
ux = S2(1)-S1(1);
uy = S2(2)-S1(2);
uz = S2(3)-S1(3);
lenSqr= (ux*ux+uy*uy+uz*uz)
detP= -vx*ux + -vy*uy + -vz*uz;
if( detP < 0 )
r = norm(S1-Pnt,2);
elseif( detP > lenSqr )
r = norm(S2-Pnt,2);
else
r =norm( abs(cross((S2-S1),(S1-Pnt)))/sqrt(lenSqr));
end
end
C++ 我不确定它是不是正确的答案,但有时它可以工作) 测试数据:Pnt=[1 1 1]; S1=[0 0 0]; S2=[0 3 3]; ans=1.0
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<vector>
#include<iterator>
#include <iomanip>
using namespace std;
int main()
{
double vx,vy,vz,ux,uy,uz,r=0,lenSqr,detP, c,tmp;
int i;
vector<double>copy;
vector<double>Pnt;
vector<double>S1;
vector<double>S2;
for(i=0; i<9; i++)
{
cin>>c;
copy.push_back(c);
}
for(i=0; i<3; i++)
{
Pnt.insert(Pnt.begin(), copy[i]);
// cout<<copy[i]<<endl;
}
copy.erase(copy.begin(),copy.begin()+3);
copy.shrink_to_fit();
for(i=0; i<3; i++)
{
S1.insert(S1.begin(), copy[i]);
}
copy.erase(copy.begin(),copy.begin()+3);
copy.shrink_to_fit();
for(i=0; i<3; i++)
{
S2.insert(S2.begin(), copy[i]);
copy.erase(copy.begin());
}
copy.shrink_to_fit();
/*
vector<float>Pnt(3,1.0);
//for(i=0; i<3; i++)
//cout<<Pnt[i];
vector<float>S1(3,0.0);
//for(i=0; i<3; i++)
//cout<<S1[i];
vector<float>S2;
S2.insert(S2.begin(), 3.0);
S2.insert(S2.begin(), 3.0);
S2.insert(S2.begin(), 0.0);
//for(int i=0; i<3; i++)
//cout<<S2[i];
//cout<<endl;
*/
vx = S1[0]-Pnt[0];
vy = S1[1]-Pnt[1];
vz = S1[2]-Pnt[2];
//cout<<"V: "<<vx<<vy<<vz<<endl;
ux = S2[0]-S1[0];
uy = S2[1]-S1[1];
uz = S2[2]-S1[2];
//cout<<"U: "<<ux<<uy<<uz<<endl;
lenSqr= (ux*ux+uy*uy+uz*uz);
//cout<<"lenSqr "<<lenSqr<<endl;
detP= (-vx*ux ) + (-vy*uy) + (-vz*uz);
//cout<<"detP "<<detP<<endl;
if( detP < 0 )
{
// r = norm(S1-Pnt,2)
for(i=0; i<3; i++)
{
tmp=pow((S1[i]-Pnt[i]),2);
r += tmp;
// cout<<"r: "<<r;
}
r = sqrt(r);
cout<<fixed<<r;
}
else if( detP > lenSqr )
{
// r = norm(S2-Pnt,2);
for(i=0; i<3; i++)
{
tmp=pow((S2[i]-Pnt[i]),2);
r += tmp;
// cout<<"r: "<<r;
}
r = sqrt(r);
cout<<fixed<<r;
}
//if(detP <= lenSqr || detP>=0)
else
{
// r =norm( abs(cross((S2-S1),(S1-Pnt)))/sqrt(lenSqr));
float i1,j1,k1;
i1 = uz*vy-uy*vz;
j1 = ux*vz-uz*vx;
k1 = uy*vx-ux*vy;
//cout<<"I J k: "<<i1<<j1<<k1<<endl;
r=sqrt(pow(i1,2)+pow(j1,2)+pow(k1,2))/sqrt(lenSqr);
cout<<fixed<<r;
}
return 0;
}