计算几何基本操作总结

挖坑自用,可能又不全面的地方欢迎指出

//double已被define为DB

点与向量

点与向量是一个二元组,在运算方面相似,因此可以定义成一个结构体

struct Point {
	DB x , y ;
	Point ( ) { } 
	Point ( DB _x , DB _y ) 
	{
		x = _x ; y = _y ; 
	}
	Point operator + ( const Point &a ) const 
	{
		return Point ( x + a.x , y + a.y ) ; 
	}
	Point operator - ( const Point &a ) const 
	{
		return Point ( x - a.x , y - a.y ) ; 
	}
	Point operator * ( const DB &a ) const 
	{
		return Point ( x * a , y * a ) ; 
	}
	Point operator / ( const DB &a ) const 
	{
		return Point ( x / a , y / a ) ; 
	}
	DB mo ( ) 
	{
		return sqrt ( x * x + y * y ) ; 
	}
}

其中模长,数乘是针对向量的,加法可以理解为 点+向量=点 或 向量+向量=向量 。减法可以是点-点=向量

基本操作有:点积和叉积,这两个运算都是针对向量的,点积定义为两向量投影的长度之积,公式为x1x2+y1y2,常被用于判垂直(点积为0),叉积 值等于两向量构成的平行四边形的面积,公式为x1y2-y1x2,可用来判断A向量在B向量的顺时针或逆时针方向,若值为0,则重合;若值大于0,则A在B的顺时针;若值小于0,则A在B的逆时针。

DB cha ( Point a , Point b ) 
{
	return a.x * b.y - a.y * b.x ; 
}

DB dian ( Point a , Point b ) 
{
	return a.x * b.x + a.y * b.y ; 
}

对于一个角度,只需记录其sin与cos即可在0-2π中唯一确定,而且用角也是用sin与cos偏多,所以用sin与cos来表示一个角,角相加则直接用公式sin(a+b)=sin(a)cos(b)+cos(a)sin(b)计算,cos亦然(数乘可以用类似快速幂求)。

struct Ang {
	DB si , co ; 
	Ang ( ) { } 
	Ang ( DB _si , DB _co ) { si = _si ; co = _co ; } 
	Ang operator + ( const Ang &a ) const 
	{
		return Ang ( si * a.co + co * a.si , co * a.co - si * a.si ) ; 
	}
	Ang operator - ( const Ang &a ) const 
	{
		return Ang ( si * a.co - co * a.si , co * a.co + si * a.si ) ;  
	}
} ;

操作 : 把一个向量逆时针旋转一个角度。

先取向量的起点为原点,则需要求的是A(x,y)绕原点旋转之后的点坐标,原向量可表示为(kcos(a),ksin(a)),k为A到原点的距离,注意到旋转后A到原点距离不变,只是角度加了一下,所以旋转过后点坐标为(kcos(a+b),ksin(a+b)) 用类似角与角相加的做法即可。我定义的角的第一个元素是sin,所以要换一下。

Point Rota ( Point a , Ang alp ) //逆时针 
{
	Ang p ( a.y , a.x ) ; 
	p = p + alp ;  
	return Point ( p.co , p.si ) ; 
}

直线

两点确定一个直线,所以可以用不同的两点来存直线(点+向量亦可)

struct Line {
	Point d , e ;
	Line ( ) { } 
	Line ( Point _d , Point _e ) { d = _d ; e = _e ; } 
} ; 

操作:判断直线是否过一点A。两点到A的向量的叉积为0。

操作:判断两直线位置关系。两直线的向量的叉积为0时平行或重合,否则相交。

操作:求中垂线。先获得一个中点M,再旋转aM向量后相加得到另一个点

操作:两直线求交点。(推荐画图理解)。设a,b是A上两点,c,d是B上两点,交点为e,则向量a->c与a->d的叉积是三角形acd的面积s1*2。同理b->c与b->d的叉积是三角形bcd的面积s2*2,因为acd与bcd同底,再根据三角形相似,s1/s2=ae/be,也就是得到了ae与be长度之比,e=a+(b-a)*(s1 / (s1-s2))。用点与向量计算绕开了分母为0的讨论(唯一情况s1=s2,但这代表a==b,即A的表示不合法),并且因为叉积自带方向性不需讨论正负,比列方程更方便。

Point Line_and_Line ( Line a , Line b ) 
{
	DB s1 = cha ( b.d - a.d , b.e - a.d ) , s2 = cha ( b.d - a.e , b.e - a.e ) ; 
	return a.d + ( ( a.e - a.d ) * ( s1 / ( s1 - s2 ) ) ) ; 
}

圆心加半径存圆

struct Cir {
	Point md ; 
	DB r ; 
	Cir ( ) { } 
	Cir ( Point _md , DB _r ) { md = _md ; r = _r ; }
} ; 

操作:3点定最小覆盖圆。

先判断3点共线,共线则以

最长的线段为半径做圆。否则求三角形外接圆,就是三角形三边中垂线的交点。

