计算几何板子

//上交计算几何算法
/****************************************
* 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))
原文地址:https://www.cnblogs.com/zpj61/p/14586852.html