计算几何模板v0.6

/*----------------------基础----------------------*/
const double pi = acos(-1);
const double eps = 1e-13;
const int maxp = 100 + 10;    //多边形最多点数
int equal(double a, double b) //判断double相等
{
    if (fabs(a - b) <= eps)
        return 1;
    else
        return 0;
}
int sign(double num) //判断符号,负数返回-1,正数返回1,零返回0
{
    if (fabs(num) < eps) return 0;
    if (num > 0) return 1;
    return -1;
}
int dcmp(double a, double b) //浮点数比较,小于-1,等于0,大于1
{
    if (fabs(a - b) <= eps) return 0;
    if (a < b) return -1;
    return 1;
}
/*---------------------------------------------------*/

/*----------------------点,向量----------------------*/
struct point
{
    double x, y;
    point(double x1 = 0, double y1 = 0) { x = x1, y = y1; }
    point operator+(point a) { return point(x + a.x, y + a.y); }
    point operator-(point a) { return point(x - a.x, y - a.y); }
    point operator*(double t) { return point(x * t, y * t); }
    point operator/(double t) { return point(x / t, y / t); }
    bool operator!=(point a) { return (!equal(x, a.x)) || (!(equal(y, a.y))); }
    bool operator==(point a) { return equal(x, a.x) && equal(y, a.y); }
};
point rotate(point p, double theta) //将点p旋转θ弧度
{
    return point(p.x * cos(theta) - p.y * sin(theta), p.x * sin(theta) + p.y * cos(theta));
}
double dot(point a, point b) { return a.x * b.x + a.y * b.y; }                                  //点乘
double cross(point a, point b) { return a.x * b.y - a.y * b.x; }                                //叉乘
double len(point a) { return sqrt(dot(a, a)); }                                                 //向量模长
double dis(point a, point b) { return len(b - a); }                                             //求两点距离
double dis2(point a, point b) { return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y); } //返回两点距离平方
double area(point a, point b, point c) { return fabs(cross(b - a, c - a) / 2.0); }              //三点组成的三角形面积
double angle(point a, point b)                                                                  //两向量夹角
{
    double num = (dot(a, b) / len(a)) / len(b);
    if (num > 1.0)
        num = 1.0;
    else if (num < -1.0)
        num = -1.0;
    return acos(num);
}
point projection(point p0, point p1, point p2) //求p0到p1p2上的投影
{
    point v0 = p2 - p1;
    point v1 = p0 - p1;
    double num = dot(v0, v1) / len(v0);
    point pro = p1 + v0 * (num / len(v0));
    return pro;
}
double project(point p0, point p1, point p2)
{
    point v0 = p2 - p1;
    point v1 = p0 - p1;
    return dot(v0, v1) / len(v0);
}
point reflection(point p0, point p1, point p2) //求p0关于p1p2上的对称点
{
    point pro = projection(p0, p1, p2);
    point ans = p0 + (pro - p0) * 2.0;
    return ans;
}
point clp[maxn];            //平面最近点对
double merge1(int l, int r) //平面最近点对区间合并
{
    double res = 0x3f3f3f3f;
    if (r - l <= 3)
    {
        for (int i = l; i <= r; i++)
            for (int j = i + 1; j <= r; j++)
                res = min(res, dis(clp[i], clp[j]));
        return res;
    }
    int mid = (l + r) >> 1;
    res = min(res, merge1(l, mid));
    res = min(res, merge1(mid + 1, r));
    vector<point> tmp;
    for (int i = l; i <= r; i++)
    {
        if (fabs(clp[i].x - clp[mid].x) >= res) continue;
        tmp.push_back(clp[i]);
    }
    sort(tmp.begin(), tmp.end(), [](point a, point b) { return a.y < b.y; });
    for (int i = 0; i < tmp.size(); i++)
    {
        for (int j = i + 1; j < tmp.size() && fabs(tmp[i].y - tmp[j].y) < res; j++)
        {
            res = min(res, dis(tmp[i], tmp[j]));
        }
    }
    return res;
}
double cloest_pair(int cnt1) //求平面最近点对
{
    sort(clp, clp + cnt1, [](point a, point b) {
        if (equal(a.x, b.x)) return a.y < b.y;
        return a.x < b.x;
    });
    double res = merge1(0, cnt1 - 1);
    return res;
}
/*---------------------------------------------------*/

