一个和解析几何有点关系的问题!大家都来啊! ( 积分: 300 )

  • 主题发起人 主题发起人 wk_knife
  • 开始时间 开始时间
W

wk_knife

Unregistered / Unconfirmed
GUEST, unregistred user!
共一个端点的两条线段,各有分在两侧的一定距离H的平行线,这四条平行线相交出四个交点。如何判断四个交点中哪个点在线段所夹的方向。

具体见下图,也就是找到实线段所夹的红色点。
http://www.delphibbs.com/keylife/images/u81530/未命名.bmp

我现在的办法是先通过y=A*X+B
得出平行线的PB:=B +(or -) H/cos(arctg(A));
再得到四个角点。

一开始我觉得只要判断四个点中有哪个点落到线段构成的三角形中就可以了,后来发现这个想法是错误的。如果线段很短,就不会有任一个点落到这个三角形中。

下面是现在的代码:
unit Unit1;

interface

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

type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private declarations }
public
{ Public declarations }
P0,P1,P2,px1,px2,px3,px4:TPoint;
sum:integer;
function GetAB(pA,pB:TPoint;var A,B:Double):Boolean;
procedure GetABParaDeltaB(pA,pB,pC:TPoint;H:Double);
end;

var
Form1: TForm1;

implementation

uses Math;

{$R *.dfm}

function TForm1.GetAB(pA, pB: TPoint; var A, B: Double):Boolean;
begin
result:=False;
if pA.x <>pB.x then
begin
A:=(pB.Y-pA.Y)/(pB.X-pA.X);
B:=pA.y-A*PA.X;
result:=True;
end;
end;

procedure TForm1.GetABParaDeltaB(pA,pB,pC:TPoint;H:Double);
var
A,B,R,C,D,RP:Double;
First,Second:Boolean;
ARgn:HRgn;
AA:array of TPoint;
InRgn:integer;
begin
canvas.MoveTo(PA.X, pA.Y);
Canvas.LineTo(pB.X ,pB.Y);
Canvas.LineTo(pC.X ,pC.Y);
First:=GetAB(pA,pB,A,B);
if First then
R:=H/cos(ArcTan(A));
Second:=GetAB(pB,pC,C,D);
if Second then
RP:=H/cos(ArcTan(C));

SetLength(AA,3);
AA[0]:=pA;
AA[1]:=pB;
AA[2]:=pC;
ARgn:=CreatePolygonRgn(AA[0],3,WINDING);

pX1.X:=Round((d-rp-b+r)/(a-c)); //-r-r'
px1.Y:=Round(a*px1.X+B-r);
if PtInRegion(ARgn,pX1.X,px1.Y) then begin
Canvas.Pen.Color:=clRed;
Canvas.Rectangle(px1.X-2,px1.Y-2,px1.X+2,px1.Y+2);
Canvas.Pen.Color:=clBlack;
InRgn:=1;
end
else
Canvas.Rectangle(px1.X-2,px1.Y-2,px1.X+2,px1.Y+2);

pX2.X:=Round((d+rp-b+r)/(a-c)); //-r+r'
px2.Y:=Round(a*px2.X+B-r);
if PtInRegion(ARgn,pX2.X,px2.Y) then begin
Canvas.Pen.Color:=clRed;
Canvas.Rectangle(px2.X-2,px2.Y-2,px2.X+2,px2.Y+2);
Canvas.Pen.Color:=clBlack;
InRgn:=2;
end
else
Canvas.Rectangle(px2.X-2,px2.Y-2,px2.X+2,px2.Y+2);


pX3.X:=Round((d-rp-b-r)/(a-c)); //+r-r'
px3.Y:=Round(a*px3.X+B+r);
if PtInRegion(ARgn,pX3.X,px3.Y) then begin
Canvas.Pen.Color:=clRed;
Canvas.Rectangle(px3.X-2,px3.Y-2,px3.X+2,px3.Y+2);
Canvas.Pen.Color:=clBlack;
InRgn:=3;
end
else
Canvas.Rectangle(px3.X-2,px3.Y-2,px3.X+2,px3.Y+2);


pX4.X:=Round((d+rp-b-r)/(a-c)); //+r+r'
px4.Y:=Round(a*px4.X+B+r);
if PtInRegion(ARgn,pX4.X,px4.Y) then begin
Canvas.Pen.Color:=clRed;
Canvas.Rectangle(px4.X-2,px4.Y-2,px4.X+2,px4.Y+2);
Canvas.Pen.Color:=clBlack;
InRgn:=4;
end
else
Canvas.Rectangle(px4.X-2,px4.Y-2,px4.X+2,px4.Y+2);
DeleteObject(ARgn);

case InRgn of //
1,4: begin
canvas.MoveTo(Px1.X, px1.Y);
Canvas.LineTo(px4.X ,px4.Y);
end;

