码迷,mamicode.com
首页 > 其他好文 > 详细

计算几何基础

时间:2016-06-12 14:02:54      阅读:202      评论:0      收藏:0      [点我收藏+]

标签:

1.基础的基础


1.点与向量.

点与向量都用x,y两个坐标表示,所以我们在程序上暂时不做区分.

但是注意:

  (1).点+向量=点;

  (2).向量+向量=向量(向量-向量=向量+(相反向量));

  (3).点-点=向量;

  (4).点+点没有意义;

其中pt(point)表示点,vt(vector)表示向量.

技术分享
1 struct pt{
2     double x,y;
3     point(double x=0,double y=0):x(x),y(y){}
4 };
5 typedef pt vt;
6 vt operator + (vt a,vt b){ return vt(a.x+b.x,a.y+b.y); }
7 vt operator - (pt a,pt b){ return vt(a.x-b.x,a.y-b.y); }
8 vt operator * (vt a,double x){ return vt(a.x*x,a.y*y); }
9 vt operator / (vt a,double x){ return vt(a.x/x,a.y/x); }
View Code

 

2.点的比较函数

在有些需要排序的时候会用到.

技术分享
1 bool operator < (const pt &a,const pt &b){ return a.x<b.x||(a.x==b.x&&a.y<b.y); }
View Code

 

3.判断点相等的函数和避免误差的三态函数

浮点误差总是存在的,所以我们用三态函数dcmp来减少精度带来的问题.

技术分享
1 const double eps=1e-8;
2 int dcmp(double x){ if(fabs(x)<eps) return 0; else return x<0?-1:1; }
3 bool operator == (const pt &a,const pt &b){  return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0; }
View Code

 

4.向量的极角

向量的极角表示从x轴正半轴旋转到该向量所需要的角度.

使用C标准库里面的atan2函数即可,单位是弧度.

技术分享
1 atan2(y,x);
View Code

 

 

2.基本运算


1.向量的点积与叉积

$$cross(a,b)=a.x*b.y-a.y*b.x$$

这个是怎么来的呢?我们比较两个向量所在直线的斜率,如果b向量所在直线的斜率大(两个向量的斜率都存在的情况),那么就有$$\frac{b.y}{b.x}>\frac{a.y}{a.x}$$

然后去分母$$a.x*b.y>a.y*b.x$$

我们注意到,此时b向量所在的直线位于a向量所在直线的右手螺旋方向(a在b的左手螺旋方向).如果是小于号即b向量所在直线的斜率小,那么b向量所在的直线位于a向量所在直线的左手螺旋方向(a在b的右手螺旋方向).如果是等号即斜率一样,那么两条直线平行即向量a,b共线.

但这是两直线斜率都存在的情况.我们来讨论一下斜率不存在的情况:

(1).a所在直线的斜率不存在即\(a.x=0\).

若原不等式仍成立即\[0>a.y*b.x\],再讨论\(a.y\)的正负,可以证明b所在直线仍然位于a所在直线的右手螺旋方向.

(2).b所在直线的斜率不存在即\(b.x=0\).

若原不等式仍成立即$$a.x*b.y>0$$,再讨论\(b.y\)的正负,可以证明b所在直线仍然位于a所在直线的右手螺旋方向.

(3).a,b所在直线的斜率都不存在即\(a.x=b.x=0\).

此时不等式取等,平行.

综上,原不等式对应的结论永远成立.所以我们可以用叉积来判断两条直线的左右位置关系.

另外,叉积的几何意义是以这两个向量为邻边的平行四边形的有向面积(可用余弦定理证明),也就是两倍的三角形面积.

为什么说是有向面积呢?因为根据定义我们很容易发现\(cross(a,b)=-cross(b,a)\),所以算出来会带正负号!

技术分享
1 double dot(vt a,vt b){ return a.x*b.x+a.y*b.y; }
2 double cross(vt a,vt b){ return a.x*b.y-a.y*b.x; }
3 double area2(pt a,pt b,pt c){ return cross(b-a,c-a); }
View Code

 

2.向量的模

技术分享
1 double length(vt a){ return sqrt(dot(a,a)); }
View Code

 

3.两向量的夹角

通过点积来计算夹角的余弦值,再用一个反三角函数.

技术分享
1 double angle(vt a,vt b){ return acos(dot(a,b)/length(a)/length(b)); }
View Code

 

4.向量的旋转.

将一个向量绕起点逆时针旋转\(\alpha\)弧度.

怎么操作呢?

我们先把这个向量的起点平移到坐标原点.写出向量终点的极坐标:$$x=rcos\theta$$

$$y=rsin\theta$$

旋转之后终点的极坐标为:

$$x‘=rcos(\theta+\alpha)$$

$$y‘=rsin(\theta+\alpha)$$

打开得到:

$$x‘=r(cos{\theta}cos{\alpha}-sin{\theta}sin{\alpha})=xcos{\alpha}-ysin{\alpha}$$

$$y‘=r(sin{\theta}cos{\alpha}+cos{\theta}sin{\alpha})=xsin{\alpha}+ycos{\alpha}$$

即:

$$x‘=xcos{\alpha}-ysin{\alpha}$$

$$y‘=xsin{\alpha}+ycos{\alpha}$$

技术分享
1 vt rotate(vt a,double rad){ return vt(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad)) }
View Code

 

5.复数

白书上提到了,但是我没有搞懂用来干嘛...貌似也比较慢,FFT里都是手写的,不管了.

 

3.点和直线


1.线段相交

由于这是出现最频繁的问题,所以我们放在第一个说.

首先来定义一下规范相交:两线段相交且交点不是四个端点中的任何一个.

在解决判断线段是否相交的问题时,最容易想到的是解析几何的办法.但是和斜率相关的点斜式和斜截式都用不了,如果用一般式或两点式需要联立解方程,然后判断是否有解,如果有解还要判断是否在两条线段内部.这样很麻烦,而且误差不好控制.

对于不要求求出交点坐标的问题,我们采用一种神奇的方法.

首先一个引理:两线段\(AB\)与\(CD\)规范相交\(\Longleftrightarrow\)\(\overrightarrow{AC}\)与\(\overrightarrow{AD}\)分别在\(\overrightarrow{AB}\)左右两侧且\(\overrightarrow{CA}\)与\(\overrightarrow{CB}\)分别在\(\overrightarrow{CD}\)左右两侧

计算几何基础

标签:

原文地址:http://www.cnblogs.com/Sunnie69/p/5577243.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!