/*----------------------直线,线段----------------------*/
struct line //直线
{
    point s, v;
    line(point s1 = {0, 0}, point v1 = {1, 0}) { s = s1, v = v1; }
};
struct seg //线段
{
    point u, v;
    seg(point u1 = {0, 0}, point v1 = {1, 0}) { u = u1, v = v1; }
};
double angle(line a) //求直线与x轴夹角
{
    return atan2(a.v.y, a.v.x);
}
point intersection(line a, line b) //求直线交点
{
    point u = a.s - b.s;
    double t = cross(b.v, u) / cross(a.v, b.v);
    return a.s + a.v * t;
}
point intersection(seg a, seg b) //求线段交点,记得先判是否相交
{
    line l1(a.u, a.v - a.u), l2(b.u, b.v - b.u);
    return intersection(l1, l2);
}
int relation(line a, line b) //两直线关系,重合3,平行2,垂直1,否则0
{
    if (sign(cross(a.v, b.v)) == 0)
    {
        point v = b.s - a.s;
        if (sign(cross(v, a.v)) == 0)
            return 3;
        else
            return 2;
    }
    else
    {
        if (dcmp(angle(a.v, b.v), pi / 2.0) == 0)
            return 1;
        else
            return 0;
    }
}
int is_intersection(seg a, seg b) //判断线段是否相交,相交返回1,否则返回0
{
    if (min(b.u.x, b.v.x) > max(a.u.x, a.v.x) || min(a.u.x, a.v.x) > max(b.u.x, b.v.x)) return 0;
    if (min(b.u.y, b.v.y) > max(a.u.y, a.v.y) || min(a.u.y, a.v.y) > max(b.u.y, b.v.y)) return 0;
    double num1, num2, num3, num4;
    num1 = cross(b.u - a.u, b.v - a.u);
    num2 = cross(b.u - a.v, b.v - a.v);
    num3 = cross(a.u - b.u, a.v - b.u);
    num4 = cross(a.u - b.v, a.v - b.v);
    if (sign(num1 * num2) <= 0 && sign(num3 * num4) <= 0) return 1;
    return 0;
}
int on_seg(point a, seg b) //判断点是否在线段上
{
    point v1, v2;
    v1 = b.u - a;
    v2 = b.v - a;
    if (a == b.u || a == b.v) return 1;
    if (equal(dot(v1, v2) / len(v1) / len(v2), -1.0)) return 1;
    return 0;
}
double dis(point a, seg b) //求点到线段距离
{
    if (on_seg(a, b)) return 0.0;
    point v1, v2;
    v1 = b.v - b.u;
    v2 = a - b.u;
    double num = dot(v1, v2) / (len(v1) * len(v1));
    if (dcmp(num, 0.0) <= 0)
        return dis(a, b.u);
    else if (dcmp(num, 1.0) >= 0)
        return dis(a, b.v);
    return dis(a, projection(a, b.u, b.v));
}
double dis(seg a, seg b) //求两线段距离
{
    if (is_intersection(a, b)) return 0.0;
    double num1, num2;
    num1 = min(dis(a.u, b), dis(a.v, b));
    num2 = min(dis(b.u, a), dis(b.v, a));
    return min(num1, num2);
}
/*---------------------------------------------------*/