2,3:begin
canvas.MoveTo(Px2.X, px2.Y);
Canvas.LineTo(px3.X ,px3.Y);
end ;
end; // case
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
sum:=0;
DoubleBuffered:=True;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
Canvas.Pen.Color :=clBlack;
case sum of //
1: Canvas.Rectangle(p0.X-2,p0.Y-2,p0.X+2,p0.Y+2);
2: begin
Canvas.Rectangle(p0.X-2,p0.Y-2,p0.X+2,p0.Y+2);
Canvas.Rectangle(p1.X-2,p1.Y-2,p1.X+2,p1.Y+2);
end;
3: begin
Canvas.Rectangle(p0.X-2,p0.Y-2,p0.X+2,p0.Y+2);
Canvas.Rectangle(p1.X-2,p1.Y-2,p1.X+2,p1.Y+2);
Canvas.Rectangle(p2.X-2,p2.Y-2,p2.X+2,p2.Y+2);
GetABParaDeltaB(p0,p1,p2,20);
end;
end; // case
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
inc(Sum);
case sum of //
1,4:begin
Sum:=1;
P0:=Point(x,y);
end;
2: P1:=Point(x,y);
3: P2:=Point(x,y);
end;
invalidate;
end;

end.
 
共一个端点的两条线段,各有分在两侧的一定距离H的平行线,这四条平行线相交出四个交点。如何判断四个交点中哪个点在线段所夹的方向。

具体见下图,也就是找到实线段所夹的红色点。
http://www.delphibbs.com/keylife/images/u81530/未命名.bmp

我现在的办法是先通过y=A*X+B
得出平行线的PB:=B +(or -) H/cos(arctg(A));
再得到四个角点。

一开始我觉得只要判断四个点中有哪个点落到线段构成的三角形中就可以了,后来发现这个想法是错误的。如果线段很短,就不会有任一个点落到这个三角形中。

下面是现在的代码:
unit Unit1;

interface

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

type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private declarations }
public
{ Public declarations }
P0,P1,P2,px1,px2,px3,px4:TPoint;
sum:integer;
function GetAB(pA,pB:TPoint;var A,B:Double):Boolean;
procedure GetABParaDeltaB(pA,pB,pC:TPoint;H:Double);
end;

var
Form1: TForm1;

implementation

uses Math;

{$R *.dfm}

function TForm1.GetAB(pA, pB: TPoint; var A, B: Double):Boolean;
begin
result:=False;
if pA.x <>pB.x then
begin
A:=(pB.Y-pA.Y)/(pB.X-pA.X);
B:=pA.y-A*PA.X;
result:=True;
end;
end;

procedure TForm1.GetABParaDeltaB(pA,pB,pC:TPoint;H:Double);
var
A,B,R,C,D,RP:Double;
First,Second:Boolean;
ARgn:HRgn;
AA:array of TPoint;
InRgn:integer;
begin
canvas.MoveTo(PA.X, pA.Y);
Canvas.LineTo(pB.X ,pB.Y);
Canvas.LineTo(pC.X ,pC.Y);
First:=GetAB(pA,pB,A,B);
if First then
R:=H/cos(ArcTan(A));
Second:=GetAB(pB,pC,C,D);
if Second then
RP:=H/cos(ArcTan(C));

SetLength(AA,3);
AA[0]:=pA;
AA[1]:=pB;
AA[2]:=pC;
ARgn:=CreatePolygonRgn(AA[0],3,WINDING);

pX1.X:=Round((d-rp-b+r)/(a-c)); //-r-r'
px1.Y:=Round(a*px1.X+B-r);
if PtInRegion(ARgn,pX1.X,px1.Y) then begin
Canvas.Pen.Color:=clRed;
Canvas.Rectangle(px1.X-2,px1.Y-2,px1.X+2,px1.Y+2);
Canvas.Pen.Color:=clBlack;
InRgn:=1;
end
else
Canvas.Rectangle(px1.X-2,px1.Y-2,px1.X+2,px1.Y+2);

pX2.X:=Round((d+rp-b+r)/(a-c)); //-r+r'
px2.Y:=Round(a*px2.X+B-r);
if PtInRegion(ARgn,pX2.X,px2.Y) then begin
Canvas.Pen.Color:=clRed;
Canvas.Rectangle(px2.X-2,px2.Y-2,px2.X+2,px2.Y+2);
Canvas.Pen.Color:=clBlack;
InRgn:=2;
end
else
Canvas.Rectangle(px2.X-2,px2.Y-2,px2.X+2,px2.Y+2);


pX3.X:=Round((d-rp-b-r)/(a-c)); //+r-r'
px3.Y:=Round(a*px3.X+B+r);
if PtInRegion(ARgn,pX3.X,px3.Y) then begin
Canvas.Pen.Color:=clRed;
Canvas.Rectangle(px3.X-2,px3.Y-2,px3.X+2,px3.Y+2);
Canvas.Pen.Color:=clBlack;
InRgn:=3;
end
else
Canvas.Rectangle(px3.X-2,px3.Y-2,px3.X+2,px3.Y+2);


