◇◆◇点到线段的最短距离◇◆◇

GoldenEye 2002-11-22 03:55:50
有一个线段,已知两个端点的坐标,在线段以外或之中有一点,坐标也已知,但所有坐标方位、方向不定,求最简化(时间最短)“这一点到这段线段的最短距离”算法。写伪代码、示例、说明都可以,谢谢!
...全文
830 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
HuWenjin 2002-11-25
  • 打赏
  • 举报
回复
我写的代码不管是烦也好,简也好,完成楼主的问题是没有说的

多种情况全部考虚到,实际应用也没有问题,就是说不管点是什么值都返回正确的距离。

什么都不用再想,只要 COPY 到你的程序中,输入入口值就可以了
harry202 2002-11-25
  • 打赏
  • 举报
回复
BOOL CSCLine::IsSelLine(CPoint pt/*鼠标点击点*/,CPoint p1,CPoint p2/*直线的两个端点*/)
{
/////////////////////////////////////////////////
int x=pt.x,y=pt.y;
int x1=p1.x,y1=p1.y;
int x2=p2.x,y2=p2.y;

//如果点击不在区域中,则返回FALSE
if(!PtInRect(CRect((x1<=x2?x1:x2)-5,
(y1<=y2?y1:y2)-5,
(x1>x2?x1:x2)+5,
(y1>y2?y1:y2)+5),pt))
return FALSE;

//计算距离
double d;
double sq = sqrt(y1*y1+x1*x1);
if(sq==0)
{
d = sqrt(x*x+y*y);
}
else
d = fabs((y1-y2)*x+(x2-x1)*y+x1*y2-x2*y1)/sq;

if(d<5)
return TRUE;//误差值,也可以通过函数参数传进来。
else
return FALSE;
}
---------------------
我刚写的,测试通过
HuWenjin 2002-11-25
  • 打赏
  • 举报
回复
试一下吗 不试怎知呢?
WesleyWu 2002-11-25
  • 打赏
  • 举报
回复
但是效率和我的不是一个数量级的哦,毕竟acos和sin比起sqrt要慢许多啊。
icansaymyabc 2002-11-23
  • 打赏
  • 举报
回复
问这个问题的搂主,说明你没好好听数学课,不是好学生。
crazy_lazy_pig 2002-11-22
  • 打赏
  • 举报
回复
直线方程两点式(变形):(x1-x2)*(y-y1)=(x-x1)*(y1-y2)
整理成标准形式:A*x + B*y + C = 0
点(x0,y0)到直线的距离为:
abs(A*x0 + B*y0 + C)/sqrt(A^2 + B^2) (1)
两点间距离公式(略)。
若你认为公式(1)的结果不是你要的,则其结果与点(x0,y0)到线段两端点的距离中取最短的一个。

最后再强调一点,距离本来就是与坐标系位置、方向、角度无关的量,除非你把坐标系的单位长度改变。所以你在一个坐标下得到的结果等同于坐标平移、旋转后的结果
WesleyWu 2002-11-22
  • 打赏
  • 举报
回复
不好意思,我上面有个地方打错了

应该是:
计算出从原点出发到线段的垂足坐标(x3,y3),和它相应的t
判断垂足是否在线段上,如果是,结果就是|d|,否则,取线段两个端点到原点距离的最小值为结果。

result=min(x1*x1+y1*y1,x2*x2+y2*y2);
WesleyWu 2002-11-22
  • 打赏
  • 举报
回复
虽是一个平面,但不能直接用点到直线的距离阿。所以要加以判断线段内或线段外。
shenanigan 2002-11-22
  • 打赏
  • 举报
回复
一样学习
感觉是数学问题

一线中的两点 和线外或线内一点 ,不还是在一个平面里面的吗?
何必要这么麻烦?
RomanticProgrammer 2002-11-22
  • 打赏
  • 举报
回复
学习.
zyl910 2002-11-22
  • 打赏
  • 举报
回复
http://expert.csdn.net/Expert/topic/715/715509.xml?temp=.5165369
WesleyWu 2002-11-22
  • 打赏
  • 举报
回复
连acos都用上了,不用这么麻烦吧。


设线段(x1,y1)-(x2,y2),另一测试点为(x0,y0),result为本题要求的“这一点到这段线段的最短距离”的结果。

如果(x0,y0)不是原点,做相应的坐标变换,使得原坐标系中的(x0,y0)为新坐标系中的原点,x轴和y轴方向不变,单位长度不变。以下算法都认为测试点是原点。

首先,计算出从原点指向该线段所在直线的单位法向量n={nx,ny},以及线段所在直线到原点的有向距离d。
//////////////////////////////////////////////////
dx=x2-x1; dy=y2-y1;

