計算幾何--平面向量(1)
弧度
弧度π=角度180°
坐標表示法(a,b)的含義
大概就是:從(0,0)向(a,b)連一條有向線段,它表示的向量就與向量(a,b)相等。
或者:$(a,b)=ai+bj$,就是正交分解成兩個分別與x、y軸同向的單位向量
點b與點a相減
直接兩組坐標對應減即可,得到向量,得到一個方向為a到b的方向,長度為a與b的直線距離的向量
向量與數的乘/除
直接兩個坐標乘/除該數字即可,得到向量,幾何意義:方向不變,長度乘/除(本文中*號表示數乘)
點與向量的加/減
直接兩組坐標對應加/減即可,得到點,幾何意義:以該點為起點,沿著向量方向移動向量長度
向量與向量的加/減
直接兩組坐標對應加/減即可,得到向量,幾何意義:滿足平行四邊形法則/三角形法則
向量相同
長度相等且方向相同
向量共線(或稱“平行”)
就是方向相同或相反,長度不管。判定:叉積為0
向量a與向量b的內積/點積/數量積(?)(返回一個數量)
a的長度*b的長度*cos夾角,$a{\cdot}b=|a||b|cos\theta$
這裏的夾角指從a到b逆時針旋轉的角,因此夾角絕對值大於90°時點積為負。
($cos{\theta}$圖像)
幾何意義:a的長度*b在a的方向上的投影
滿足:
交換律,分配律,結合律(可以幾何證明)
垂直向量的內積為0。
a與b同向,那麽內積等於長度的乘積。
a與b反向,那麽內積等於長度乘積的相反數。
坐標計算:
設$a=x1*i+y1*j,b=x2*i+y2*j$,
那麽$a{\cdot}b=(x1*i+y1*j){\cdot}(x2*i+y2*j)$
$=x1*x2*i^2+x1*y2*i*j+y1*x2*i*j+y1*y2*j^2$
由於i,j垂直且長度為1,那麽$i^2=j^2=1$,$i{\cdot}j=j{\cdot}i=0$
所以$a{\cdot}b=x1*x2+y1*y2$
向量夾角
用內積計算式變換一下即可。
${\theta}=a{\cdot}b/(|a||b|)$
向量長度(也叫“模”)
就是自身內積開平方根。
$|a|=\sqrt{a{\cdot}a}$
也可以理解為勾股定理。
向量a與向量b的叉積/外積(×)(返回一個向量)
(似乎一般只使用這個向量的長度也就是一個數量...)
$a{\times}b=|a||b|sin{\theta}$,就是三角形面積的某個公式乘2
$a{\times}b=a.x*b.y-b.x*a.y$
滿足:
反交換律$a{\times}b=-b{\times}a$
分配律$a{\times}(b+c)=a{\times}b+a{\times}c$
結合律$(r*a){\times}b=a{\times}(r*b)=r(a{\times}b)$
幾何意義:
把a和b的起點固定,a和b組成的三角形的“有向面積”的兩倍,就是形成的一個平行四邊形的面積。
所謂有向面積,如果從a到b旋轉是逆時針,那麽為正,如果是順時針則為負(旋轉取小於等於180°的角)。
或者說,沿著a的方向看,b在左側,那麽為正,如果在右側則為負。
如果a、b共線,不管方向相同還是相反,叉積都為0。
向量旋轉
設rad為逆時針旋轉的角度(弧度制),那麽新向量為$(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad))$
在2-D的迪卡爾坐標系中,一個位置向量的旋轉公式可以由三角函數的幾何意義推出。比如上圖所示是位置向量R逆時針旋轉角度B前後的情況。在左圖中,我們有關系:
x0 = |R| * cosA
y0 = |R| * sinA
=>
cosA = x0 / |R|
sinA = y0 / |R|
在右圖中,我們有關系:
x1 = |R| * cos(A+B)
y1 = |R| * sin(A+B)
其中(x1, y1)就是(x0, y0)旋轉角B後得到的點,也就是位置向量R最後指向的點。我們展開cos(A+B)和sin(A+B),得到
x1 = |R| * (cosAcosB - sinAsinB)
y1 = |R| * (sinAcosB + cosAsinB)
現在把
cosA = x0 / |R|
sinA = y0 / |R|
代入上面的式子,得到
x1 = |R| * (x0 * cosB / |R| - y0 * sinB / |R|)
y1 = |R| * (y0 * cosB / |R| + x0 * sinB / |R|)
=>
x1 = x0 * cosB - y0 * sinB
y1 = x0 * sinB + y0 * cosB
這樣我們就得到了2-D迪卡爾坐標下向量圍繞原點的逆時針旋轉公式。
證明
直線的參數表示
$P+tv$,其中P為點,t為參數,v為向量(表示方向)
直線:t無限制;射線:t大於0;線段:t在0和1之間
直線交點
證明
記錄1 記錄2
設直線分別為$P+tv$和$Q+tw$。交點在第一條直線上參數為t1,第二條直線上參數為t2。
那麽,$P+t1v=Q+t2w$
兩邊同時叉乘w,得到$(P+t1v){\times}w=(Q+t2w){\times}w$
由分配律知,$P{\times}w+t1v{\times}w=Q{\times}w+t2w{\times}w$
由結合律(?)知,$P{\times}w+t1v{\times}w=Q{\times}w+t2(w{\times}w)$
由$w×w=0$知,$P{\times}w+t1v{\times}w=Q{\times}w$
則$t1v{\times}w=Q{\times}w-P{\times}w=(Q-P){\times}w=w{\times}(P-Q)$
則$t1=(w{\times}(P-Q))/(v{\times}w)=cross(w,P-Q)/cross(v,w)$
點到直線距離
簡單,畫圖驗證即可。基本就是直線上任取一點,叉積算出某個平行四邊形的面積,再除以底。
直線上有點A、B,P到直線的距離是$(B-A){\times}(P-a)/|(B-A)|$
如果不取絕對值,那麽返回的是有向距離:
//(未驗證)沿直線上兩點形成有向線段方向看去,如果點在右側那麽為負,如果點在左側則為正。
namespace X { const double eps=1e-10; struct Point { double x,y; Point(double x=0,double y=0):x(x),y(y){} }; typedef Point Vec; Vec operator+(const Vec& a,const Vec& b) { return Vec(a.x+b.x,a.y+b.y); } Vec operator-(const Vec& a,const Vec& b) { return Vec(a.x-b.x,a.y-b.y); } Vec operator*(const double& a,const Vec& b) { return Vec(a*b.x,a*b.y); } Vec operator*(const Vec& a,const double& b) { return Vec(b*a.x,b*a.y); } Vec operator/(const Vec& a,const double& b) { return Vec(a.x/b,a.y/b); } int dcmp(double x) { if(fabs(x)<eps) return 0; return x<0?-1:1; } bool operator==(const Vec& a,const Vec& b) { return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0; } double dot(const Vec& a,const Vec& b) { return a.x*b.x+a.y*b.y; } double len(const Vec& x) { return sqrt(dot(x,x)); } double angle(const Vec& a,const Vec& b) { return acos(dot(a,b)/len(a)/len(b)); } double cross(const Vec& a,const Vec& b) { return a.x*b.y-a.y*b.x; } Vec Rotate(const Vec& a,const double& rad) { return Vec(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad)); } Point get_line_intersection(const Point& p,const Vec& v,const Point& q,const Vec& w) { return p+v*cross(w,p-q)/cross(v,w); } double dis_to_line(const Point& p,const Point& a,const Point& b) { Vec v1=b-a,v2=p-a; return fabs(cross(v1,v2)/len(v1)); } double dis_to_seg(const Point& p,const Point& a,const Point& b) { if(a==b) return len(p-a); Vec v1=b-a,v2=p-a,v3=p-b; if(dcmp(dot(v1,v2))<0) return len(v2); else if(dcmp(dot(v1,v3))>0) return len(v3); else return fabs(cross(v1,v2)/len(v1)); } };
計算幾何--平面向量(1)