Cir made_2 ( Point a , Point b ) 
{
	Point det = ( b - a ) / 2 ;
	return Cir ( a + det , det.mo ( ) ) ;
}

Cir made_3 ( Point a , Point b , Point c ) 
{
	if ( jd ( cha ( a - b , b - c ) ) < eps ) 
	{
		if ( b.x > c.x ) swap ( b , c ) ; 
		if ( a.x > b.x ) swap ( a , b ) ; 
		if ( b.x > c.x ) swap ( b , c ) ;
		return made_2 ( a , c ) ; 
	}
	Point mp = a + ( ( b - a ) / 2 ) , det = a - mp ;
	Line g1 ( mp , mp + Rota ( det , Ang ( 1.0 , 0.0 ) ) ) ; 
	mp = a + ( ( c - a ) / 2 ) , det = a - mp ; 
	Line g2 ( mp , mp + Rota ( det , Ang ( 1.0 , 0.0 ) ) ) ; 
	Point _md = Line_and_Line ( g1 , g2 ) ; 
	return Cir ( _md , dist ( _md , a ) ) ; 
}

操作:求圆与直线交点

设求的交点为B,首先可以用圆心+垂直向量获得过圆心与L相垂直的直线,两直线求交得交点A,然后勾股定理求出AB距离,与L的向量的模长做个比即可求出向量AB了。(一般情况有两个对应加和减)

Point Cir_and_Line ( Cir p , Line l ) 
{
	Point vc = l.e - l.d ; 
	Point vv = Rota ( vc , Ang ( 1.0 , 0.0 ) ) ; 
	Point another = p.md + vv ; 
	Point cha = Line_and_Line ( Line ( p.md , another ) , l ) ;
	double d = dist ( cha , p.md ) ;  
	double leth = sqrt ( p.r * p.r - d * d ) ; 
	double poi = vc.mo ( ) ;  
	Point xa = cha + vc * leth / poi , xb = cha - vc * leth / poi ; 
        return xa ; 
	// xa , xb 即为两交点  
}

操作:求过一点圆的切线

设点n与圆的交点为A,则角oAn是直角,求出An的长度,直接旋转即可

Line Point_cut_Cir ( Cir p , Point n ) 
{
	int leth = dist ( p.md , n ) ; 
	int ntoA = sqrt ( leth * leth - p.r * p.r ) ; 
	return Rota ( Line ( p.md , n ) , Ang ( p.r / leth , ntoA / leth ) ) ; //顺时针还有一个 
}

待更......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
计算几何算法(含源代码) ㈠ 点的基本运算 1. 平面上两点之间距离 1 2. 判断两点是否重合 1 3. 矢量叉乘 1 4. 矢量点乘 2 5. 判断点是否在线段上 2 6. 求一点饶某点旋转后的坐标 2 7. 求矢量夹角 2 ㈡ 线段及直线的基本运算 1. 点与线段的关系 3 2. 求点到线段所在直线垂线的垂足 4 3. 点到线段的最近点 4 4. 点到线段所在直线的距离 4 5. 点到折线集的最近距离 4 6. 判断圆是否在多边形内 5 7. 求矢量夹角余弦 5 8. 求线段之间的夹角 5 9. 判断线段是否相交 6 10.判断线段是否相交但不交在端点处 6 11.求线段所在直线的方程 6 12.求直线的斜率 7 13.求直线的倾斜角 7 14.求点关于某直线的对称点 7 15.判断两条直线是否相交及求直线交点 7 16.判断线段是否相交,如果相交返回交点 7 ㈢ 多边形常用算法模块 1. 判断多边形是否简单多边形 8 2. 检查多边形顶点的凸凹性 9 3. 判断多边形是否凸多边形 9 4. 求多边形面积 9 5. 判断多边形顶点的排列方向,方法一 10 6. 判断多边形顶点的排列方向,方法二 10 7. 射线法判断点是否在多边形内 10 8. 判断点是否在凸多边形内 11 9. 寻找点集的graham算法 12 10.寻找点集凸包的卷包裹法 13 11.判断线段是否在多边形内 14 12.求简单多边形的重心 15 13.求凸多边形的重心 17 14.求肯定在给定多边形内的一个点 17 15.求从多边形外一点出发到该多边形的切线 18 16.判断多边形的核是否存在 19 ㈣ 圆的基本运算 1 .点是否在圆内 20 2 .求不共线的三点所确定的圆 21 ㈤ 矩形的基本运算 1.已知矩形三点坐标,求第4点坐标 22 ㈥ 常用算法的描述 22 ㈦ 补充 1.两圆关系: 24 2.判断圆是否在矩形内: 24 3.点到平面的距离: 25 4.点是否在直线同侧: 25 5.镜面反射线: 25 6.矩形包含: 26 7.两圆交点: 27 8.两圆公共面积: 28 9. 圆和直线关系: 29 10. 内切圆: 30 11. 求切点: 31 12. 线段的左右旋: 31 13.公式: 32
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值