计算几何全家桶

二维计算几何

#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N = 1e5 + 5;
const double pi = acos(-1), eps = 1e-8;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
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;
}
struct Point {
    double x, y;
    Point(double x = 0, double y = 0) : x(x), y(y) {}
    bool operator < (const Point &p) {
        if (x == p.x) return y < p.y;
        return x < p.x;
    }
    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 x == a.x && y == a.y;
    }
    double lenth() { //模
        return sqrt(x * x + y * y);
    }
};
struct Line {
    Point st, ed;
    Line() {}
    Line(Point a, Point b){
        this->st = a;
        this->ed = b;
    }
};
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p, double r){
        this->p = p;
        this->r = r;
    }
};
double get_dist(Point a, Point b) { //两点距离
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}
double get_angle_line(const Line &a) { //线的角度
    return atan2(a.ed.y - a.st.y, a.ed.x - a.st.x);
}
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 - b.x * a.y;
}
double get_angle(Point a, Point b) { //两向量夹角
    return acos(dot(a, b) / a.lenth() / b.lenth());
}
double area(Point a, Point b, Point c) {
    return cross(b - a, c - a);
}
Point norm(Point a) { //单位向量
    return a / a.lenth();
}
Point rotate(Point a, double angle) { //点的旋转
    return Point(a.x * cos(angle) + a.y * sin(angle), -a.x * sin(angle) + a.y * cos(angle));
}
Point get_line_intersection(Point p, Point v, Point q, Point w) { //两直线交点
    Point u = p - q, res;
    double t = cross(w, u) / cross(v, w);
    return {p.x + v.x * t, p.y + v.y * t};
}
Point get_line_intersection(Line a, Line b) { //两直线交点
    return get_line_intersection(a.st, a.ed - a.st, b.st, b.ed - b.st);
}
bool on_right(Line &a, Line &b, Line &c) { //bc的交点是否在a的右侧
    auto o = get_line_intersection(b, c);
    return sign(area(a.st, a.ed, o)) <= 0;
}
double distance_to_line(Point p, Point a, Point b) { //点到线的距离
    Point v1 = b - a, v2 = p - a;
    return fabs(cross(v1, v2) / v1.lenth());
}
double distance_to_segment(Point p, Point a, Point b) { //点到线段的距离
    if (a == b) return (p - a).lenth();
    Point v1 = b - a, v2 = p - a, v3 = p - b;
    if (sign(dot(v1, v2)) < 0) return v2.lenth();
    if (sign(dot(v1, v3)) > 0) return v3.lenth();
    return distance_to_line(p, a, b);
}
Point get_line_projection(Point p, Point a, Point b) { //点在线上的投影
    Point v = b - a;
    return a + v * (dot(v, p - a) / dot(v, v));
}
double project(Point a, Point b, Point c) { //ac在ab上的投影
    return dot(b - a, c - a) / (b - a).lenth();
}
bool on_segment(Point p, Point a, Point b) { //点是否在线段上
    return sign(cross(p - a, p - b)) == 0 && sign(dot(p - a, p - b)) <= 0;
}
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;
}
bool cmp_line(const Line &a, const Line &b) { //线段按角度排序
    double A = get_angle_line(a), B = get_angle_line(b);
    if (!cmp(A, B)) return area(a.st, a.ed, b.ed) < 0;
    return A < B;
}
Point a[N], ans[N], r;
Line line[N];
Circle cir[N];
PII A[N];
PDD D[N];
double res, R;
int stk[N], top, n, q[N], cnt, m;
bool used[N];
double polygon_area() { //多边形面积
    double res = 0;
    for (int i = 0; i < n; i ++) res += cross(a[i], a[(i + 1) % n]);
    return fabs(0.5 * res);
}
void andrew() { //求凸包
    sort(a, a + n);
    for (int i = 0; i < n; i ++) {
        while (top >= 2 && area(a[stk[top - 1]], a[stk[top]], a[i]) <= 0) {
            if (area(a[stk[top - 1]], a[stk[top]], a[i]) < 0) {
                used[stk[top --]] = 0;
            } else {
                top --;
            }
        }
        stk[++ top] = i;
        used[i] = 1;
    }
    used[0] = 0;
    for (int i = n - 1; ~i; i --){
        if (used[i]) continue;
        while (top >= 2 && area(a[stk[top - 1]], a[stk[top]], a[i]) <= 0) top -- ;
        stk[++ top] = i;
    }
}
double rotating_calipers() { //旋转卡壳
    if (top <= 3) return get_dist(a[0], a[n - 1]);
    double res = 0;
    for (int i = 1, j = 3; i <= top; i ++) {
        auto d = a[stk[i]], e = a[stk[i + 1]];
        while (area(d, e, a[stk[j]]) < area(d, e, a[stk[j + 1]])) {
            j = (j + 1) % top;
            if (!j) j = 1;
        }
        res = max(res, max(get_dist(d, a[stk[j]]), get_dist(e, a[stk[j]])));
    }
    return res;
}
double half_plane_intersection() { //半平面交
    sort(line, line + cnt, cmp_line);
    int hh = 0, tt = -1;
    for (int i = 0; i < cnt; i ++) {
        if (i && !cmp(get_angle_line(line[i]), get_angle_line(line[i - 1]))) continue;
        while (hh + 1 <= tt && on_right(line[i], line[q[tt - 1]], line[q[tt]])) tt -- ;
        while (hh + 1 <= tt && on_right(line[i], line[q[hh]], line[q[hh + 1]])) hh ++ ;
        q[++ tt] = i;
    }
    while (hh + 1 <= tt && on_right(line[q[hh]], line[q[tt - 1]], line[q[tt]])) tt -- ;
    while (hh + 1 <= tt && on_right(line[q[tt]], line[q[hh]], line[q[hh + 1]])) hh ++ ;
    q[++ tt] = q[hh];
    int k = 0;
    for (int i = hh; i < tt; i ++) ans[k ++] = get_line_intersection(line[q[i]], line[q[i + 1]]);
    double res = 0;
    for (int i = 1; i + 1 < k; i ++) res += area(ans[0], ans[i], ans[i + 1]);
    return res / 2;
}
Line get_line(Point a, Point b) {
    return Line((a + b) / 2, rotate(b - a, pi / 2));
}
double get_circle_line_intersection(Point a, Point b, Point &pa, Point &pb) { //圆与直线交点
    auto e = get_line_intersection(a, b - a, r, rotate(b - a, pi / 2));
    auto mind = get_dist(r, e);
    if (!on_segment(e, a, b)) mind = min(get_dist(r, a), get_dist(r, b));
    if (cmp(R, mind) <= 0) return mind;
    auto len = sqrt(R * R - get_dist(r, e) * get_dist(r, e));
    pa = e + norm(a - b) * len;
    pb = e + norm(b - a) * len;
    return mind;
}
double get_sector(Point a, Point b) { //扇形面积
    auto angle = acos(dot(a, b) / a.lenth() / b.lenth());
    if (sign(cross(a, b)) < 0) angle = -angle;
    return R * R * angle / 2;
}
double get_circle_triangle_area(Point a, Point b) { //三角剖分 圆与三角面积交
    auto da = get_dist(r, a), db = get_dist(r, b);
    if (cmp(R, da) >= 0 && cmp(R, db) >= 0) return cross(a, b) / 2;
    if (!sign(cross(a, b))) return 0;
    Point pa, pb;
    auto mind = get_circle_line_intersection(a, b, pa, pb);
    if (cmp(R, mind) <= 0) return get_sector(a, b);
    if (cmp(R, da) >= 0) return cross(a, pb) / 2 + get_sector(pb, b);
    if (cmp(R, db) >= 0) return get_sector(a, pa) + cross(pa, b) / 2;
    return get_sector(a, pa) + cross(pa, pb) / 2 + get_sector(pb, b);
}
Circle get_circle(Point a, Point b, Point c) { //三点求圆
    auto u = get_line(a, b), v = get_line(a, c);
    auto p = get_line_intersection(u.st, u.ed, v.st, v.ed);
    return Circle(p, get_dist(p, a));
}
Circle min_circle_cover() { //最小圆覆盖
    random_shuffle(a, a + n);
    Circle c = Circle(a[0], 0);
    for (int i = 1; i < n; i ++) {
        if (cmp(c.r, get_dist(c.p, a[i])) < 0) {
            c = {a[i], 0};
            for (int j = 0; j < i; j ++) {
                if (cmp(c.r, get_dist(c.p, a[j])) < 0) {
                    c = {(a[i] + a[j]) / 2, get_dist(a[i], a[j]) / 2};
                    for (int k = 0; k < j; k ++) {
                        if (cmp(c.r, get_dist(c.p, a[k])) < 0) {
                            c = get_circle(a[i], a[j], a[k]);
                        }
                    }
                }
            }
        }
    }
    return c;
}
double f(double x) { //辛普森积分函数(圆的面积并)
    int cnt = 0;
    for (int i = 0; i < n; i ++) {
        auto X = fabs(x - cir[i].p.x), R = cir[i].r;
        if (cmp(X, R) < 0) {
            auto Y = sqrt(R * R - X * X);
            a[cnt ++] = {cir[i].p.y - Y, cir[i].p.y + Y};
        }
    }
    if (!cnt) return 0;
    sort(a, a + cnt);
    double res = 0, st = a[0].x, ed = a[0].y;
    for (int i = 1; i < cnt; i ++) {
        if (a[i].x <= ed) {
            ed = max(ed, a[i].y);
        } else {
            res += ed - st;
            st = a[i].x, ed = a[i].y;
        }
    }
    return res + ed - st;
}
double simpson(double l, double r) { //辛普森积分
    auto mid = (l + r) / 2;
    return (r - l) * (f(l) + 4 * f(mid) + f(r)) / 6;
}
double asr(double l, double r, double s) { //自适应
    auto mid = (l + r) / 2;
    auto left = simpson(l, mid), right = simpson(mid, r);
    if (fabs(s - left - right) < eps) return left + right;
    return asr(l, mid, left) + asr(mid, r, right);
}
signed main() {
    
}

