计算几何中大部分都是用点和向量写的,所以一般使用结构体存储。向量和点都可以使用x和y来表示。所以直接typedef 就可以了。
struct point{
int x,y;
point(double x = 0,double y = 0) : x(x),y(y){};
};
typedef point Vector;
因为要大量计算,所以操作符重载是必不可少的。分别是加减乘除和等号。由于精度问题,所以等号中使用了eps(两点之间有偏差,偏差过小可以当成一个点)。
一般定义double eps = 1e-10就够了,题目上一般会有。有的板子上可能使用的是dcmp函数,意思是一样的。sgn函数就是在允许浮点数误差的情况下判断正负,1,-1,0分别代表正负零。
int sgn(double p){
if(fabs(p) < eps){
return 0;
}else if(p < 0){
return -1;
}else{
return 1;
}
}
bool dcmp(double a){
return fabs(a) < eps;
}
Vector operator + (Vector A, Vector B){
return Vector(A.x + B.x,A.y + B.y)
}
Vector operator - (Vector A, Vector B){
return Vector(A.x - B.x,A.y - B.y);
}
Vector operator * (Vector A, double B){
return Vector(A.x * B,A.y * B);
}
Vector operator / (Vector A, double B){
return Vector(A.x / B,A.y / B);
}
bool operator == (Vector A,Vector B){
return (fabs(A.x - B.x) <= eps && fabs(A.y - B.y ) <= eps);
}
接下来就是向量乘法和取模运算。
double Dot(Vector A,Vector B){
return A.x*B.x + B.y*A.y;
}
double Cross(Vector A,Vector B){
return A.x * B.y - B.x*A.y;
}
double Mod(Vector A){
return sqrt(A.x*A.x + A.y*A.y);
}
然后是计算向量之间的角度
//弧度
double Angle(Vector A,Vector B){
return acos(Dot(A,B) / (Mod(A)*Mod(B)));
}
还有是旋转,旋转的话,我自己当时学一直不知道公式是怎么来的。所以我这里给了一个证明
A的角度是Q,B的是Q+theta
所以易得
然后就是向量的旋转了,把它当成两个点就行了
Vector Rotato(Vector A,double rad){
return Vector(A.x * cos(rad) - A.y * sin(rad),A.x *sin(rad) + A.y *cos(rad));
}
接下来就是判断三个点的位置关系,c在直线ab的左边还是右边。经常用在凸包判断
判断c在ab的左边还是右边
bool Tolefttest(point a,point b,point c){
Vector A = (b-a);
Vector B = (c-b);
return Cross(A,B) > 0;
}
然后就是一个点绕着另一个点旋转,只要把P点当成原点最后加回去就好了
点绕着 p 点逆时针旋转
Point Rotato(point A,point P,double angle){
Vector v = A - P;
double s = sin(angle),c = cos(angle);
return point(P.x + v.x *c - v.y *s,P.y + v.x*s + v.y*c);
}