计算几何中的坐标一般是实数,一般使用double类型,不用精度较低的float类型。
在进行浮点数运算时会产生精度误差,为了控制精度,可以设置一个偏差值eps,eps要大于浮点运算结果的不确定量,一般取10^-8。
判断浮点数是否等于0,不能直接用“==0”来判断,而是用sgn()函数判断是否小于eps。在比较两个浮点数时,也不能直接用等号直接判断是否相等,而是用dcmp()函数判断是否相等。
const double pi = acos(-1.0); //高精度圆周率
const double eps = 1e-8; //偏差值
int sgn(double x){ //判断x是否等于0
if(fabs(x)<eps) return 0;
else return x<0 ? -1:1;
}
int dcmp(double x,double y){ //比较两个浮点数:0为相等,-1为小于,1为大于
if(fabs(x-y)<eps) return 0;
else return x<y? -1 : 1;
}
二维平面中的点用坐标(x,y)来表示。
struct Point{
double x,y;
Point(){}
Point(double x,double y):x(x),y(y){}
};
(1)把两点看成直角三角形的两个顶点,斜边就是两点的距离,用库函数hypot()计算直角三角形的斜边长。
double Distance(Point a,Point b){
return hypot(a.x-b.x,a.y-b.y);
}
(2)或者用sqrt()函数计算
double Dist(Point a,Point b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
有大小、有方向的量成为向量(矢量),只有大小没有方向的量成为标量。
注意,向量并不是一个有向线段,只是表示方向和大小,所以向量平移后仍然不变。
加、减、乘、除、等于
Point operator + (Point b){ return Point(x+b.x,y+b.y);}
Point operator - (Point b){ return Point(x-b.x,y-b.y);}
Point operator * (double k){return Point(x*k,y*k);}
Point operator / (double k){return Point(x/k,y/k);}
bool operator == (Point b){return sgn(x-b.x)==0 && sgn(y-b.y)==0;}
向量的基本运算是点积和叉积,计算几何的各种操作几乎都基于这两种运算。
double Dot(Vector a,Vector b){
return a.x*b.x+a.y*b.y;
}
(1)判断A与B的夹角是钝角还是锐角
dot(A,B)>0 为锐角,dot(A,B)=0为直角,dot(A,B)<0为钝角
(2)求向量A的长度
double Len(Vector a){
return sqrt(dot(a,a));
}
(3)求向量A与B的夹角大小
double Angle(Vector a,Vector b){
return acos(dot(a,b)/Len(a)/Len(b);)
}
double Cross(Vector a,Vector b){
return a.x*b.y - a.y*b.x;
}
struct Line{
Point p1,p2;
Line(){}
Line(Point p1,Point p2):p1(p1),p2(p2){}
Line(Point p,double angle){
p1=p;
if(sgn(angle-pi/2)==0){
p2=(p1+Point(0,1));
}
else {
p2=(p1+Point(1,tan(angle)));
}
}
Line(double a,double b,double c){
if(sgn(a)==0){
p1=Point(0,-c/b);
p2=Point(1,-c/b);
}
else if(sgn(b)==0){
p1=Point(-c/a,0);
p2=Point(-c/a,1);
}
else{
p1=Point(0,-c/b);
p2=Point(1,(-c-a)/b);
}
}
};
int point_Line_Relation(Point p,Line v){
int c = sgn(Cross(p-v.p1,v.p2-v.p1));
if(c<0) return -1; //点在直线左边
if(c>0) return 1; //p在v的右边
return 0; // p在v上
}
bool point_On_Seg(Point p,Line v){ //0 为不在线段v上,1为在线段v上
return sgn(Cross(p-v.p1,v.p2-v.p1))==0 && sgn(Dot(p-v.p1,p-v.p2))<=0;
}
double dis_Point_Line(Point p,Line v){
return fabs(Cross(p-v.p1,v.p2-v.p1))/Dist(v.p1,v.p2);
}
Point point_Line_Proj(Point p,Line v){
double k = Dot(v.p2-v.p1,p-v.p1)/Len2(v.p2-v.p1);
return v.p1+(v.p2-v.p1)*k;
}
Point point_Line_Symmetry(Point p,Line v){
Point q = point_Line_Proj(p,v);
return Point(2*q.x-p.x,2*q.y-p.y);
}
double dis_Point_Seg(Point p,Segment v){
if(sgn(Dot(p-v.p1,v.p2-v.p1))<0 || sgn(Dot(p-v.p2,v.p1-v.p2))<0){
return min(Dist(p,v.p1),Dist(p,v.p2));
}
return dis_Point_Line(p,v);
}
int line_Relation(Line v1,Line v2){
if(sgn(Cross(v1.p2-v1.p1,v2.p2-v2.p1))==0){
if(point_Line_Relation(v1.p1,v2)==0){
return 1;//重合
}
else return 0; //平行
}
return -1;//相交
}
Point cross_Point(Point a,Point b,Point c,Point d){
double s1 = Cross(b-a,c-a);
double s2 = Cross(b-a,d-a);
return Point(c.x*s2-d.x*s1,c.y*s2-d.y*s1)/(s2-s1);
}