Luckyleaves's Blog

stay hungry,stay foolish greedy and lucky

计算几何

毒瘤码量类。

前置知识点

  • $pi = acos(-1)$。
  • 余弦定理 $c^2 = a^2 + b^2 - 2ab \cos(t)$。

浮点数的比较

1
2
3
4
5
6
7
8
9
10
11
12
13
const double eps = 1e-8;
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;
}

向量

  • 向量的加减法和数乘运算

内积(点积)

  • $ A·B = |A||B|cos(C)$

  • 几何意义:向量A在向量B上的投影与B的长度的乘积。

  • 代码实现

    1
    2
    3
    4
    double dot(Point a, Point b)
    {
    return a.x * b.x + a.y * b.y;
    }

外积(叉积)

  • $AxB = |A||B| \sin(C)$

  • 几何意义:向量A与B张成的平行四边形的有向面积。B在A的逆时针方向为正。

  • 代码实现

    1
    2
    3
    4
    double cross(Point a, Point b)
    {
    return a.x * b.y - b.x * a.y;
    }

常用函数

  • 取模

    1
    2
    3
    4
    double get_length(Point a)
    {
    return sqrt(dot(a, a));
    }
  • 计算向量夹角

      
    1
    2
    3
    4
    double get_angle(Point a, Point b)
    {
    return acos(dot(a, b) / get_length(a) / get_length(b));
    }
  • 计算两个向量构成的平行四边形有向面积

    1
    2
    3
    4
    double area(Point a, Point b, Point c)
    {
    return cross(b - a, c - a);
    }
  • 向量A顺时针旋转C的角度:

    1
    2
    3
    4
    Point rotate(Point a, double angle)
    {
    return Point(a.x * cos(angle) + a.y * sin(angle), -a.x * sin(angle) + a.y * cos(angle));
    }

点与线

直线定理

  • 一般式 $ax + by + c = 0$

  • 点向式 $p_0 + \vec vt$

  • 斜截式 $y = kx + b$

常用操作

  • 判断点在直线上 $\vec A \times \vec B = 0$

  • 两直线相交

    1
    2
    3
    4
    5
    6
    7
    //  cross(v, w) == 0则两直线平行或者重合
    Point get_line_intersection(Point p, Vector v, Point q, vector w)
    {
    vector u = p - q;
    double t = cross(w, u) / cross(v, w);
    return p + v * t;
    }
  • 点到直线的距离

    1
    2
    3
    4
    5
    double distance_to_line(Point p, Point a, Point b)
    {
    vector v1 = b - a, v2 = p - a;
    return fabs(cross(v1, v2) / get_length(v1));
    }
  • 点到线段的距离

    1
    2
    3
    4
    5
    6
    7
    8
    double distance_to_segment(Point p, Point a, Point b)
    {
    if (a == b) return get_length(p - a);
    Vector v1 = b - a, v2 = p - a, v3 = p - b;
    if (sign(dot(v1, v2)) < 0) return get_length(v2);
    if (sign(dot(v1, v3)) > 0) return get_length(v3);
    return distance_to_line(p, a, b);
    }
  • 点在直线上的投影

    1
    2
    3
    4
    5
    double get_line_projection(Point p, Point a, Point b)
    {
    Vector v = b - a;
    return a + v * (dot(v, p - a) / dot(v, v));
    }
  • 点是否在线段上

    1
    2
    3
    4
    bool on_segment(Point p, Point a, Point b)
    {
    return sign(cross(p - a, p - b)) == 0 && sign(dot(p - a, p - b)) <= 0;
    }
  • 判断两线段是否相交

    1
    2
    3
    4
    5
    6
    bool segment_intersection(Point a1, Point a2, Point b1, Point b2)
    {
    double c1 = cross(a2 - a1, b1 - a1), c2 = cross(a2 - a1, b2 - a1);
    double c3 = cross(b2 - b1, a2 - b1), c4 = cross(b2 - b1, a1 - b1);
    return sign(c1) * sign(c2) <= 0 && sign(c3) * sign(c4) <= 0;
    }

多边形

三角形

  • 面积

    1
    2
    3
    4
    (1) 叉积
    (2) 海伦公式:
    p = (a + b + c) / 2;
    S = sqrt(p(p - a) * (p - b) * (p - c));
  • 三角形四心

    1
    2
    3
    4
    5
    6
    7
    8
    (1) 外心,外接圆圆心
    三边中垂线交点。到三角形三个顶点的距离相等
    (2) 内心,内切圆圆心
    角平分线交点,到三边距离相等
    (3) 垂心
    三条垂线交点
    (4) 重心
    三条中线交点(到三角形三顶点距离的平方和最小的点,三角形内到三边距离之积最大的点)

    普通多边形

    • 通常按逆时针存储所有点

    定义

      (1) 多边形
          由在同一平面且不再同一直线上的多条线段首尾顺次连接且不相交所组成的图形叫多边形
      (2) 简单多边形
          简单多边形是除相邻边外其它边不相交的多边形
      (3) 凸多边形
          过多边形的任意一边做一条直线,如果其他各个顶点都在这条直线的同侧,则把这个多边形叫做凸多边形
          任意凸多边形外角和均为360°
          任意凸多边形内角和为(n-2)180°
    

    常用函数

    • 求多边形面积(不一定是凸多边形)

    • 我们可以从第一个顶点除法把凸多边形分成 $n - 2$个三角形,然后把面积加起来。

      1
      2
      3
      4
      5
      6
      7
      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;
      }
    • 判断点是否在多边形内(不一定是凸多边形)

      1. 射线法,从该点任意做一条和所有边都不平行的射线。交点个数为偶数,则在多边形外,为奇数,则在多边形内。
          2. 转角法
      
    • 判断点是否在凸多边形内

      只需判断点是否在所有边的左边(逆时针存储多边形)。
      

      皮克定理

      皮克定理是指一个计算点阵中顶点在格点上的多边形面积公式该公式可以表示为:
          S = a + b/2 - 1
      其中a表示多边形内部的点数,b表示多边形边界上的点数,S表示多边形的面积。
      

(1) 圆与直线交点
(2) 两圆交点
(3) 点到圆的切线
(4) 两圆公切线
(5) 两圆相交面积