if (dx!=0.0f)
{
ny=1.0f;
nx=-ny*dy/dx;
} else {
nx=1.0f;
ny=-nx*dx/dy;
}

l=1/sqrt(nx*nx+ny*ny);
nx*=l; ny*=l;

d=x1*nx+y1*ny;
//////////////////////////////////////////////////

把这个线段用参数形式表示,t为参数。
x=x1+t*(x2-x1)
y=y1+t*(y2-y1)
如果 0<=t<=1 则该点(x,y)在线段上,否则在线段外。

计算出从原点出发到线段的垂足坐标(x3,y3),和它相应的t
判断垂足是否在线段上,如果是,结果就是|d|,否则,取线段两个端点到原点距离的最大值为结果。
//////////////////////////////////////////////////
x3=d*nx; y3=d*ny;

t=(dx!=0.0f) ? (x3-x1)/dx : (y3-y1)/dy;

if (t>=0.0f && t<=1.0f)
{
result=fabs(d);
} else {
result=max(x1*x1+y1*y1,x2*x2+y2*y2);
result=sqrt(result);
}
//////////////////////////////////////////////////

给分吧 :)
HuWenjin 2002-11-22
  • 打赏
  • 举报
回复
要给分,要不再不回答了



//计算点 point 到线段 (lineX,lineY) 的距离,返回计算的距离值
float PointToLine(CPoint LineX,CPoint LineY,CPoint point)
{
float xx,yy,x1,y1,x2,y2;
xx = (float)point.x;
yy = (float)point.y;

x1 = (float)LineX.x;
y1 = (float)LineX.y;

x2 = (float)LineY.x;
y2 = (float)LineY.y;

float a,b,c,ang1,ang2,ang;
//计算三条边的距离
a=CalcTwoPointLong(LineX,point);if(a==0.0)return 0.0;
b=CalcTwoPointLong(LineY,point);if(b==0.0)return 0.0;
c=CalcTwoPointLong(LineX,LineY);
//如果(x1,y1)和(x2,y2)是一个点直接返回距离
if(c==0.0) return a;
if(a<b) //如果(xx,yy)的点(x1,y1)这条边较短
{
if(y1==y2)
{
if(x1<x2)
ang1=0;
else
ang1=(float)PAI;
}
else
{
ang1=(float)acos((x2-x1)/c);
if(y1>y2)ang1=(float)PAI*2-ang1; //直线(x1,y1)-(x2,y2)的弧度
}
ang2=(float)acos((xx-x1)/a);
if(y1>yy)ang2=(float)PAI*2-ang2; //直线(x1,y1)-(xx,yy)的弧度
ang=ang2-ang1;
if(ang<0)ang=-ang;
if(ang>PAI) ang=(float)PAI*2-ang; //交角的大小
if(ang>PAI/2) return a; //如果为钝角,直接返回距离
else
return (a*(float)sin(ang)); //否则返回计算得到的距离
}
else //如果(xx,yy)的点(x2,y2)这条边较短
{
if(y1==y2)
{
if(x1<x2)
ang1=(float)PAI;
else
ang1=0;
}
else
{
ang1=(float)acos((x1-x2)/c); //直线(x2,y2)-(x1,y1)的斜率的弧度
if(y2>y1)ang1=(float)PAI*2-ang1;
}
ang2=(float)acos((xx-x2)/b); //直线(x2,x1)-(xx,yy)的斜率的弧度
if(y2>yy)ang2=(float)PAI*2-ang2;
ang=ang2-ang1;
if(ang<0) ang=-ang;
if(ang>PAI) ang=(float)PAI*2-ang; //交角的大小 ?
if(ang>PAI/2) return b; //如果为钝角,直接返回距离
else
return(b*(float)sin(ang)); //否则返回计算得到的距离
}
}



#define PAI 3.1415926
GoldenEye 2002-11-22
  • 打赏
  • 举报
回复
在二维,应该这么说:
1、过这两点做与这个线段垂直的直线,形成一个“区域”,我们暂叫他“path”;
2、出现两种情况,一种就是这个点在path之外,这时所求必为线段两端点中的一个,另外一种就在path之内,利用普通的勾股定理就ok;

原理很简单,问题在于:线段方向是任意的,我们怎么知道这个点在path之内还是之外?
body 2002-11-22
  • 打赏
  • 举报
回复
1。过点做与线段所在直线垂直的平面。
2。求出平面与线段所在直线的交点。
3。如果交点位于线段上,交点为所求。
4。如果不是,所求必为线段两端点中的一个。
Aizz 2002-11-22
  • 打赏
  • 举报
回复

“但所有坐标方位、方向不定”--几维坐标系?
用勾股定理吧,是不是最简就不知道了。
rtdb 2002-11-22
  • 打赏
  • 举报
回复
只要在一个坐标系内, 此题与坐标方位、方向无关.

19,468

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