/*----------------------多边形----------------------*/
struct polygon
{
    point p[maxp];
    int cnt;
    polygon() { cnt = 0; }
    void add(point pp) { p[cnt++] = pp; } //加点
};
int stk[maxn];   //求凸包栈
bool used[maxn]; //求凸包标记已使用点
polygon an_poly, ans_an_poly;
void andrew() //求凸包
{
    int top = 0;
    sort(an_poly.p, an_poly.p + an_poly.cnt, [](point a, point b) {
        if (equal(a.x, b.x)) return a.y < b.y;
        return a.x < b.x;
    });
    for (int i = 0; i < an_poly.cnt; i++)
    {
        while (top >= 2 && cross(an_poly.p[stk[top - 1]] - an_poly.p[stk[top - 2]], an_poly.p[i] - an_poly.p[stk[top - 1]]) <= 0)
        {
            if (cross(an_poly.p[stk[top - 1]] - an_poly.p[stk[top - 2]], an_poly.p[i] - an_poly.p[stk[top - 1]]) < 0)
                used[stk[--top]] = false;
            else
                top--;
        }
        stk[top++] = i;
        used[i] = true;
    }
    int tmp = top;
    used[0] = false;
    for (int i = an_poly.cnt - 1; i >= 0; i--)
    {
        if (used[i]) continue;
        while (top >= tmp && cross(an_poly.p[stk[top - 1]] - an_poly.p[stk[top - 2]], an_poly.p[i] - an_poly.p[stk[top - 1]]) <= 0)
            top--;
        stk[top++] = i;
        used[i] = true;
    }
    for (int i = 0; i < top; i++) ans_an_poly.add(an_poly.p[stk[i]]);
}
int is_convex(polygon poly) //判断是否是凸包(逆时针)
{
    if (poly.cnt < 3) return 0;
    point p[maxp];
    int tot = 0;
    p[tot++] = poly.p[0];
    p[tot++] = poly.p[1];
    for (int i = 2; i < poly.cnt; i++)
    {
        point v1, v2;
        v1 = p[tot - 1] - p[tot - 2];
        v2 = poly.p[i] - p[tot - 1];
        if (sign(cross(v1, v2)) == -1) return 0;
        p[tot++] = poly.p[i];
    }
    point v1, v2;
    v1 = p[tot - 1] - p[tot - 2];
    v2 = poly.p[0] - p[tot - 1];
    if (sign(cross(v1, v2)) == -1) return 0;
    return 1;
}
double area(polygon &poly) //求多边形面积
{
    double res = 0;
    if (poly.cnt < 3) return 0;
    for (int i = 1; i < poly.cnt; i++)
    {
        res += cross(poly.p[i], poly.p[i - 1]);
    }
    res += cross(poly.p[0], poly.p[poly.cnt - 1]);
    return fabs(res / 2.0);
}
double len(polygon &poly) //求多边形周长
{
    double res = 0;
    for (int i = 1; i < poly.cnt; i++)
    {
        res += len(poly.p[i] - poly.p[i - 1]);
    }
    res += len(poly.p[0] - poly.p[poly.cnt - 1]);
    return res;
}
int point_in_poly(point p, polygon poly) //点与多边形关系,2多边形内 ,1线段上,0多边形外
{
    seg seg1[110]; //多边形边的数量
    int tot = 0;
    for (int i = 1; i < poly.cnt; i++)
    {
        point u, v;
        u = poly.p[i - 1];
        v = poly.p[i];
        seg1[tot++] = seg(u, v);
    }
    seg1[tot++] = seg(poly.p[poly.cnt - 1], poly.p[0]);
    int flag = 0;
    point u, v;
    for (int i = 0; i < tot; i++)
    {
        if (on_seg(p, seg1[i])) return 1;
        u = seg1[i].u;
        v = seg1[i].v;
        if (((sign(u.y - p.y) > 0) != (sign(v.y - p.y) > 0)) && sign(p.x - (p.y - u.y) * (u.x - v.x) / (u.y - v.y) - u.x) < 0)
            flag ^= 2;
    }
    return flag;
}
int on_right(line a, line b, line c) //判断bc交点是否在a的右边
{
    point o = intersection(b, c);
    if (sign(cross(o - a.s, a.v)) == 1) return 1;
    return 0;
}
line hpi_li[maxn];
int hpi_q[maxn];                         //半平面交双端队列
polygon half_plane_intersection(int cnt) //求半平面交
{
    sort(hpi_li, hpi_li + cnt, [&](line a, line b) {
        double num1, num2;
        num1 = atan2(a.v.y, a.v.x);
        num2 = atan2(b.v.y, b.v.x);
        if (equal(num1, num2)) return sign(cross(b.s - a.s, a.v)) == 1;
        return num1 < num2;
    });
    int hh = 0, tt = -1;
    for (int i = 0; i < cnt; i++)
    {
        if (i > 0 && dcmp(angle(hpi_li[i]), angle(hpi_li[i - 1])) == 0) continue;
        while (hh + 1 <= tt && on_right(hpi_li[i], hpi_li[hpi_q[tt - 1]], hpi_li[hpi_q[tt]])) tt--;
        while (hh + 1 <= tt && on_right(hpi_li[i], hpi_li[hpi_q[hh]], hpi_li[hpi_q[hh + 1]])) hh++;
        hpi_q[++tt] = i;
    }
    while (hh + 1 <= tt && on_right(hpi_li[hpi_q[hh]], hpi_li[hpi_q[tt - 1]], hpi_li[hpi_q[tt]])) tt--;
    while (hh + 1 <= tt && on_right(hpi_li[hpi_q[tt]], hpi_li[hpi_q[hh]], hpi_li[hpi_q[hh + 1]])) hh++;
    hpi_q[++tt] = hpi_q[hh];
    int k = 0;
    polygon ans;
    for (int i = hh; i < tt; i++)
        ans.add(intersection(hpi_li[hpi_q[i]], hpi_li[hpi_q[i + 1]]));
    return ans;
}
polygon rc_poly;
double rotating_calipers() //旋转卡壳求凸包最远点对距离平方,最后一个点和第一个点相同
{
    double res = 0;
    int top1 = rc_poly.cnt - 1;
    for (int i = 0, j = 2; i < top1; i++)
    {
        point s = rc_poly.p[i], e = rc_poly.p[i + 1];
        while (area(s, e, rc_poly.p[j]) <= area(s, e, rc_poly.p[j + 1])) j = (j + 1) % top1;
        res = max(res, max(dis2(rc_poly.p[j], s), dis2(rc_poly.p[j], e)));
    }
    return res;
}

