一,定义和约定
# define pi acos(-1);
const double eps = 1e-8;
- 由在同一平面且不再同一直线上的多条线段首尾顺次连接且不相交所组成的图形叫多边形
- 简单多边形是除相邻边外其它边不相交的多边形
- 过多边形的任意一边做一条直线,如果其他各个顶点都在这条直线的同侧,则把这个多边形叫做凸多边形,任意凸多边形外角和均为360°, 任意凸多边形内角和为(n−2)180°
二,叉积和点积
1,点积(内积)
- 定义: A ⋅ B = ∣ A ∣ ∣ B ∣ c o s ( C ) A·B = |A||B|cos(C) A⋅B=∣A∣∣B∣cos(C)
- 几何意义:向量A在向量B上的投影与B的长度的乘积。
double dot(Point a, Point b) { return a.x * b.x + a.y * b.y; }
double dot(pdd a , pdd b) {return (a.x*b.x) + (a.y*b.y); }
2,外积(叉积)
- 定义: A x B = ∣ A ∣ ∣ B ∣ s i n ( C ) AxB = |A||B|sin(C) AxB=∣A∣∣B∣sin(C)
- 几何意义:向量A与B张成的平行四边形的有向面积。B在A的逆时针方向为正。
double cross(Point a, Point b) { return a.x * b.y - b.x * a.y; }
double cross(pdd a, pdd b) { return a.x * b.y - b.x * a.y; }
三,基本操作
1,浮点数的比较
- s i g n sign sign 符号
- c m p cmp cmp 比较
int sign(double x)
{
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
return 1;
}
int cmp(double x, double y)
{
if (fabs(x - y) < eps) return 0;
if (x < y) return -1;
return 1;
}
2,向量与向量
2.1 计算模长
double get_len(pdd a)
{
return sqrt(dot(a,a));
}
2.2 计算向量夹角
double get_angle(pdd a,pdd b)
{
double p = dot(a,b);
return acros (p / get_dist(a) / get_dist(b));
}
2.3 计算两个向量构成的平行四边形有向面积
注:三个点的有向面积 b->a 与 c->a
double area (pdd a,pdd b,pdd c)
{
return cross(b-a,c-a);
}
2.4 向量A顺时针旋转C的角度:
double spin (pdd a,double angle)
{
return {a.x*cos(angle) + a.y*sin(angle),-a.x*sin(angle) + a.y*cos(angle)};
}
3,点与线
3.1 直线表示
(1) 一般式 ax + by + c = 0
(2) 点向式 p0 + vt
(3) 斜截式 y = kx + b
3.2 直线操作
(1) 判断点在直线上 A x B = 0
(2) 两直线相交
// cross(v, w) == 0则两直线平行或者重合
double get_line_join(pdd p,pdd v,pdd q,pdd w)
{
pdd tem = p-q;
double t = cross(w,tem) / cross(v,w);
return p + v * t;
}
(3) 点到直线的距离
double dist_to_line(pdd p,pdd a,pdd b)
{
pdd v = p - a;
pdd w = b - a;
pdd tem = cross(v,w) / get_len(w);
return fabs(tem);
}
(4) 点到线段的距离
double dist_to_seg (pdd p,pdd a,pdd b)
{
if(a==b) return get_dist(p - a);
pdd v = p -a;
pdd w = b -a;
pdd t = p -b;
if(sign(dot(w,v)) < 0) return get_len(v);
if(sign(dot(w,t)) > 0) return get_len(t);
return dist_to_line(p,a,b);
}
(5) 点在直线上的投影
double get_projection_to_line(pdd p,pdd a,pdd b)
{
pdd w = b-a;
pdd v = p-a;
return a + w*(dot(v,w)/dot(w,w));
}
(6) 点是否在线段上
bool is_on_seg (pdd p,pdd a,pdd b)
{
pdd w = b-a;
pdd v = p-a;
pdd t = p-b;
return sign(cross(w,v))==0 && sign(dot(v,t))<=0;
}
(7) 判断两线段是否相交
bool is_seg_join(pdd a1,pdd b1,pdd a2,pdd b2)
{
pdd bas_1 = b1-a1;
pdd bas_2 = b2-a2;
double c1 = cross(a2-a1,bas_1);
double c2 = cross(b2-a1,bas_1);
double c3 = cross(b1-a2,bas_2);
double c4 = cross(a1-a2,bas_2);
return sign(c1)*sign(c2) <=0 && sign(c3)*sign(c4)<=0;
}
4,三角形
- 面积
1,叉积
2,海伦公式 p = ( a + b + c ) / 2 p = (a + b + c) / 2 p=(a+b+c)/2 , S = s q r t ( p ( p − a ) ∗ ( p − b ) ∗ ( p − c ) ) S = sqrt(p(p - a) * (p - b) * (p - c)) S=sqrt(p(p−a)∗(p−b)∗(p−c))
5,一般多边形
- 5.1求多边形面积(不一定是凸多边形)
我们可以从第一个顶点除法把凸多边形分成n − 2个三角形,然后把面积加起来。(使用叉积)
double polygon_area(Point p[], int n)
{
double s = 0;
for (int i = 1; i + 1 < n; i ++ )
s += cross(p[i] - p[0], p[i + 1] - p[i]);
return s / 2;
}
- 5.2 判断点是否在多边形内(不一定是凸多边形)
a, 射线法,从该点任意做一条和所有边都不平行的射线。交点个数为偶数,则在多边形外,为奇数,则在多边形内。
b, 转角法
- 5.3 判断点是否在凸多边形内
只需判断点是否在所有边的左边(逆时针存储多边形)。
6,皮克定理
- 指一个计算点阵中顶点在格点上的多边形面积公式该公式可以表示为 S = a + b / 2 − 1 S = a + b/2 - 1 S=a+b/2−1
- 其中 a a a表示多边形内部的点数, b b b表示多边形边界上的点数,S表示多边形的面积。