欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

计算几何基础

程序员文章站 2022-03-27 21:34:09
计算几何基础计算几何基本概念计算几何中的坐标一般是实数,一般使用double类型,不用精度较低的float类型。在进行浮点数运算时会产生精度误差,为了控制精度,可以设置一个偏差值eps,eps要大于浮点运算结果的不确定量,一般取10^-8。判断浮点数是否等于0,不能直接用“==0”来判断,而是用sgn()函数判断是否小于eps。在比较两个浮点数时,也不能直接用等号直接判断是否相等,而是用dcmp()函数判断是否相等。const double pi = acos(-1.0); //高精度圆周率co...

计算几何基础

计算几何基本概念

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

本文地址:https://blog.csdn.net/weixin_43964559/article/details/107333619