计算几何(一):点,向量

写在前面

本文基于fxj巨佬的计算几何全家桶,并基于原文进行了自己的一些整理了经验补充,阅读本文前请前往支持巨佬fxj。

前言:

计算几何的使用有一些基本原则,它们能帮助你快速地找到代码中出现的问题并方向明确地解决它们。

  1. 精度:计算几何丢精度是必有的事情,问题只在于你能否满足题目的精度要求。为了避免较大的精度误差,应当减少三角函数,除法,根号的使用,同时,根号函数的精度似乎十分健康。当精度不够时,可以选择long double来解决问题,不过代价就是跑得更慢。
  2. 简洁: 主要通过减少分类讨论的情况数和合理的模块化实现。

精度问题

由于计算几何常用double类型计算,因此丢精度是必然会出现的。这个问题主要体现在比较运算中。

举个例子,在计算几何中算出一个三角形的面积是2.999,但是我们知道这肯定是存在误差的,因此它实际上应当不是2.99,假设在没有误差时它的面积应是3,那么我们要把这个三角面积比较时,就要忽略这一点小误差。

解决这个问题,就要引入贯穿了整个计算几何的核心内容:存在误差时的比较运算
e p s eps eps是一个极小量,通常在 [ 1 0 − 12 , 1 0 − 8 ] [10^{-12},10^{-8}] [1012,108]的范围内,表示精度要求。

a = b a=b a=b → → a b s ( a − b ) abs(a−b) abs(ab) < < < e p s eps eps
a < b a < b a<b → → a < b a < b a<b − − e p s e p s eps
a > b a > b a>b → → a > b a>b a>b + + + e p s eps eps

以上比较式的很容易证明:

  1. 认为 a = b a=b a=b时表达式不应成立,同理可得其他两式。
  2. 也可通过分情况讨论:认为 a a a存在误差, b b b不存在误差,分类讨论 a a a偏大偏小的情况。
    注意:这里认为a的误差值不超过 e p s eps eps

由于浮点数计算产生的精度误差是普遍存在于计算几何中,因此通过计算集合得出的数进行的比较运算中,必须用上文的格式写出。

最容易出现的一个错误就是在将某数 a a a 0 0 0比较时将式子写成 a > 0 a>0 a>0而非 a > 0 + e p s a>0+eps a>0+eps a > e p s a>eps a>eps
范神在部分模板中忽略了这一点,现已更正

点/向量相关:

表示

在计算几何中,点和向量往往是等价的,且经常出现一个变量被同时当作点和向量使用的现象,因此一起表示。

struct V
{
	double x,y;
	V():x(0),y(0){};
	V(double a,double b):x(a),y(b){};	
}dot[maxn];

inline void input(V &a){a.x=read();a.y=read();}

void print(const V &a,int op=1){printf("%.10lf %.10lf",a.x,a.y);putchar(op?10:32);}
//op=endl or space

向量的基本运算:

基本的加、减、乘、除、点积、叉积、模长、中点、垂直向量、向量单位化、三角形面积。

拓展
高维点积:定义不变,但在投影方面几何意义只对二维和三维空间有效。
高维叉积:叉积在k维下的定义是三行k列的行列式,第一行为各维度的单位向量,二三行为两个点各自在对应维度的坐标。

注意:
(1)严格意义上,向量叉积是一个(更高维,二维向量叉积为三维)的向量,模长为 x 1 y 2 − x 2 y 1 x_1y_2-x_2y_1 x1y2x2y1,方向垂直与纸面,遵循右手定则,这也是叉积可以表示负面积的原因。
(被叉积表示面积的平行四边形是叉积在二维平面内的投影)。
(2)以下模板中的垂直向量并没有考虑方向的问题。

Code
struct V
{
   double x,y;
   V():x(0),y(0){};
   V(double a,double b):x(a),y(b){};	
}//点和向量的存储

inline void input(V &a){a.x=read();a.y=read();}

void print(const V &a,int op=1){printf("%.10lf %.10lf",a.x,a.y);putchar(op?10:32);}
//op=endl or space

inline V operator + (const V &a,const V &b){return (V){a.x+b.x,a.y+b.y};}
inline V operator - (const V &a,const V &b){return (V){a.x-b.x,a.y-b.y};}

inline V operator * (const V &a,const double &x){return (V){a.x*x,b.y*x};}
inline V operator * (const double &x,const V &a){return (V){a.x*x,b.y*x};}
inline V operator / (const V &a,const double &x){return (V){a.x/x,b.y/x};}

inline bool operator == (const V &a,const V &b){return abs(a.x-b.x)<eps && abs(a.y-b.y)<eps;}
inline bool operator != (const V &a,const V &b){return !(a==b);}

inline double operator * (const V &a,const V &b){return a.x*b.x+a.y*b.y;}
inline double operator ^ (const V &a,const V &b){return a.x*b.y-b.x*a.y;}

inline double len (const V &a,const V &b){return sqrt(a.x*b.x+a.y*b.y);}

inline V mid(const V &a,const V &b){return (V){(a.x+b.x)/2,(a.y+b.y)/2};}中点坐标公式求中点
inline V cui(const V &a){return (V){a.y,-a.x};}//求垂直向量,使用k1*k2=-1的性质
inline V danwei(const V &a){return a/len(a);}//求单位向量

inline double tri_S(const V &a,const V &b,const V &c){return abs((b-a)*(c-a))/2;}//求向量或三点所成三角形面积

inline bool operator < (const V &a,const V &b){return a.x<b.x || (abs(a.x-b.x)<eps && a.y<b.y-eps);}
//这个向量的大小比较是将向量按照x为第一关键字,y为第二关键字,升序排列。
//这个算符会在求凸包中被大量使用,平时倒是没什么用

角度相关:

向量夹角:

用向量点积易得。
这个角的取值范围是 [ 0 , π ] [0,π] [0,π].

inline double angle(const V &a,const V &b){return acos( a*b / len(a) / len(b));}
inline bool dun(const V &a,const V &b,const V &c){return ((b-a)*(c-a))<-eps;}//angle:BAC
inline bool rui(const V &a,const V &b,const V &c){return ((b-a)*(c-a))>eps;}
inline bool zhi(const V &a,const V &b,const V &c){return abs(((b-a)*(c-a)))<eps;}

向量的旋转:

设原向量为 ( x , y ) (x,y) (x,y),旋转角度为 θ θ θ,(注意:θ的正负判断遵循右手定则,即逆时针旋转的角为正角),
则旋转后的得到向量为 ( x c o s θ − y s i n θ , x s i n θ + y c o s θ ) (xcosθ-ysinθ,xsinθ+ycosθ) (xcosθysinθ,xsinθ+ycosθ)

证明:用复数乘法,在复平面内 ( x , y i ) ⋅ ( c o s θ , s i n θ i ) (x,yi)·(cosθ,sinθi) (x,yi)(cosθ,sinθi),结合复平面的性质可得 ( x c o s θ − y s i n θ , i x s i n θ + i y c o s θ ) (xcosθ-ysinθ,ixsinθ+iycosθ) (xcosθysinθ,ixsinθ+iycosθ),结果同上.

inline V rotate(const V &a,const double t)
{
	double s=sin(t),c=cos(t);
	return (V){a.x*c-a.y*s,a.x*s+a.y*c};	
}

你可能感兴趣的:(计算几何,模板,几何学,算法)