用矢量变换的方法求两条直线的交点

求两条直线的交点,最常见的写法是列出两条直线的方程,联立求解。
    但这种办法的弊端很大:
    1 )算法是坐标系相关的,要考虑直线是水平还是垂直,写出很多判断条件,增加了程序的不稳定性
   2)即使两直线都是斜的,只要接近水平或者垂直,也会带来过大的误差,导致计算失败
      出现这种问题的核心是联立方程无法做到坐标系无关,总要把求交点的几何问题绑定到坐标系。
    从本质上讲,两条直线的交点是几何图形的内在性质,不依赖于坐标系。用矢量变换的方式来求交点,可以避免求解直线方程,也不用判断直线是否水平垂直,能真正做到坐标系无关。类似的算法还可以推广到求直线和圆的交点、圆和圆的交点、直线和椭圆的交点等等。
以下是用delphi编写的用矢量变换的方法求两条直线交点的程序。
该程序不仅能求出交点坐标,还能判断直线是否通过交点,因为有时候交点在延长线上。
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons;
type
  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    procedure BitBtn1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    CalInterPoint(x1, y1, x2, y2, x3, y3, x4, y4: Double;
      var xj, yj: Double): integer;
    calPro(vx1, vy1, vx2, vy2: Double): Double;
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
{ TForm1 }
TForm1.CalInterPoint(x1, y1, x2, y2, x3, y3, x4, y4: Double;
  var xj, yj: Double): integer;
{-----------------------------------------------------------------------------
  函数名: CalInterPoint
  作者 : 陈新中
  时间 : 2002-8-28
  参数 :  (x1,y1,x2,y2)是一条直线
           (x3,y3,x4,y4)是另一条直线
  返回值:  >=0 相交 包含1表示交点在12上包含2表示交点在34上
                    四种组合
                    0 两条直线都不通过交点
                    1 直线12通过 ,直线34不通过
                    2 直线34通过 ,直线12不通过
                    3 直线12和34都通过
           -1 平行
  功能 : 该函数计算直线的交点
-----------------------------------------------------------------------------}
var
  px12, py12, //直线12的方向矢量
    px34, py34, //直线34的方向矢量
    t12, t34, //12 和34的长度
    nx12, ny12, //直线12的单位矢
    nx34, ny34, //直线34的单位矢
    px13, py13, //13连线矢量
    ty, //13连线矢量在直线12上的投影
    tysx, tysy, //13连线矢量在直线12上的投影矢量
    czsx, czsy, //3到12的垂线矢量
    cossit, //垂线矢跟直线34方向矢的夹角余弦
    sux, suy, //3到交点的连线矢量
    czL, //垂线长度
    gene: //变换因子
  Double;
begin
  px12 := x2 - x1; //12连线矢量
  py12 := y2 - y1;
  px34 := x4 - x3; //34连线矢量
  py34 := y4 - y3;
  //如果矢积为0,则说明平行,置平行标志,返回
  if px12 * py34 - px34 * py12 = 0 then
  begin
    Result := -1;
    exit;
  end;
  if (x3 - x1) * (y3 - y2) + (x3 - x2) * (y3 - y1) = 0 then
  begin //如果3正好落在直线12上,交点为 (x3,x4)
    xj := x3;
    yj := y3;
  end
  else
  begin
    t12 := sqrt(px12 * px12 + py12 * py12); //12长度
    t34 := sqrt(px34 * px34 + py34 * py34); //34长度
    nx12 := px12 / t12; //12单位矢
    ny12 := py12 / t12;
    nx34 := px34 / t34; //34单位矢
    ny34 := py34 / t34;
    px13 := x3 - x1; //13连线矢
    py13 := y3 - y1;
    ty := px13 * nx12 + py13 * ny12; //投影
    tysx := ty * nx12; //投影矢量
    tysy := ty * ny12;
    czsx := tysx - px13; //垂线矢
    czsy := tysy - py13;
    czL := sqrt(czsx * czsx + czsy * czsy); //垂线长度
    gene := czL / calPro(x4 - x3, y4 - y3, czsx, czsy); //变换因子
    xj := x3 + px34 * gene;
    yj := y3 + py34 * gene;
  end;
  Result := 0;
  if (x1 - xj) * (x2 - xj) + (y1 - yj) * (y2 - yj) < 0 then
    Result := Result + 1; //判断是否在直线12上
  if (x3 - xj) * (x4 - xj) + (y3 - yj) * (y4 - yj) < 0 then
    Result := Result + 2; //判断是否在直线34上
end;

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  x1, y1, x2, y2, x3, y3, x4, y4: double;
  xo, yo: double;
  ret: integer;
  info: string;
begin
  x1 := 150;
  y1 := 150;
  x2 := 200;
  y2 := 200;
  x3 := 200;
  y3 := 100;
  x4 := 0;
  y4 := 150;
  Form1.Canvas.MoveTo(round(x1), round(y1));
  Form1.Canvas.LineTo(round(x2), round(y2));
  Form1.Canvas.MoveTo(round(x3), round(y3));
  Form1.Canvas.LineTo(round(x4), round(y4));
  ret := CalInterPoint(x1, y1, x2, y2, x3, y3, x4, y4, xo, yo);
  Form1.Canvas.Ellipse(round(xo - 10), round(yo - 10), round(xo + 10), round(yo + 10));
  info := '';
  if (ret and 1) > 0 then
  begin
    info := info + '交点在直线12上 ';
  end
  else
  begin
    info := info + '交点不在直线12上 ';
  end;
  if (ret and 2) > 0 then
  begin
    info := info + '交点在直线34上 ';
  end
  else
  begin
    info := info + '交点不在直线34上 ';
  end;
  ShowMessage(info);
end;

TForm1.calPro(vx1, vy1, vx2, vy2: Double): Double;
// 求矢量的投影 矢量v1在v2上的投影 (vx1, vy1)是矢量v1 (vx2, vy2)是矢量v2
begin
  result := (vx1 * vx2 + vy1 * vy2) / sqrt(vx2 * vx2 + vy2 * vy2);
end;
end.

猜你喜欢

转载自blog.csdn.net/wflishh/article/details/2293071