计算几何基础知识及基础模板

前置知识

  1. \(\pi=\arccos(-1)\)
  2. 余弦定理 \(c^2=a^2+b^2-2ab\cos\theta\)

浮点数比较

const double eps=1e-8;//根据题意适时调整
int sign(double x)
{//符号函数
    if(fabs(x)<eps)return 0;//注意fabs在头文件<cmath>中
    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;
}

向量

  1. 向量的加减法和数乘
  2. 内积(点积) \(\vec A\cdot\vec B=\left |\vec A\right|\cdot\left|\vec B\right|\cos\theta\)
    • 几何意义:向量 \(A\) 在向量 \(B\) 上的投影与 \(B\) 的长度的乘积
    • 代码实现
      double dot(Point a,Point b)
      {//求向量A,B的内积
          return a.x*b.x+a.y*b.y;
      }
      
  3. 外积(叉积) \(\vec A\times\vec B=\left |\vec A\right|\cdot\left|\vec B\right|\sin\theta\)
    • 几何意义:向量 \(A\) 与向量 \(B\) 张成的平行四边形的有向面积,\(B\)\(A\) 的逆时针方向为正
    • 代码实现
      double cross(Point a,Point b)
      {//求向量A,B的外积
          return a.x*b.y-a.y*b.x;
      }
      
    • 常用函数
      • 取模

        double get_length(Point a)
        {//求一个向量的模
            return sqrt(dot(a,a));
        }
        
      • 计算向量的夹角

        已知 \(\vec A\cdot\vec B=\left|\vec A\right|\cdot\left|\vec B\right|\cos \theta\)

        可以推得 \(\cos\theta=\frac{\vec A\cdot\vec B}{\left|\vec A\right|\cdot\left|\vec B\right|}\)

        因此 \(\theta=\arccos(\frac{\vec A\cdot\vec B}{\left|\vec A\right|\cdot\left|\vec B\right|})\)

        double get_angle(Point a,Point b)
        {//求向量A,B的夹角(有方向:从A转到B)
            return acos(dot(a,b)/get_length(a)/get_length(b));
        }
        
      • 计算两个向量构成的平行四边形有向面积

        double area(Point a,Point b,Point c)
        {//叉积
            return cross(b-a,c-a);
        }
        
      • 向量 \(A\) 顺时针旋转 \(C\) 的角度

        直接给出结论:相当于将向量 \((x,y)\) 乘一个如下的矩阵

        \[\begin{bmatrix} \cos\theta &-\sin\theta \\ \sin\theta &\cos\theta \end{bmatrix} \]

        \[(x,y) \begin{bmatrix} \cos\theta &-\sin\theta \\ \sin\theta &\cos\theta \end{bmatrix}=(x\cos\theta+y\sin\theta,-x\sin\theta+y\cos\theta) \]

        Point rotate(Point a,double angle)
        {//将向量A顺时针旋转angle度
            return Point({a.x*cos(angle)+a.y*sin(angle),-a.x*sin(angle)+a.y*cos(angle)});
        }
        
  4. 点与线
    • 直线定理
      • 一般式 \(ax+by+c=0\)
      • 点向式 \(p0+\vec vt\)
      • 斜截式 \(y=kx+b\)
    • 常用操作
      • 判断点在直线上 \(\vec A\times \vec B=0\)

      • 两直线相交

        //cross(v,w)==0;则两直线平行或重合
        Point get_line_intersection(Point p,vector v,Point q,vector w)
        {//求向量P,Q的交点
            vector u=p-q;
            double t=cross(w,u)/cross(v,w);
            return p+v*t;
        } 
        
      • 点到直线的距离

        double distance_to_line(Point p,Point a,Point b)
        {//给定一点P和一条直线AB,求P到AB的距离
            vector v1=b-a,v2=p-a;//取出两向量AB,AP
            return fabs(cross(v1,v2)/get_length(v1));
        }
        
      • 点到线段的距离

        double distance_to_segment(Point p,Point a,Point b)
        {//给定一点P和一条线段AB,求P到AB的距离
            if(a==b)return get_length(p-a);//特判A,B是一个点
            vector v1=b-a,v2=p-a,v3=p-b
            if(sign(dot(v1,v2))<0)return get_length(v2);//当前夹角超过90度,直接返回线段PA长度即可
            if(sign(dot(v1,v3))>0)return get_length(v2);//当前夹角小于90度,直接返回线段PB长度即可
            return distance_to_line(p,a,b);//否则直接返回P到直线AB距离即可
        }
        
      • 点在直线上的投影

        double get_line_projection(Point p,Point a,Point b)
        {//求向量AP在向量AB上的投影
            vector v=b-a;
            return a+v*(dotv,p-a)/dot(v,v);
        }
        
      • 点是否在线段上

        bool on_segment(Point p,Point a,Point b)
        {//判断P是否在线段AB上
            return sign(cross(p-a,p-b)==0&&sign(dot(p-a,p-b)))<=0;//如果P在直线上,首先要保证向量AP,BP共线,同时要保证P不在线段的两侧
            //即向量AP和BP方向相反,点积小于等于0
        }
        
      • 判断两线段是否相交

        跨立实验:

        对于两线段 \(A_1A_2\)\(B_1B_2\) 判断是否 \(A_1\)\(A_2\) 在线段 \(B_1B_2\) 两侧,同样也判断 \(B_1\)\(B_2\) 是否在 \(A_1A_2\) 两侧,如果都成立,说明线段 \(A_1A_2\) 和线段 \(B_1B_2\) 相交,否则不相交

        bool segment_intersection(Point a1,Point a2,Point b1,Point b2)
        {//判断线段A1A2与线段B1B2是否相交
            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;
        }
        
  5. 多边形
    • 三角形

      • 面积
        • 叉积(坐标)

        • 海伦公式(边长)

          \(p=\frac{a+b+c}{2}\)

          \(S=\sqrt{p(p-a)(p-b)(p-c)}\)

      • 三角形四心
        • 外心,外接圆圆心

          三边中垂线交点,到三角形三个顶点的距离相等

        • 内心,内切圆圆心

          角平分线的交点,到三边距离相等

        • 垂心

          三条垂线交点

        • 重心

          三条中线交点,到三个顶点的距离的平方和最小的点,三角形内到三边距离之积最大的点

    • 普通多边形

      通常按逆时针存储所有点

      • 定义

        • 多边形

          由在同意平面且不在同一直线上的多条线段首尾顺次连接且不相交所组成的图形叫做多边形

        • 简单多边形

          简单多边形是除相邻边外其他边不相交的多边形

        • 凸多边形

          过多边形的任意一边做一条直线,如果其他各个顶点都在这条直线的同侧,则把这个多边形叫做凸多边形

          任意凸多边形外角和均为 \(360°\)

          任意凸多边形内角和为 \((n-2)\times 180°\)

      • 常用函数

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

          我们可以从第一个顶点出发把凸多边形三角剖分成 \(n-2\) 个三角形,然后把面积加起来

          double polygon_area(Point p[],int n)
          {//求多边形P的面积,共有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;
          }
          
        • 判断一个点是否在多边形内

          • 射线法

            从该点任意做一条和所有边都不平行的射线。交点个数为偶数,则在多边形外,为奇数,则在多边形内。

          • 转角法

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

          • 皮克定理

            皮克定理是指一个计算点阵中顶点在格点上的多边形面积公式该公式可以表示为:

            \[S = a + \frac{b}{2} - 1 \]

            其中 \(a\) 表示多边形内部的点数,\(b\) 表示多边形边界上的点数,\(S\) 表示多边形的面积。

  6. 圆(咕咕咕)
    • 圆与直线交点
    • 两圆交点
    • 点到圆的切线
    • 两圆公切线
    • 两圆相交面积

文章内容来源于:acwing视频讲解

posted @ 2023-06-13 06:55  week_end  阅读(22)  评论(0编辑  收藏  举报