计算几何的基础运算(笔记)
余弦
余弦定理:三角形任一边的平方等于其他两边平方和减去这两边与它们夹角的余弦的积的两倍
\(a^2=b^2+c^2-2bc\cdot cosA\)
点积
两个向量\(v\)和\(w\)的点积等于二者模积乘上它们夹角的余弦,因此当夹角大于\(90^o\)时点积为负
\(|v|\cdot|w|\cdot cos\theta\)
两个向量OA和OB的点积等于\(x_Ax_B+y_Ay_B\),即\(\overrightarrow{OA}\cdot\overrightarrow{OB}=\overrightarrow{|OA|}\cdot\overrightarrow{|OB|}cos\theta=x_Ax_B+y_Ay_B\)
证明略
显然满足交换律
double Dot(Point A, Point B){ return A.x* B.x+ A.y* B.y; }
叉积
两个向量\(v\)和\(w\)的叉积等于\(v\)和\(w\)所组成的三角形的有向面积的两倍
\(|v|\cdot|w|\cdot sin\theta\)
从向量\(v\)来看,如果\(w\)在左边(逆时针),则\(v\)和\(w\)的叉积大于\(0\),否则小于\(0\)。特殊地,如果两个向量共线(方向相同),那么叉积等于\(0\)(三角形退化成线段)
可以发现,叉积不满足交换律:\(cross(v,w)=-cross(w,v)\),两个向量\(OA\)和\(OB\)的叉积等于\(x_Ay_B-x_By_A\)
double Cross(Point A, Point B){ return A.x* B.y- A.y* B.x; }
直线的参数表示
直线可以用直线上一点\(P_0\)和方向向量\(v\)表示(这个向量的大小在表示中无用),借此直线上所以点\(P\)可以满足\(P=P_0+tv\),其中t为参数
如:一直直线上不同两点\(A和B\),则方向向量为\(B-A\),所以参数方程为\(A+(B-A)t\)
直线交点
设直线分别为\(P+tv\)和\(Q+tw\),设向量\(u=P-Q\),设交点在第一条直线参数为\(t_1\),在第二条直线参数为\(t_2\),则:
点到线段的距离
距离有两种可能
一种是点\(P\)在直线\(AB\)的投影点\(Q\)在线段\(AB\)上,其距离为线段\(PQ\)的长度;另一种,则距离为点\(P\)到线段\(AB\)两端点的最小值
可以利用点积判断位置关系分类处理
inline double Getlength(Point P,Point A,Point B){
if(A==B) return Length(P-A);
if(dcmp(Dot(v1, v2)) < 0) return Length(v2);
else if(dcmp(Dot(v1, v2))< 0) return Length(v3);
else return fabs(Cross(v1, v2)) / Length(v1);
}
多边形面积
凸包的面积求法很显然:找到左下角一点然后顺时针求相邻两点分割成三角形即可
那非凸(不规则)多边形呢?其实方法是相同的,因为三角形面积是有向的,在外面的部分可以抵消掉(好神奇啊!!!(* ̄︶ ̄))
代码实现
几个常用库函数:\(cos(rad)\)(余弦函数:返回余弦值),\(acos(p)\)(反余弦函数:返回弧度)...剩下的都类似了
struct Point{
double x, y;
Point(double x=0, double y=0):x(x), y(y) {}
};
Point operator + (Point A, Point B){ return Point(A.x+ B.x, A.y+ B.y); }
Point operator - (Point A, Point B){ return Point(A.x- B.x, A.y- B.y); }
Point operator * (Point A, double p){ return Point(A.x* p, A.y* p); }
Point operator / (Point A, double p){ return Point(A.x/ p, A.y/ p); }
优化精度(粗略大小)
inline int Dcmp(double x){
if(fabs(x)< eps) return 0;
else return x< 0?-1: 1;
}
点积(满足交换律)
求向量的模长
```cpp`
double Length(Point A){ return sqrt(Dot(A, A)); }
利用余弦定理逆向求角度(满足交换律)
```cpp
double Angle(Point A, Point B){ return acos(Dot(A, B)/ Length(A)/ Length(B)); }
叉积(不满足交换律)
利用叉积求有向面积
double Area2(Point A, Point B, Point C){ return Cross(B- A, C- A); }
直线交点公式(满足交换律)
Point Getlinedot(Point P, Point v, Point Q, Point w){
Point u=P-Q;
double t=Cross(w, u)/ Cross(v, w);
return P+v*t;
}
判线段是否相交,十字形状,向量形成一个箭头,左右各一个
inline bool Segmentlinedot(Point a1, Point a2, Point b1, Point b2){
double c1=Cross(a2-a1, b1-a1), c2=Cross(a2-a1, b2-a1),
c3=Cross(b2-b1, a1-b1), c4=Cross(b2-b1, a2-b1);
return Dcmp(c1)*Dcmp(c2)<0 && Dcmp(c3)*Dcmp(c4)<0;
}
判断点是否在线段上而不在线段的端点
inline bool Onsegment(Point p, Point a1, Point a2){
return Dcmp(Cross(a1-p, a2-p))==0 && Dcmp(Dot(a1-p, a2-p))<0;
}