polygon mrc_poly, ans_mrc_poly; //最小矩形覆盖用
void mini_rectangle_coverage()  //最小矩形覆盖
{
    double minarea = 1e20;
    for (int i = 0, j = 2, k = 2, l = 2; i < mrc_poly.cnt; i++)
    {
        point s, e;
        s = mrc_poly.p[i], e = mrc_poly.p[i + 1];
        double num1, num2;
        num1 = area(s, e, mrc_poly.p[j]);
        num2 = area(s, e, mrc_poly.p[j + 1]);
        while (dcmp(area(s, e, mrc_poly.p[j]), area(s, e, mrc_poly.p[j + 1])) < 0) j = (j + 1) % mrc_poly.cnt;
        while (dcmp(project(mrc_poly.p[k], s, e), project(mrc_poly.p[k + 1], s, e)) < 0) k = (k + 1) % mrc_poly.cnt;
        if (i == 0) l = j;
        while (dcmp(project(mrc_poly.p[l], s, e), project(mrc_poly.p[l + 1], s, e)) > 0) l = (l + 1) % mrc_poly.cnt;
        point right = mrc_poly.p[k], up = mrc_poly.p[j], left = mrc_poly.p[l];
        double h = 2.0 * area(s, e, up) / len(e - s);
        double w = fabs(dot(right - left, e - s)) / len(e - s);
        if (h * w < minarea)
        {
            minarea = h * w;
            ans_mrc_poly.cnt = 4;
            ans_mrc_poly.p[0] = s + ((e - s) / len(e - s)) * project(right, s, e);
            ans_mrc_poly.p[3] = s + ((e - s) / len(e - s)) * project(left, s, e);
            point ahh = rotate(e - s, pi / 2.0) / len(e - s);
            ans_mrc_poly.p[1] = ans_mrc_poly.p[0] + ahh * h;
            ans_mrc_poly.p[2] = ans_mrc_poly.p[3] + ahh * h;
        }
    }
}
/*---------------------------------------------------*/
/*----------------------圆----------------------*/
struct circle
{
    point c;
    double r;
    circle(point c1 = {0, 0}, double r1 = 0) { c = c1, r = r1; }
};
double area(circle ci) { return pi * ci.r * ci.r; } //圆面积
double len(circle ci) { return 2.0 * pi * ci.r; }   //圆周长
circle get_circle(point a, point b, point c)        //求三点外接圆
{
    circle res;
    line l1((a + b) / 2.0, rotate(b - a, pi / 2.0));
    line l2((a + c) / 2.0, rotate(c - a, pi / 2.0));
    res.c = intersection(l1, l2);
    res.r = dis(res.c, a);
    return res;
}
circle mini_circle_coverage(point p[], int cnt)
{
    srand(time(0));
    random_shuffle(p, p + cnt);
    circle res(p[0], 0);
    for (int i = 1; i < cnt; i++)
    {
        if (dcmp(dis(res.c, p[i]), res.r) <= 0) continue;
        circle now(p[i], 0);
        for (int j = 0; j < i; j++)
        {
            if (dcmp(dis(now.c, p[j]), now.r) <= 0) continue;
            now.c = (p[i] + p[j]) / 2.0;
            now.r = dis(now.c, p[i]);
            for (int k = 0; k < j; k++)
            {
                if (dcmp(dis(now.c, p[k]), now.r) <= 0) continue;
                now = get_circle(p[i], p[j], p[k]);
            }
        }
        res = now;
    }
    return res;
}
/*---------------------------------------------------*/

