计算几何基础

计算几何基础

计算几何基本概念

计算几何中的坐标一般是实数,一般使用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;
}

点和向量

1.点

二维平面中的点用坐标(x,y)来表示。

struct Point{
	double x,y;
	Point(){}
	Point(double x,double y):x(x),y(y){}
};

2.两点之间的距离

(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));
}

3.向量

有大小、有方向的量成为向量(矢量),只有大小没有方向的量成为标量。
注意,向量并不是一个有向线段,只是表示方向和大小,所以向量平移后仍然不变。

4.向量的运算

加、减、乘、除、等于

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;}

点积和叉积

向量的基本运算是点积和叉积,计算几何的各种操作几乎都基于这两种运算。

1.点积

double Dot(Vector a,Vector b){
	return a.x*b.x+a.y*b.y;
}

2.点积的应用

(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);)
}

3.叉积

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);
}

你可能感兴趣的:(算法学习)