线段与三维点之间的最短距离(3D)

时间:2017-04-11 20:49:00

标签: matlab 3d geometry distance line-segment

我一直在MATLAB中构建一个程序,这个程序描述了如何在2D(Shortest distance between a point and a line segment)中找到点和线段之间的最短距离。我需要一个与之前回答的问题基本相同的功能,但是在3D而不是2D和MATLAB中。

上一篇文章的答案的最高评论都没有在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

3 个答案:

答案 0 :(得分:3)

只需将AB以及P定义为列向量即可。然后,X行上的任何点AB都具有

形式
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)

所以你只需要使用我在这里发布的第三行和第五行代码,如果我没有弄错你就可以了。

答案 1 :(得分:1)

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;
}

答案 2 :(得分:0)

对于发现此问题的未来用户,这是我在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