模板在网上很容易找到,这里我就讲一讲我对这些代码(lrj白皮书上的)的理解,包括添加证明,插图等。
定义向量及向量的四则运算,其中A,B都是一个向量。(貌似是高中数学课本上的内容)
struct poi
{
double x,y;
poi(double x=0,double y=0) :x(x),y(y){}
}
typedef poi vec;//定义一个poi的别名只是为了更方理解代码,一个表示点,一个表示向量
vec operator +(vec A,vec B) {return vec(A.x+B.x, A.y+B.y);}
vec operator -(vec A,vec B) {return vec(A.x-B.x, A.y-B.y);}
vec operator *(vec A,double p) {return vec(A.x*p, A.y*p);}
vec operator /(vec A,double p) {return vec(A.x/p, A.y/p);}
再来说说向量的比较函数
为什么要定义一个比较函数?就用==不好吗?由于在计算几何的计算中,参与运算的大多数都是浮点数,会产生误差,定义dcmp减少了精度问题
const double eps = 1e-9;
int dcmp(double x)
{if(fabs(x) < eps) return 0; else return x>0?1:-1;}
bool operator <(vec A,vec B)
{if(A.x == B.x) return A.y < B.y; else return A.x < B.x;}
bool operator ==(vec A,vec B)
{return dcmp(A.x-B.x) == 0&&dcmp(A.y-B.y) == 0;}
基本运算包括求向量的点积(点乘),叉积(叉乘)和求向量的夹角,向量的模长。貌似在高中教材中没有提到叉积这一概念。
点积(dot):
a⃗ ⋅b⃗ =|a⃗ ||b⃗ |cos<a⃗ ,b⃗ >。|a⃗ |,|b⃗ |,cos<a⃗ ,b⃗ >
分别是向量的模长,夹角的余弦值。
叉积(cross):
a⃗ ∗b⃗ =|a⃗ ||b⃗ |sin<a⃗ ,b⃗ >
。几何意义为平移
a⃗ ,b⃗
得到的平行四边形面积,可由正弦公式推导而来。注意叉积有正负,不满足交换律,简单的判断方式:把向量a顺时针旋转到向量b,若角度小于
π
就为正,否则为负。
求夹角,其实就是把点积公式倒过来使用。
<a⃗ ,b⃗ >=arccos(a⃗ ⋅b⃗ |a⃗ ||b⃗ |)
<script type="math/tex" id="MathJax-Element-5"><\vec a,\vec b> = arccos(\frac {\vec a \cdot \vec b}{|\vec a||\vec b|})</script>。
double dot(vec A,vec B) {return A.x*B.x + A.y*B.y;}
double cross(vec A,vec B) {return A.x*B.y - A.y*B.x;}
double length(vec A) {return sqrt(dot(A,A));}
double angle(vec A,vec B) {return acos(dot(A,B) /length(A) /length(B));}
强行解释一下cross那个公式怎么来的
直线OA:
yAx−xAy=0
那么由距离公式
d=|yAxB−xAyB|x2A+y2A√⇒sinθ=|yAxB−xAyB|x2A+y2A√x2B+y2B√⇒S△abc=12|yAxB−xAyB|
旋转任意角,求单位法向量(旋转90度)公式
vec rotate(vec A,double rad) {return vec(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));}
vec normal(vec A) {double L = length(A); return vec(-A.y/L,A.x/L);}
旋转公式推导
原来的向量设为
(x0,y0)
,倾斜角为
φ
,转角为
α
,那么有
x0=x20+y20−−−−−−√cosφ,y0=x20+y20−−−−−−√sinφ
旋转之后的向量
(x′,y′)
则有
x′=x20+y20−−−−−−√cos(α+φ),y′=x20+y20−−−−−−√sin(α+φ)
展开得到
x′=x20+y20−−−−−−√cosφcosα−x20+y20−−−−−−√sinφsinα=x0cosα−y0sinα
y′=x20+y20−−−−−−√sinφcosα+x20+y20−−−−−−√cosφsinα=y0cosα+x0sinα