/*----------------------三维----------------------*/
struct point3 //三维点
{
    double x, y, z;
    point3(double x1 = 0, double y1 = 0, double z1 = 0) { x = x1, y = y1, z = z1; }
    point3 operator+(point3 a) { return point3(x + a.x, y + a.y, z + a.z); }
    point3 operator-(point3 a) { return point3(x - a.x, y - a.y, z - a.z); }
    point3 operator*(double t) { return point3(x * t, y * t, z * t); }
    point3 operator/(double t) { return point3(x / t, y / t, z / t); }
    bool operator!=(point3 a) { return (!equal(x, a.x)) || (!(equal(y, a.y))) || (!equal(z, a.z)); }
    bool operator==(point3 a) { return equal(x, a.x) && equal(y, a.y) && equal(z, a.z); }
} pt3[maxn];
struct line3
{
    point3 s, e;
    line3() {}
    line3(point3 _s, point3 _e)
    {
        s = _s;
        e = _e;
    }
};
struct plane
{
    int p[3];
    plane(int a = 0, int b = 0, int c = 0) { p[0] = a, p[1] = b, p[2] = c; }
};
double dis(point3 a, point3 b) //两点距离
{
    double dx = a.x - b.x, dy = a.y - b.y, dz = a.z - b.z;
    return sqrt(dx * dx + dy * dy + dz * dz);
}
double rand_eps() { return ((double)rand() / RAND_MAX - 0.5) * eps; }                                                    //随机抖动
point3 shake(point3 a) { return a + point3(rand_eps(), rand_eps(), rand_eps()); }                                        //抖动
double len(point3 a) { return sqrt(a.x * a.x + a.y * a.y + a.z * a.z); }                                                 //向量长度
point3 cross(point3 a, point3 b) { return point3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); } //叉积
double dot(point3 a, point3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; }                                             //点积
point3 norm(plane a) { return cross(pt3[a.p[1]] - pt3[a.p[0]], pt3[a.p[2]] - pt3[a.p[0]]); }                             //法向量
double area(plane a) { return fabs(len(cross(pt3[a.p[1]] - pt3[a.p[0]], pt3[a.p[2]] - pt3[a.p[0]]))) / 2.0; }            //面积
int above(point3 p, plane pl)                                                                                            //点在面上和面内1,点在面下0
{
    point3 nor = norm(pl);
    double pro = dot(p - pt3[pl.p[0]], nor);
    return pro >= 0;
}
plane pl[maxn * 10], np[maxn * 10]; //三维凸包结果,当前凸包
int gg[1][1];                       //边是否被照射
int convex3(int nn)                 //三维凸包,返回凸包面数
{                                   //记得加抖动
    int tot = 0;
    pl[tot++] = {0, 1, 2};
    pl[tot++] = {2, 1, 0};
    for (int i = 3; i < nn; i++)
    {
        int cnt = 0;
        for (int j = 0; j < tot; j++)
        {
            int x = above(pt3[i], pl[j]);
            if (x == 0) np[cnt++] = pl[j];
            for (int k = 0; k < 3; k++)
            {
                if (x == 0)
                    gg[pl[j].p[k]][pl[j].p[(k + 1) % 3]] = 0;
                else
                    gg[pl[j].p[k]][pl[j].p[(k + 1) % 3]] = 1;
            }
        }
        for (int j = 0; j < tot; j++)
        {
            for (int k = 0; k < 3; k++)
            {
                int u, v;
                u = pl[j].p[k];
                v = pl[j].p[(k + 1) % 3];
                if (gg[u][v] == 1 && gg[v][u] == 0) np[cnt++] = plane(u, v, i);
            }
        }
        tot = cnt;
        for (int j = 0; j < tot; j++) pl[j] = np[j];
    }
    return tot;
}
point3 trunc(point3 a, double r)
{
    double l = len(a);
    if (!sign(l)) return a;
    r /= l;
    return point3(a.x * r, a.y * r, a.z * r);
}
point3 rotate(point3 p, line3 vec, double ang) //点p绕vec旋转ang弧度
{
    if (sign(len(cross((vec.s - p), (vec.e - p)))) == 0) return p;
    point3 f1 = cross((vec.e - vec.s), (p - vec.s));
    point3 f2 = cross((vec.e - vec.s), (f1));
    double len1 = len(cross((vec.s - p), (vec.e - p))) / dis(vec.s, vec.e);
    f1 = trunc(f1, len1);
    f2 = trunc(f2, len1);
    point3 h = p + f2;
    point3 pp = h + f1;
    return h + ((p - h) * cos(ang)) + ((pp - h) * sin(ang));
}
/*---------------------------------------------------*/
posted @ 2021-08-05 11:20  null4785  阅读(85)  评论(0)    收藏  举报