求兩條直線的交點,最常見的寫法是列出兩條直線的方程,聯立求解。
但這種辦法的弊端很大:
1 )演算法是座標系相關的,要考慮直線是水平還是垂直,寫出很多判斷條件,增加了程式的不穩定性
2)即使兩直線都是斜的,只要接近水平或者垂直,也會帶來過大的誤差,導致計算失敗
出現這種問題的核心是聯立方程無法做到座標系無關,總要把求交點的幾何問題繫結到座標系。
從本質上講,兩條直線的交點是幾何圖形的內在性質,不依賴於座標系。用向量變換的方式來求交點,可以避免求解直線方程,也不用判斷直線是否水平垂直,能真正做到座標系無關。類似的演算法還可以推廣到求直線和圓的交點、圓和圓的交點、直線和橢圓的交點等等。
以下是用delphi編寫的用向量變換的方法求兩條直線交點的程式。
該程式不僅能求出交點座標,還能判斷直線是否通過交點,因為有時候交點在延長線上。
unit unit1;
inte***ce
uses
windows, messages, sysutils, variants, classes, graphics, controls, forms,
dialogs, stdctrls, buttons;
type
tform1 = class(tform)
bitbtn1: tbitbtn;
procedure bitbtn1click(sender: tobject);
private
public
calinterpoint(x1, y1, x2, y2, x3, y3, x4, y4: double;
var xj, yj: double): integer;
calpro(vx1, vy1, vx2, vy2: double): double;
end;
varform1: tform1;
implementation
tform1.calinterpoint(x1, y1, x2, y2, x3, y3, x4, y4: double;
var xj, yj: double): integer;
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;
endelse
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);
varx1, 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上 ';
endelse
begin
info := info + '交點不在直線12上 ';
end;
if (ret and 2) > 0 then
begin
info := info + '交點在直線34上 ';
endelse
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.
求兩條直線(線段)的交點
如圖,如何求得直線 ab 與直線 cd的交點p?以上內容摘自 演算法藝術與資訊學競賽 思路就是利用叉積求得點p分線段dc的比,然後利用高中學習的定比分點座標公式求得分點p的座標。看不懂的可以去複習下 定比分點 的知識。include include include include using nam...
求兩條直線的關係及交點
給你兩條直線,判斷這兩條直線是否共線,相交,不相交 即平行 相交的話輸出交點。判斷平行,然後通過叉積判斷是否共線。平行判斷可以判斷兩條直線的斜率是否相等。交點的話,相當於聯立方程組求解了。這些方程看模板理解的,剛才搜了下,有人講得比較清楚,借鑑下 如何判斷是否同線?由叉積的原理知道如果p1,p2,p...
求空間兩條直線之間的距離
1.前言 最近老闆讓寫一段空間點匹配的 其中涉及到求空間兩直線之間的距離,寫起來滿費勁的,這裡做乙個記錄。2.處理思路 空間兩直線之間的位置關係主要可以分為 重合,平行,相交,異面。2.1 異面情形 含相交 已知空間中兩線段,如果它們無限變粗,判斷是否相交。主要討論不在同一平面的情況 線段ab 線段...