三维计算几何

#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 5;
const double eps = 1e-12;
int n, m;
bool g[N][N];
double res;
double rand_eps() {
    return ((double)rand() / RAND_MAX - 0.5) * eps;
}
struct Point {
    double x, y, z;
    void shake() {
        x += rand_eps(), y += rand_eps(), z += rand_eps();
    }
    Point operator- (Point t) {
        return {x - t.x, y - t.y, z - t.z};
    }
    double operator& (Point t) {
        return x * t.x + y * t.y + z * t.z;
    }
    Point operator* (Point t) {
        return {y * t.z - t.y * z, z * t.x - x * t.z, x * t.y - y * t.x};
    }
    double len() {
        return sqrt(x * x + y * y + z * z);
    }
};
Point q[N];
struct Plane {
    int v[3];
    Point norm() { // 法向量
        return (q[v[1]] - q[v[0]]) * (q[v[2]] - q[v[0]]);
    }
    double area() { // 求面积
        return norm().len() / 2;
    }
    bool above(Point a) {
        return ((a - q[v[0]]) & norm()) >= 0;
    }
};
Plane plane[N], np[N];
void get_convex_3d() { //三维凸包
    plane[m ++] = {0, 1, 2};
    plane[m ++] = {2, 1, 0};
    for (int i = 3; i < n; i ++) {
        int cnt = 0;
        for (int j = 0; j < m; j ++) {
            bool t = plane[j].above(q[i]);
            if (!t) np[cnt ++] = plane[j];
            for (int k = 0; k < 3; k ++) g[plane[j].v[k]][plane[j].v[(k + 1) % 3]] = t;
        }
        for (int j = 0; j < m; j ++) {
            for (int k = 0; k < 3; k ++) {
                int a = plane[j].v[k], b = plane[j].v[(k + 1) % 3];
                if (g[a][b] && !g[b][a]) np[cnt ++] = {a, b, i};
            }
        }
        m = cnt;
        for (int j = 0; j < m; j ++) plane[j] = np[j];
    }
}
signed main() {
    cin >> n;
    for (int i = 0; i < n; i ++) {
        cin >> q[i].x >> q[i].y >> q[i].z;
        q[i].shake();
    }
    get_convex_3d();
    for (int i = 0; i < m; i ++) res += plane[i].area();
    printf("%lf", res);
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值