二维计算几何基础知识
1.點積:
向量點積的定義:(x1,y1)*(x2,y2)=x1*x2+y1*y2;滿足交換律
向量點積的代數意義:向量V1的模 * 向量V2的模 * cos<V1,V2>
向量點積的幾何意義:α在β的投影α’與β的長度乘積
2.叉積
向量叉積定義:(x1,y1) x (x2,y2) =x1*y2 - x2*y1;滿足反交換律;
向量叉積幾何意義:有向面積
叉積大小為兩向量圍成的平行四邊形的有向面積
結論:flag=a x b
3.兩線段判交
在平面上兩直線,有平行、重合、相交三種關系
若兩條線段所在的直線平行,則兩條線段平行
兩條線段p1p2和Q1Q2相交的必要條件:(P2-P1) x (Q1-P1) * (P2-P1) x (Q2-P1) <= 0
還有這兩種情況:
在左圖中只滿足了一個“跨立”條件,即Q1和Q2在直線P1P2的兩側,于是我們應該做兩次跨立實驗才能保證它們是相交的;
而右圖則是邊界條件的特殊情況,不方便用跨立實驗來判斷;
不過通過觀察兩張圖后,我們發現:當兩線段不相交時,以這兩條線段為對角線的格點矩形沒有交集!
于是我們可以借助這一點來增加判交條件以保證算法的正確性,我們稱之為快速排斥實驗,如下圖:
線段的規范相交和非規范相交
#include <stdio.h> #include <math.h> #include <algorithm> #include <string.h> #include <math.h> using namespace std;const double eps = 1e-8; //三態函數:減少浮點數誤差 int sgn(double x) {if(fabs(x) < eps)return 0;if(x < 0)return -1;else return 1; } struct Point {double x,y;Point(){}Point(double _x,double _y){x = _x;y = _y;}Point operator -(const Point &b)const{return Point(x - b.x,y - b.y);}//叉積double operator ^(const Point &b)const{return x*b.y - y*b.x;}//點積double operator *(const Point &b)const{return x*b.x + y*b.y;} }; struct Line {Point s,e;Line(){}Line(Point _s,Point _e){s = _s;e = _e;}//兩直線相交求交點//第一個值為0表示直線重合,為1表示平行,為0表示相交,為2是相交//只有第一個值為2時,交點才有意義pair<int,Point> operator &(const Line &b)const{Point res = s;if(sgn((s-e)^(b.s-b.e)) == 0){if(sgn((s-b.e)^(b.s-b.e)) == 0)return make_pair(0,res);//重合else return make_pair(1,res);//平行}double t = ((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));res.x += (e.x-s.x)*t;res.y += (e.y-s.y)*t;return make_pair(2,res);} };//判斷線段相交 bool inter(Line l1,Line l2) {return//快速排斥實驗max(l1.s.x,l1.e.x) >= min(l2.s.x,l2.e.x) &&max(l2.s.x,l2.e.x) >= min(l1.s.x,l1.e.x) &&max(l1.s.y,l1.e.y) >= min(l2.s.y,l2.e.y) &&max(l2.s.y,l2.e.y) >= min(l1.s.y,l1.e.y) &&//跨立實驗sgn((l2.s-l1.e)^(l1.s-l1.e))*sgn((l2.e-l1.e)^(l1.s-l1.e)) <= 0 &&sgn((l1.s-l2.e)^(l2.s-l2.e))*sgn((l1.e-l2.e)^(l2.s-l2.e)) <= 0; }//向量的模 typedef Point Vector; double Length(Vector A){return sqrt(A*A); }//求向量A和向量B的夾角,弧度制 double Angle(Vector A,Vector B) {return acos((A*B)/Length(A)/Length(B)); }4.判斷直線和線段相交
//判斷直線L1和線段L2相交 bool seg_inter_line(Line L1,Line L2) {return sgn((L2.s-L1.e)^(L1.s-L1.e))*sgn((L2.e-L1.e)^(L1.s-L1.e))<=0; }利用叉積計算點到直線距離
//利用叉積計算:點到直線距離 double DisLine(Line l,Point p) {Vector v1=p-l.s,v2=l.s-l.e;return fabs(v1*v2)/Length(v2);//平行四邊形的面積除以底邊即平行四邊形的高 }?點到線段的距離
點到線段距離的計算根據點與直線的位置分為兩大類 (第二類分為兩小類)
1,如左圖所示,如果點與線段的垂直線與線段所在直線 的交點在線段上,所求的距離就是點到線段的距離
2,如右圖所示,如果是在射線上,就是點到射線一端的 距離,圖中點到線段的距離就是P到A的距離
dsy的模板?
double DisSegment(Point P,Point A,Point B) {if(sgn(A.x-B.x)==0&&sgn(A.y-B.y)==0)//兩點重合return Length(A-P);//兩點之間的距離Vector v1=B-A,v2=P-A,v3=P-B;//p點投影到射線if(sgn(v1*v2)<0) return Length(v2);if(sgn(v1*v3)>0) return Length(v3);//p點投影到線段return fabs(v1*v2)/Length(v2);//點到直線距離 }kuangbin的模板?
//兩點距離 double dist(Point a,Point b) {return sqrt((a-b)*(a-b)); }//點到線段的距離,返回點到線段最近的點 Point NearestPointToLineSeg(Point p,Line L) {Point result;double t=((p-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s));if(t>=0&&t<=1){result.x=L.s.x+(L.e.x-L.s.x)*t;result.y=L.s.y+(L.e.y-L.s.y)*t;}else{if(dist(p,L.s)<dist(p,L.e))result=L.s;elseresult=L.e;}return result; }判斷凸多邊形
//判斷凸多邊形,允許共線邊 //點的編號0~n-1,可以是順時針和逆時針 bool isConvex(Point poly[],int n){bool s[3];memset(s,false,sizeof s);for(int i=0;i<n;i++){s[sgn( (poly[(i+1)%n]-poly[i])^(poly[(i+2)%n]-poly[i]) )+1]=true;if(s[0]&&s[2]) return false;}return true; }?
總結
以上是生活随笔為你收集整理的二维计算几何基础知识的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: POJ 2826 An Easy Pro
- 下一篇: POJ 1584 A Round Peg