距离问题(100分)

  • 主题发起人 主题发起人 xujincheng69
  • 开始时间 开始时间
X

xujincheng69

Unregistered / Unconfirmed
GUEST, unregistred user!
大富翁的朋友们,谁能帮我找一个能算出任意一个点到线段的最短距离、或点区域的最短距离,要做成函数形式。
 
如果经过点,不能画一条和线段垂直的线,则肯定是两个端点的某一个。
如果这样的垂直线存在,则肯定是交点!
 
我是想要一个最快的算法,点到直线我是有,可是点到线段却很麻烦。不知道能不能解决。
 
jsxjd说的对
 
to jsxjd
可以写个函数给我吗?
 
大侠们能帮帮我吗?
 
好象不是太简单!
我调试过了,你再调试一下。

function PointToLine(p,p1,p2:Tpoint):real;
// p 是点
// 线段是由点 p1,p2 表示的。
var
r1,r2,rX,Ry:Real;
x,y,A,B,C,A1,B1,C1:integer;
begin

x:=p.x-p1.x;
y:=p.y-p1.y;
r1:=sqrt(x*x+y*y);
Result:=r1;

if (p1.x=p2.x) and (p1.y=p2.y) then exit;
//如果p1 p2 重合,则就是 p 到 p1 的距离


if (p1.x=p2.x) then //垂直线的情况
if (p.y>=min(p1.y,p2.y)) and (p.y<=max(p1.y,p2.y))
then begin
Result:=abs(p1.x-p.x);
exit;
end;

if (p1.y=p2.y) then //水平线的情况
if (p.x>=min(p1.x,p2.x)) and (p.x<=max(p1.x,p2.x))
then begin
Result:=abs(p1.y-p.y);
exit;
end;

//其它情况,线段表示的Ax+By+C直线应为:
// (y2-y1)x + (x1-x2)y + (x2y1-x1y2)=0

A:=p2.y-p1.y;
B:=p1.x-p2.x;
C:=p2.x*p1.y-p1.x*p2.y;

//经过点 p 到线段所表示直线的垂直线的表示:
// A1x + B1y +C1 =0
A1:=B;
B1:=-A;
C1:=A*p.y-B*p.x;

rX:=(C1*b-C*B1)/(A*B1-A1*B);
rY:=-(A*rX+C)/B;

if (rX>=min(p1.x,p2.x)) and (rX<=max(p1.x,p2.x)) and
(rY>=min(p1.y,p2.y)) and (rY<=max(p1.y,p2.y)) then
begin
Result:=sqrt((p.x-rX)*(p.x-rX)+(p.y-rY)*(p.y-rY));
exit;
end;

x:=p.x-p2.x;
y:=p.y-p2.y;
r2:=sqrt(x*x+y*y);

if r2<result then result:=r2;

end;

procedure TForm1.Button4Click(Sender: TObject);
var
r:real;
begin
r:=PointToLine(point(0,0),point(1,-1),point(2,-1));
showmessage(floattostr(r));

r:=PointToLine(point(0,0),point(-1,-1),point(2,-1));
showmessage(floattostr(r));
end;
 
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;

type
TForm1 = class(TForm)
//第三点坐标
Edit1: TEdit;//x
Edit2: TEdit;//y
//线段两端点坐标//
Edit3: TEdit;//x
Edit4: TEdit;//y
Edit5: TEdit;//x
Edit6: TEdit;//y
//最短距离
Edit7: TEdit;
BitBtn1: TBitBtn;
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
x,y,z,Cos: Array[1..3] of real;

implementation

{$R *.dfm}

procedure TForm1.BitBtn1Click(Sender: TObject);
const E= 0.000000000001;
begin
//第三点坐标
x[1]:=StrToFloat(Edit1.Text);
y[1]:=StrToFloat(Edit2.Text);
//线段两端点坐标
x[2]:=StrToFloat(Edit3.Text);
y[2]:=StrToFloat(Edit4.Text);
x[3]:=StrToFloat(Edit5.Text);
y[3]:=StrToFloat(Edit6.Text);
{*********以下计算的几点说明:*******************
1,认为3点可以构成一个三角形,第三点在线段所在的直线上时,认为是两底角
有一个为0的三角形
2,顶点设为1,2,3其相对的边为1,2,3;如图:
1 。
2 3

3 。_________。 2
1
3,z[1],z[2],z[3] 分别为3条边的长,Cos[1],Cos[2],Cos[3]分别为三个角的余弦
4,原理:画三角形可以看出:两底角有一个为钝角时最短距离就是较短的边
两底角为锐角时则是三角形从点1到边1的高,两个底角都为0时,则距离为0
*********************************************************}
z[1]:=Sqrt((x[3]-x[2])*(x[3]-x[2])+(y[3]-y[2])*(y[3]-y[2]));
z[2]:=Sqrt((x[1]-x[3])*(x[1]-x[3])+(y[1]-y[3])*(y[1]-y[3]));
z[3]:=Sqrt((x[1]-x[2])*(x[1]-x[2])+(y[1]-y[2])*(y[1]-y[2]));
Cos[1]:=(z[2]*z[2]+z[3]*z[3]-z[1]*z[1])/(2*z[3]*z[2]);
Cos[2]:=(z[1]*z[1]+z[3]*z[3]-z[2]*z[2])/(2*z[1]*z[3]);
Cos[3]:=(z[1]*z[1]+z[2]*z[2]-z[3]*z[3])/(2*z[2]*z[1]);
if ((cos[2]>1-E)and(cos[3]>1-E)) then
Edit7.Text:= '0'
else if ((cos[2]<-E) or (Cos[3]<-E) ) then
begin
if z[2]<=z[3] then
Edit7.Text:= FloatToStr(z[2])
else
Edit7.Text:= FloatToStr(z[3])
end
else
Edit7.Text:= FloatToStr(z[2]*Sqrt((1-cos[3]*cos[3])));
end;

end.
 
你所谓的点区域是什么??
如果指点到区域的话,那就是点到线段的延伸
 
那点到区域怎么算呢?
怎么样得到区域边界的所有点。
 
不在区域里面,边是线段很好求,边是曲线,可能要和求积分一样吧!
设定步长取点,把曲线看成一段段的线段来求。
 
那一个点要和每个线段都要判断一下了?这样线段越多速也就越慢了。
有更的算法吗?
 
如果是多边形区域,那么可以转化为到各边(线段)的距离的最小值!!
 
我想了一下,多边形的话你先求出最靠近这点的区域的顶点,规则曲线区域的话
(如圆,椭圆等)中心和点的连线与区域边界的交点,不规则的曲线还是要利用求
积分的方法,这样就太不通用了
还是利用求积分一样的求法吧。。。。。。。。。。
 
还有更好的算法吗?
 
呵呵,看看别人怎么说吧
 
求积分行吗?
 
后退
顶部