pX4.X:=Round((d+rp-b-r)/(a-c)); //+r+r'
px4.Y:=Round(a*px4.X+B+r);
if PtInRegion(ARgn,pX4.X,px4.Y) then begin
Canvas.Pen.Color:=clRed;
Canvas.Rectangle(px4.X-2,px4.Y-2,px4.X+2,px4.Y+2);
Canvas.Pen.Color:=clBlack;
InRgn:=4;
end
else
Canvas.Rectangle(px4.X-2,px4.Y-2,px4.X+2,px4.Y+2);
DeleteObject(ARgn);

case InRgn of //
1,4: begin
canvas.MoveTo(Px1.X, px1.Y);
Canvas.LineTo(px4.X ,px4.Y);
end;

2,3:begin
canvas.MoveTo(Px2.X, px2.Y);
Canvas.LineTo(px3.X ,px3.Y);
end ;
end; // case
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
sum:=0;
DoubleBuffered:=True;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
Canvas.Pen.Color :=clBlack;
case sum of //
1: Canvas.Rectangle(p0.X-2,p0.Y-2,p0.X+2,p0.Y+2);
2: begin
Canvas.Rectangle(p0.X-2,p0.Y-2,p0.X+2,p0.Y+2);
Canvas.Rectangle(p1.X-2,p1.Y-2,p1.X+2,p1.Y+2);
end;
3: begin
Canvas.Rectangle(p0.X-2,p0.Y-2,p0.X+2,p0.Y+2);
Canvas.Rectangle(p1.X-2,p1.Y-2,p1.X+2,p1.Y+2);
Canvas.Rectangle(p2.X-2,p2.Y-2,p2.X+2,p2.Y+2);
GetABParaDeltaB(p0,p1,p2,20);
end;
end; // case
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
inc(Sum);
case sum of //
1,4:begin
Sum:=1;
P0:=Point(x,y);
end;
2: P1:=Point(x,y);
3: P2:=Point(x,y);
end;
invalidate;
end;

end.
 
将交点坐标分别代入方程(每个方程代表一条直线),同时满足两个方程的即为交点.
 
太难了,说点思路

求角度如何,角度在中间的就是,比如A, B, C三个点,BA和BC与x轴角度,然后4个点分别和B求角度
 
呵阿,俺是学数学的:
四条平行线有四个方程,同时两条相交线段也有两个方程(当然这两个方程是有限制的),
这时放宽它们的限制,求出这两条线段和相关的两条平行线的焦点,看看那两个点在哪两条平行线上,然后根据那两条平行线再求出一个焦点便是你所求的焦点了。
 
假设你的公共点为 点O ,两条线段分别为 线段OA 和 线段OB
为了方便计算,我们把 点O 看作坐标原点,
把 线段OA 看成是方向是从O到A的向量,记为 向量OA
把 线段OB 看成是方向是从O到B的向量,记为 向量OB
同 线段OA 平行的且距离 线段OA 为H的两条平行线中的一条一定会与 线段OB 或其延长线(从O到B方向的延长)相交,其交点所代表的向量,我们记为 向量OBH,
同样,同 线段OB 平行的且距离 线段OB 为H的两条平行线中的一条一定会与 线段OA 或其延长线(从O到A方向的延长)相交,其交点所代表的向量,我们记为 向量OAH,
则,你所说的那个点,就是 向量OAH + 向量OBH
 
关键问题是不好确定是哪两条平行线能交出需要的点!我一开始就是这样的做的。
后来发现这样比较困难,判断太多,所以才想到先得到四个交点,然后判断交点的位置。
一开始Demo里的线段画的比较长,感觉问题解决了,后来画的短了才发现问题。

我这个问题其实是要做当画笔宽度大于1时,两条线段相交时,端点的模式类似于PS_JOIN_MITER,是相交出一个尖角,而不是方头的。因为我是做的自定义线型,
所以不能直接用PS_JOIN_MITER。
也就是下面右图的效果,而不是左面的。
http://www.delphibbs.com/keylife/images/u81530/123.bmp
 
那就取向量的夹角,假设你要的那个交点是H,则,向量OH与向量OA的夹角加上向量OH与向量OB的夹角应该等于向量OA和向量OB的夹角。
 
如果是像你刚刚说的那样,那问题就更简单了,先将向量OA和向量OB相加,得到的向量OH,向量OH所代表的那条直线方程,就应该穿过你想要的那两个点(一个在原来的两条直线外面,一个在原来的两条直线内部),把4个点分别代入直线方程,哪个能让等式成了,哪个就是你要的点。不过这其中的计算需要使用浮点数而不是整数,要不然会不准确。
两个浮点数比较最好是让两个数作差,当这个差小于一定的范围的时候,就可以认为两个浮点数相等
 
或者,你用计算出来的4个交点作顶点,画一个菱形,然后用你线条的颜色填充这个菱形就可以了,没必要去判断点的相对位置。
 
我已经有想法了,等实验后再说!
 
后退
顶部