[計算幾何] 點與線段的位置 向量法
阿新 • • 發佈:2018-12-11
給出點A、B的座標, 構成線段AB, 再給出一點P的座標, 判斷點P與線段AB的位置關係
如下圖, 點P與AB的關係可分為5種情況
(1) 點P線上段AB的順時針方向
(2) 點P線上段AB的逆時針方向
(3) 點P線上段AB的反向延長線上
(4) 點P線上段AB的延長線上
(5) 點P線上段AB上
為了更好的解決此類問題, 藉助兩個工具: 向量的外積(叉積)和向量的內積(點積)
向量的外積(叉積)
用的形式表示兩個向量, 則 與 的外積為
(可通過矩陣匯出)
在二維平面上, , 所以二維平面上向量的外積的大小為
向量的內積(點積)
點與線段位置的判定標準
1. 如果向量AB與向量AP的外積(叉積)為正, 則點P線上段AB的逆時針方向, 如上圖(1)
2. 如果向量AB與向量AP的外積(叉積)為負, 則點P線上段AB的順時針方向, 如上圖(2)
在上兩種情況都不滿足的情況下(討論完外積(叉積), 下面討論內積(點積))
注意: 必須上兩種情況不滿足才討論以下情況
3. 如果向量AB與向量AP的內積(點積)為負, 則點P線上段AB的反向延長線上, 如上圖(3)
4. 如果向量AB與向量AP的內積(點積)為非負, 有兩種情況分別為上圖(4) 和 (5)
4.1. 如果向量AB的模|AB|小於向量AP的模|AP|, 則點P線上段AB的延長線上, 如上圖(4)
4.2. 如果向量AB的模|AB|等於或小於向量AP的模|AP|, 則點P線上段AB上, 如上圖(5) (|AB|=|AP|時, P點與B點重合)
程式程式碼
#include<iostream> #include<cmath> using namespace std; typedef struct node { double x, y; }NODE; double cross(NODE A, NODE B, NODE P) //計算向量AB與AP的外積(叉積)的大小(不包括方向) { NODE AB = { B.x - A.x, B.y - A.y }; NODE AP = { P.x - A.x, P.y - A.y }; return AB.x*AP.y - AB.y*AP.x; } double dot(NODE A, NODE B, NODE P) //計算向量AB與向量AP的內積(點積) { NODE AB = { B.x - A.x, B.y - A.y }; NODE AP = { P.x - A.x, P.y - A.y }; return AB.x*AP.x + AB.y*AP.y; } double mol(NODE a,NODE b) //求向量ab的模(也可以說是點a、b的距離) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } int dir(NODE A,NODE B,NODE P) //判斷點P線上段AB的哪個方向上 { if (cross(A, B, P) > 0) return 1; //外積大於0,點p線上段AB的逆時針方向 else if (cross(A, B, P) < 0) return 2; //外積小於0,點p線上段AB的順時針方向 else if (dot(A, B, P) < 0) return 3; //內積小於0,點p線上段AB的反延長線上 else if (dot(A, B, P)>=0) //內積大於0,分兩種情況 { if (mol(A, B) < mol(A, P)) return 4; //如果AB的模小於AP的模, 那麼p線上段AB的延長線上 else return 5; //p線上段AB上 } } int main() { NODE A, B, P; cin >> A.x >> A.y; cin >> B.x >> B.y; int q; cin >> q; while (q--) { cin >> P.x >> P.y; if (dir(A, B, P) == 1) cout << "COUNTER_CLOCKWISE" << endl; //逆時針 else if (dir(A, B, P) == 2) cout << "CLOCKWISE" << endl; //順時針 else if (dir(A, B, P) == 3) cout << "ONLINE_BACK" << endl; //反向延長線 else if (dir(A, B, P) == 4) cout << "ONLINE_FRONT" << endl; //延長線 else if (dir(A, B, P) == 5) cout << "ON_SEGMENT" << endl; //線段上 } return 0; }
如果覺得本文對你有啟發, 不妨贊一下, 在精神上鼓勵鼓勵博主;
如果有不懂的地方, 可以在下方留言, 博主一看到便會馬上回復;
如果發現本文有錯誤的地方, 歡迎指正。