相機標定——數學原理及公式推導篇
當然這個東西不常考,學一點基本的就行
叉積
\(\vec a\times \vec b\),或者簡寫成 axb。
\[a*b=x_1y_2-x_2y_1 \]並不滿足交換律。
這個可以這樣理解,將 \(a\) 逆時針旋轉到 \(b\) 的角度。所以如果 \(>0\) 那麼 \(a\) 就在 \(b\) 的下方,否則就在上方。
判斷一個點在直線的哪邊
設這個直線是 \(PQ\),而且我要求 \(A\) 在直線的哪邊。計算出直線的方向向量 \(v=PQ\),那麼判斷 \(v*PA\) 的正負性即可(\(>0\) 在下方,\(<0\) 在上方)。
求點集的凸包
用 Andrew 演算法求出 \(n\)
首先將它們以 \(x\) 為第一關鍵字,\(y\) 為第二關鍵字排序。那麼最左邊和最右邊的點就一定會在凸包中。我們依次求出上凸包和下凸包。
用一個棧維護現在的凸包點集,如果我們現在要加入一個新點 \(a\),我們就看加入它後可以彈出棧頂多少個點。用叉積去計算斜率,比較 \(s_{top},s_{top-1}\) 的斜率,和 \(a,s_{top-1}\) 的斜率即可,若凹下去了就彈棧。
while(top>1 && cross(vet(sak[top-1],sak[top]),vet(sak[top-1],i))<0 )top--;
求一個點是否在一個三角形內
對於三角形 \(\bigtriangledown ABC\),和點 \(N\),我們看,是否 \(A,N\) 在直線 \(BC\) 同側; \(B,N\) 在直線 \(AC\) 同側;\(C,N\) 在直線 \(AB\) 同側。三個都滿足就是,否則就不在三角形內。
求多邊形的周長與面積
周長:直接相鄰兩個點算距離,最後再加起來。
面積:\(\Large S=\frac{1}2 |\sum\limits_{i=1}^np_i\times p_{i+1}|\)(如果 \(i=n\) 則 \(i+1=1\))
平衡樹維護凸包
CF70D。(當然下面的程式碼不是這一題的 233)
#include<bits/stdc++.h> #define rep(i,x,y) for(int i=x;i<=y;++i) #define per(i,x,y) for(int i=x;i>=y;--i) #define lon long long #define lod long double #define iter set <drop> :: iterator using namespace std; const int n7=201234,inf=2e9; const lod eps=1e-12; struct drop{ lod x,y; friend bool operator == (drop p,drop q){return p.x==q.x&&p.y==q.y;} friend bool operator != (drop p,drop q){return !(p==q);} friend bool operator < (drop p,drop q){return p.x==q.x?p.y<q.y:p.x<q.x;} friend drop operator - (drop p,drop q){return (drop){p.x-q.x,p.y-q.y};} friend lod operator * (drop p,drop q){return p.x*q.y-p.y*q.x;} }a[n7],infl,infr; struct iron{char typ;int t,l,r;}qt[n7]; int n,T,vis[n7],ans[n7],xmax,ymax; set <drop> sut; int rd(){ int shu=0;bool fu=0;char ch=getchar(); while( !isdigit(ch) ){if(ch=='-')fu=1;ch=getchar();} while( isdigit(ch) )shu=(shu<<1)+(shu<<3)+ch-'0',ch=getchar(); return fu?-shu:shu; } lod getK(drop p,drop q){ if(p.x==q.x)return inf; return (p.y-q.y)/(p.x-q.x); } void print(iter it=sut.end()){ puts("------"); if(it==sut.end()){ it=sut.begin(); while(it!=sut.end())printf("%.0Lf %.0Lf\n",(*it).x,(*it).y),++it; } else printf("%.0Lf %.0Lf\n",(*it).x,(*it).y); } bool check(drop x,iter it){ if( *prev(it)==infl || *it==infr )return 1; drop p=*prev(it),q=*it; drop z1=p-q,z2=x-p; return z1*z2+eps<0; } void work(drop x){ if( sut.count(x) )return; iter it=sut.lower_bound(x); if( !check(x,it) )return; while( *it!=infr && *next(it)!=infr ){ if( getK(*it,x)<=getK(*next(it),x) )++it,sut.erase( prev(it) ); else break; } it=--sut.lower_bound(x); while( *it!=infl && *prev(it)!=infl ){ if( getK(*it,x)>=getK(*prev(it),x) )--it,sut.erase( next(it) ); else break; } sut.insert(x); } int main(){ n=rd(); rep(i,1,n)a[i]=(drop){rd(),rd()}; T=rd(); rep(i,1,T){ char sys=getchar(); while( !isalpha(sys) )sys=getchar(); if(sys=='c')qt[i]=(iron){'c',rd(),rd(),rd()}; if(sys=='q')qt[i]=(iron){'q',rd()},vis[ qt[i].t ]=1; } infl=(drop){-inf,-inf},infr=(drop){inf,-inf}; sut.insert(infl),sut.insert(infr); rep(i,1,n){ if(vis[i])continue; work(a[i]); if(a[i].y>ymax)xmax=a[i].x,ymax=a[i].y; } per(i,T,1){ if(qt[i].typ=='c'){ drop z=(drop){qt[i].l*1.0/qt[i].t,qt[i].r*1.0/qt[i].t}; if(z.x<=xmax&&z.y<=ymax)ans[i]=1; else if( sut.count(z) )ans[i]=1; else{ iter it=sut.lower_bound(z); ans[i]=!check(z,it); } } if(qt[i].typ=='q'){ work(a[ qt[i].t ]); if(a[ qt[i].t ].y>ymax)xmax=a[ qt[i].t ].x,ymax=a[ qt[i].t ].y; } } rep(i,1,T)if(qt[i].typ=='c')puts(ans[i]?"no":"yes"); return 0; }
旋轉卡殼
雙指標維護兩個端點即可。
詳細一點:設定兩個指標 \(i,j\),如果 \(dis(i,j)<dis(i,j+1)\) 那麼 \(j++\),否則 \(i++\)。