zoukankan      html  css  js  c++  java
  • 计算几何板子

    //上交计算几何算法
    /****************************************
    * COMPUTATIONAL GEOMETRY ROUTINES
    * WRITTEN BY : LIU Yu (C) 2003
    ****************************************/
    //    叉乘
    //    两个点的距离
    //    点到直线距离
    //    返回直线 Ax + By + C =0  的系数
    //    线段
    ////    两个圆的公共面积
    //    矩形
    //    根据下标返回多边形的边
    //    两个矩形的公共面积
    //    多边形  ,逆时针或顺时针给出x,y
    //    多边形顶点
    //    多边形的边
    //    多边形的周长
    //    判断点是否在线段上
    //    判断两条线断是否相交,端点重合算相交
    //    判断两条线断是否平行
    //    判断两条直线断是否相交
    //    直线相交的交点
    //    判断是否简单多边形
    //    求多边形面积
    //    判断是否在多边形上
    //    判断是否在多边形内部
    //    点阵的凸包,返回一个多边形
    //   最近点对的距离
    #include <cmath>
    #include <cstdio>
    #include <memory>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    typedef double TYPE;
    #define Abs(x) (((x)>0)?(x):(-(x)))
    #define Sgn(x) (((x)<0)?(-1):(1))
    #define Max(a,b) (((a)>(b))?(a):(b))
    #define Min(a,b) (((a)<(b))?(a):(b))
    #define Epsilon 1e-10
    #define Infinity 1e+10
    #define Pi 3.14159265358979323846
    TYPE Deg2Rad(TYPE deg)
    {
        return (deg * Pi / 180.0);
    }
    TYPE Rad2Deg(TYPE rad)
    {
        return (rad * 180.0 / Pi);
    }
    TYPE Sin(TYPE deg)
    {
        return sin(Deg2Rad(deg));
    }
    TYPE Cos(TYPE deg)
    {
        return cos(Deg2Rad(deg));
    }
    TYPE ArcSin(TYPE val)
    {
        return Rad2Deg(asin(val));
    }
    TYPE ArcCos(TYPE val)
    {
        return Rad2Deg(acos(val));
    }
    TYPE Sqrt(TYPE val)
    {
        return sqrt(val);
    }
    struct POINT
    {
        TYPE x;
        TYPE y;
        TYPE z;
        POINT() : x(0), y(0), z(0) {};
        POINT(TYPE _x_, TYPE _y_, TYPE _z_ = 0) : x(_x_), y(_y_), z(_z_) {};
    };
    // cross product of (o->a) and (o->b)// 叉乘
    TYPE Cross(const POINT & a, const POINT & b, const POINT & o)
    {
        return (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y);
    }
    // planar points' distance//  两个点的距离
    TYPE Distance(const POINT & a, const POINT & b)
    {
        return Sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z
                    - b.z));
    }
    struct LINE
    {
        POINT a;
        POINT b;
        LINE() {};
        LINE(POINT _a_, POINT _b_) : a(_a_), b(_b_) {}};
    //点到直线距离
    double PointToLine(POINT p0 ,POINT p1 ,POINT p2 ,POINT &cp)
    {
        double d = Distance(p1 ,p2);
        double s = Cross(p1 ,p2 ,p0) / d;
        cp.x = p0.x + s*( p2.y-p1.y) / d;
        cp.y = p0.y - s*( p2.x-p1.x) / d;
        return Abs(s);
    }
    // 返回直线 Ax + By + C =0  的系数
    void Coefficient(const LINE & L, TYPE & A, TYPE & B, TYPE & C)
    {
        A = L.b.y - L.a.y;
        B = L.a.x - L.b.x;
        C = L.b.x * L.a.y - L.a.x * L.b.y;
    }
    void Coefficient(const POINT & p,const TYPE a,TYPE & A,TYPE & B,TYPE & C)
    {
        A = Cos(a);    // 线段
        B = Sin(a);
        C = - (p.y * B + p.x * A);
    }
    struct SEG
    {
        POINT a;
        POINT b;
        SEG() {};
        SEG(POINT  _a_, POINT _b_):a(_a_),b(_b_) {};
    };
    //
    struct CIRCLE
    {
        TYPE x;
        TYPE y;
        TYPE r;
        CIRCLE() {}
        CIRCLE(TYPE _x_, TYPE _y_, TYPE _r_) : x(_x_), y(_y_), r(_r_) {}};
    POINT Center(const CIRCLE & circle)
    {
        return POINT(circle.x, circle.y);
    }
    TYPE Area(const CIRCLE & circle)
    {
        return Pi * circle.r * circle.r;    //两个圆的公共面积
    }
    TYPE CommonArea(const  CIRCLE & A, const CIRCLE & B)
    {
        TYPE area = 0.0;
        const CIRCLE & M = (A.r > B.r) ? A : B;
        const CIRCLE & N = (A.r > B.r) ? B : A;
        TYPE D = Distance(Center(M), Center(N));
        if ((D < M.r + N.r) && (D > M.r - N.r))
        {
            TYPE cosM = (M.r * M.r + D * D - N.r * N.r) / (2.0 * M.r * D);
            TYPE cosN = (N.r * N.r + D * D - M.r * M.r) / (2.0 * N.r * D);
            TYPE alpha = 2.0 * ArcCos(cosM);
            TYPE beta  = 2.0 * ArcCos(cosN);
            TYPE TM = 0.5*M.r*M.r*Sin(alpha);
            TYPE TN=0.5 * N.r * N.r * Sin(beta);
            TYPE FM = (alpha / 360.0) * Area(M);
            TYPE FN = (beta / 360.0) * Area(N);
            area = FM + FN - TM - TN;
        }
        else if (D <=  M.r - N.r)
        {
            area = Area(N);
        }
        return area;
    }
    //    矩形
    //    矩形的线段
    //        2
    //      --------------- b
    //      |               |
    //    3 |               |  1
    //    a ---------------
    //         0
    struct RECT
    {
        POINT a; // 左下点  POINT b;  // 右上点
        RECT() {};
        RECT(const POINT & _a_, const POINT & _b_)
        {
            a = _a_;
            b = _b_;
        }
    };
    //根据下标返回多边形的边
    SEG Edge(const RECT & rect, int idx)
    {
        SEG edge;
        while (idx < 0) idx +=  4;
        switch (idx % 4)
        {
        case 0:
            edge.a = rect.a;
            edge.b = POINT(rect.b.x, rect.a.y);
            break;
        case 1:
            edge.a = POINT(rect.b.x, rect.a.y);
            edge.b = rect.b;
            break;
        case 2:
            edge.a = rect.b;
            edge.b = POINT(rect.a.x, rect.b.y);
            break;
        case 3:
            edge.a = POINT(rect.a.x, rect.b.y);
            edge.b = rect.a;
            break;
        default:
            break;
        }
        return edge;
    }
    TYPE Area(const RECT & rect)
    {
        return (rect.b.x - rect.a.x) * (rect.b.y - rect.a.y);
    }
    //  两个矩形的公共面积
    TYPE CommonArea(const  RECT & A, const RECT & B)
    {
        TYPE area = 0.0;
        POINT LL(Max(A.a.x, B.a.x), Max(A.a.y, B.a.y));
        POINT UR(Min(A.b.x,  B.b.x), Min(A.b.y, B.b.y));
        if ((LL.x <=  UR.x) && (LL.y <= UR.y))
        {
            area = Area(RECT(LL, UR));
        }
        return area;
    }// 多边形  ,逆时针或顺时针给出x,y
    struct POLY
    {
        int n; //n个点  TYPE * x;  //x,y为点的指针,首尾必须重合  TYPE * y;
        POLY() : n(0), x(NULL), y(NULL) {};
        POLY(int _n_, const TYPE * _x_, const TYPE * _y_)
        {
            n = _n_;
            x = new TYPE[n + 1];
            memcpy(x,  _x_, n*sizeof(TYPE));
            x[n] = _x_[0];
            y = new TYPE[n + 1];
            memcpy(y, _y_, n*sizeof(TYPE));
            y[n] = _y_[0];
        }
    };//多边形顶点
    POINT Vertex(const POLY & poly, int idx)
    {
        idx %= poly.n;    //多边形的边
        return POINT(poly.x[idx],  poly.y[idx]);
    }
    SEG Edge(const POLY & poly, int idx)
    {
        idx %= poly.n;
        return SEG(POINT(poly.x[idx],  poly.y[idx]),
                   POINT(poly.x[idx  + 1], poly.y[idx + 1]));
    } //多边形的周长
    TYPE Perimeter(const POLY & poly)
    {
        TYPE p = 0.0;
        for (int i = 0; i < poly.n; i++)
            p = p + Distance(Vertex(poly, i), Vertex(poly, i + 1));
        return p;
    }
    bool IsEqual(TYPE a, TYPE b)
    {
        return (Abs(a - b) < Epsilon);
    }
    bool IsEqual(const POINT & a, const POINT & b)
    {
        return (IsEqual(a.x, b.x) && IsEqual(a.y, b.y));
    }
    bool IsEqual(const LINE & A, const LINE & B)
    {
        TYPE A1, B1, C1;
        TYPE A2, B2, C2;
        Coefficient(A, A1, B1, C1);
        Coefficient(B, A2, B2, C2);
        return IsEqual(A1 * B2, A2 * B1) &&
               IsEqual(A1 * C2, A2 * C1) &&  IsEqual(B1 * C2, B2 * C1);
    }
    // 判断点是否在线段上
    bool IsOnSeg(const SEG & seg, const POINT & p)
    {
        return (IsEqual(p, seg.a) || IsEqual(p, seg.b)) ||
               (((p.x - seg.a.x) * (p.x - seg.b.x) < 0 || (p.y - seg.a.y) * (p.y - seg.b.y) < 0) &&
                (IsEqual(Cross(seg.b, p, seg.a), 0)));
    }
    //判断两条线断是否相交,端点重合算相交
    bool IsIntersect(const SEG & u, const SEG & v)
    {
        return (Cross(v.a, u.b, u.a) * Cross(u.b, v.b, u.a) >=  0) &&
               (Cross(u.a, v.b, v.a) * Cross(v.b, u.b, v.a) >= 0) &&(Max(u.a.x, u.b.x)>=Min(v.
                       a.x, v.b.x))&&(Max(v.a.x, v.b.x)>= Min(u.a.x,u.b.x))&&(Max(u.a.y, u.b.y)>=Min(
                                   v.a.y, v.b.y))&&(Max(v.a.y, v.b.y)>=Min(u.a.y,  u.b.y));
    }
    //判断两条线断是否平行
    bool IsParallel(const LINE & A, const LINE & B)
    {
        TYPE A1, B1, C1;
        TYPE A2, B2, C2;
        Coefficient(A, A1, B1, C1);
        Coefficient(B, A2, B2, C2);
        return (A1*B2==  A2*B1) &&((A1 * C2 != A2 * C1) || (B1 * C2 != B2 * C1));
    }
    //判断两条直线断是否相交
    bool IsIntersect(const LINE & A, const LINE & B)
    {
        return !IsParallel(A, B);    //直线相交的交点
    }
    POINT Intersection(const LINE & A, const LINE & B)
    {
        TYPE A1, B1, C1;
        TYPE A2, B2, C2;
        Coefficient(A, A1, B1, C1);
        Coefficient(B, A2, B2, C2);
        POINT I(0, 0);
        I.x = - (B2 * C1 - B1 * C2) / (A1 * B2 - A2 * B1);
        I.y =   (A2 * C1 - A1 * C2) / (A1 * B2 - A2 * B1);
        return I;
    }
    bool IsInCircle(const CIRCLE & circle, const RECT & rect)
    {
        return (circle.x - circle.r >=  rect.a.x) &&
               (circle.x + circle.r <= rect.b.x) &&(circle.y - circle.r >=  rect.a.y) &&
               (circle.y + circle.r <= rect.b.y);
    }
    //判断是否简单多边形
    bool IsSimple(const POLY & poly)
    {
        if (poly.n < 3) return false;
        SEG L1, L2;
        for (int i = 0; i < poly.n - 1; i++)
        {
            L1 = Edge(poly, i);
            for (int j = i + 1; j < poly.n; j++)
            {
                L2 = Edge(poly, j);
                if (j == i+1)
                {
                    if  (IsOnSeg(L1, L2.b)||IsOnSeg(L2, L1.a))  return false;
                }
                else if (j == poly.n - i - 1)
                {
                    if (IsOnSeg(L1, L2.a) || IsOnSeg(L2, L1.b))  return false;
                }
                else
                {
                    if (IsIntersect(L1, L2))  return false;    // for i
                }
            } // for j
        }
        return true;
    }
    //求多边形面积
    TYPE Area(const POLY & poly)
    {
        if (poly.n < 3) return TYPE(0);
        double s = poly.y[0] * (poly.x[poly.n - 1] - poly.x[1]);
        for (int i = 1; i < poly.n; i++)
        {
            s += poly.y[i] * (poly.x[i - 1] - poly.x[(i + 1) % poly.n]);
        }
        return s/2;
    }
    //判断是否在多边形上
    bool IsOnPoly(const POLY & poly, const POINT & p)
    {
        for (int i = 0; i < poly.n; i++)
        {
            if (IsOnSeg(Edge(poly,  i), p))   return true;
        }
        return false;
    }
    //判断是否在多边形内部
    bool IsInPoly(const POLY & poly, const POINT & p)
    {
        SEG L(p, POINT(Infinity, p.y));
        int count = 0;
        for (int i = 0; i < poly.n; i++)
        {
            SEG S = Edge(poly, i);
            if (IsOnSeg(S, p))
            {
                return false; //如果想让 在poly上则返回 true,则改为true
            }
            if (!IsEqual(S.a.y, S.b.y))
            {
                POINT & q = (S.a.y > S.b.y)?(S.a):(S.b);
                if (IsOnSeg(L, q))
                {
                    ++count;
                }
                else if(!IsOnSeg(L,S.a)&&!IsOnSeg(L,S.b)&&IsIntersect(S,L))
                {
                    ++count;
                }
            }
        }
        return (count % 2 != 0);
    }
    // 点阵的凸包,返回一个多边形
    POLY ConvexHull(const POINT * set, int n)            // 不适用于点少于三个的情况
    {
        POINT * points = new POINT[n];
        memcpy(points, set, n * sizeof(POINT));
        TYPE * X = new TYPE[n];
        TYPE * Y = new TYPE[n];
        int i, j, k = 0, top = 2;
        for(i = 1; i < n; i++)
        {
            if((points[i].y<points[k].y)||((points[i].y==points[k].y)&&
                                           (points[i].x<points[k].x)))
            {
                k  = i;
            }
        }
        std::swap(points[0], points[k]);
        for (i = 1; i < n - 1; i++)
        {
            k = i;
            for (j = i + 1; j < n; j++)
            {
                if ((Cross(points[j], points[k], points[0]) >0)||((Cross(points[j], points[k],
                        points[0]) == 0) && (Distance(points[0], points[j])<Distance(points[0], points[k]
                                                                                    ))))
                {
                    k = j;
                }
            }
            std::swap(points[i], points[k]);
        }
        X[0] = points[0].x;
        Y[0] = points[0].y;
        X[1] = points[1].x;
        Y[1] = points[1].y;
        X[2] = points[2].x;
        Y[2] = points[2].y;
        for (i = 3; i < n; i++)
        {
            while(Cross(points[i],POINT(X[top],Y[top]),POINT(X[top
                        -1],Y[top-1]))>=0)
            {
                top--;
            }
            ++top;
            X[top] = points[i].x;
            Y[top] = points[i].y;
        }
        delete [] points;
        POLY poly(++top, X, Y);
        delete [] X;
        delete [] Y;
        return poly;
    }
    //最近点对的距离, Written By PrincessSnow
    #define MAXN 100000
    POINT pt[MAXN];
    bool cmp(POINT n1, POINT n2)
    {
        return (n1.x<n2.x  || n1.x==n2.x  && n1.y<n2.y);
    }
    double Get(double dis, int mid, int start, int end)
    {
        int s=mid,  e=mid,  i, j;
        double t;
        while(s > start && pt[mid].x - pt[s].x <= dis)     s--;
        while(e < end && pt[e].x - pt[mid].x <=  dis)     e++;
        for(i=s; i <= e; i++)
            for(j=i+1;  j <= e && j <=  i+7; j++)
            {
                t = Distance(pt[i], pt[j]);
                if(t < dis)     dis=t;
            }
        return dis;
    }
    double ClosestPairDistance(int start, int end)
    {
        int m = end-start+1, mid, i;
        double t1, t2, dis=-1, t;
        if(m <= 3)
        {
            for(i=start; i < end; i++)
            {
                t = Distance(pt[i] , pt[i+1]);
                if(t < dis || dis ==  -1)     dis = t;
            }
            t = Distance(pt[start] , pt[end]);
            if(t < dis) dis=t;
            return dis;
        }
        if(m%2  == 0)     mid = start + m/2 - 1;
        else               mid = start + m/2;
        if(m%2  == 0)
        {
            t1 = ClosestPairDistance(start, mid);
            t2 = ClosestPairDistance(mid+1, end);
        }
        else
        {
            t1 =ClosestPairDistance(start,mid);
            t2=ClosestPairDistance(mid+1,end);
        }
        if(t1 < t2)     dis = t1;
        else          dis = t2;
        dis = Get(dis, mid, start, end);
        return dis;
    }
    
    
    //1.  球面上两点最短距离
    // 计算圆心角lat 表示纬度, -90 <= w <= 90, lng 表示经度
    // 返回两点所在大圆劣弧对应圆心角,  0 <= angle <=  pi
    double angle(double lng1, double lat1, double lng2, double lat2)
    {
        double dlng = fabs(lng1 - lng2) * pi / 180;
        while(dlng >= pi+pi)      dlng -= pi+pi;
        if(dlng > pi)     dlng = pi + pi - dlng;
        lat1 *= pi / 180,     lat2 *= pi / 180;
        return acos( cos(lat1)*cos(lat2)*cos(dlng) + sin(lat1)*sin(lat2) );
    }
    // 计算距离, r为球半径
    double line_dist(double  r, double lng1, double lat1, double lng2, double lat2)
    {
        double dlng = fabs(lng1 - lng2) * pi / 180;
        while(dlng  >= pi+pi)      dlng -= pi+pi;
        if(dlng > pi)     dlng = pi + pi - dlng;
        lat1 *= pi / 180,     lat2 *= pi / 180;
        return r*sqrt(2-2*( cos(lat1)*cos(lat2)*cos(dlng)+ sin(lat1)*sin(lat2)) );
    }
    // 计算球面距离, r为球半径
    double sphere_dist(double r, double lng1,double lat1,double lng2, double lat2)
    {
        return r * angle(lng1, lat1, lng2, lat2);
    }
    
    
    //2.  三点求圆心坐标
    double GetRadiusBy3Points(double  x1, double y1,
                              double x2, double y2,  double x3, double y3, double &x, double &y)
    {
        // 由 ( x - x1 )^2 + ( y - y1 )^2 = ( x - x2 )^2 + ( y - y2 )^2 得
        // 2*( x2 - x1 )*x + 2*( y2 - y1 )*y = x2^2 - x1^2 + y2^2 - y1^2
        // 同理得
        // 2*( x3 - x2 )*x + 2*( y3 - y2 )*y = x3^2 - x2^2 + y3^2 - y2^2
        // 由行列式解方程得 x , y
        double a11, a12, a21, a22, b1, b2;
        double d, d1, d2 ;
        a11 = 2 * ( x3 - x2 );
        a12 = 2 * ( y3 - y2 );
        a21 = 2 * ( x2 - x1 );
        a22 = 2 * ( y2 - y1 );
        b1 = x3*x3 - x2*x2 + y3*y3 - y2*y2;
        b2 = x2*x2 - x1*x1 + y2*y2 - y1*y1;
        d = a11*a22 - a12*a21;
        d1 = b1*a22 - a12*b2;
        d2 = a11*b2 - b1*a21;
        // x , y 是圆心坐标
        x = d1 / d;
        y = d2 / d;
        return  (x1 - x)*(x1 - x) + (y1 - y)*(y1 - y);
    }
    //
    //
    //3.  三角形几个重要的点
    //设三角形的三条边为a,  b, c,且不妨假设a <=  b <=  c
    //三角形的面积可以根据海伦公式算得,如下:
    //s = sqrt(p * (p - a) * (p - b) * (p - c)), p = (a +  b + c) / 2
    //1. 费马点(该点到三角形三个顶点的距离之和最小)
    //有个有趣的结论:若三角形的三个内角均小于120度,
    //那么该点连接三个顶点形成的三个角均为120度;若三角形存在一个内角
    //大于120度,则该顶点就是费马点)
    //计算公式如下:
    //若有一个内角大于120度(这里假设为角C),则距离为a  +  b
    //若三个内角均小于120度,则距离为
    //sqrt((a * a +  b * b + c * c + 4 * sqrt(3.0) * s) / 2),其中
    //2.内心----角平分线的交点
    //令x =  (a + b - c) / 2, y =  (a - b +  c) / 2, z =  (-a +  b + c) / 2, h =  s / p
    // 计算公式为 sqrt(x * x + h * h) + sqrt(y * y +  h * h) +  sqrt(z * z +  h * h)
    //3.重心----中线的交点
    //ACM算法模板集
    //  - 46 -
    //计算公式如下:
    //2.0 / 3 * (sqrt((2 * (a * a +  b * b) - c * c) / 4)
    //             +  sqrt((2 * (a * a +  c * c) - b * b) / 4)
    //             +  sqrt((2 * (b * b + c * c) - a * a) / 4))
    //4.垂心----垂线的交点
    //计算公式如下:
    //3 * (c / 2 / sqrt(1 - cosC * cosC))
  • 相关阅读:
    「from CommonAnts」寻找 LCM
    P3380 二逼平衡树 [树状数组套可持久化主席树]
    [模板]二次剩余(无讲解)
    [校内训练19_09_10]sort
    [校内训练19_09_06]排序
    [校内训练19_09_06]直径
    [校内训练19_09_05]ca
    [校内训练19_09_02]不同的缩写
    [校内训练19_09_03]c Huge Counting
    [校内训练19_09_02]C
  • 原文地址:https://www.cnblogs.com/zpj61/p/14586852.html
Copyright © 2011-2022 走看看