首页 > 其他 > 详细

计算几何模板整理

时间:2019-09-06 23:59:03      阅读:147      评论:0      收藏:0      [点我收藏+]
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const db eps = 1e-10;  // 误差
const db pi = acos(-1.0);  // 圆周率
const ll inf = 0x3f3f3f3f3f3f3f3f;  // 无穷大
const ll maxn = 1e5 + 10;

// 精度三态函数
inline int dcmp(db x) {
    if(fabs(x) < eps) return 0;
    return x > 0? 1: -1;
}

class Point {
public:
    double x, y;
    Point(double x = 0, double y = 0) : x(x), y(y) {}  // 构造器
    // 输入
    void input() {
        scanf("%lf%lf", &x, &y);
    }
    // 一般用于排序
    bool operator<(const Point &a) const {
        return (!dcmp(x - a.x))? dcmp(y - a.y) < 0: x < a.x;
    }
    // 判断点的坐标是否相同
    bool operator==(const Point &a) const {
        return dcmp(x - a.x) == 0 && dcmp(y - a.y) == 0;
    }
    // 点到点的距离的平方
    db dis2(const Point a) {
        return pow(x - a.x, 2) + pow(y - a.y, 2);
    }
    // 点到点的距离
    db dis(const Point a) {
        return sqrt(dis2(a));
    }

    // 向量的模的平方
    db dis2() {
        return x * x + y * y;
    }
    // 向量的模
    db dis() {
        return sqrt(dis2());
    }
    // 向量加法
    Point operator+(const Point a) {
        return Point(x + a.x, y + a.y);
    }
    // 向量减法
    Point operator-(const Point a) {
        return Point(x - a.x, y - a.y);
    }
    // 向量数乘
    Point operator*(double p) {
        return Point(x * p, y * p);
    }
    // 向量数除
    Point operator/(double p) {
        return Point(x / p, y / p);
    }
    // 向量点积
    db dot(const Point a) {
        return x * a.x + y * a.y;
    }
    // 向量叉积
    db cross(const Point a) {
        return x * a.y - y * a.x;
    }
    // 向量与 a 向量的夹角
    db ang(Point a) {
        return acos((a.dis() * dis()) / dot(a));
    }
    // 向量在 b 向量上的投影
    db projection(Point b) {
        if(dcmp(dis()) == 0) return 0;
        if(dcmp(b.dis()) == 0) return dis();
        return cos(ang(b)) * dis();
    }
    // 向量逆时针旋转 rad 弧度
    Point Rotate(double rad) {
        return Point(x * cos(rad) - y * sin(rad), x * sin(rad) + y * cos(rad));
    }

};
typedef Point Vector;

class Line {
public:
    Point s, e;
    Line(Point s, Point e) : s(s), e(e) {}
    // 点 p 在有向线段 se 的左边返回 1, 右边返回 -1
    int toLeftTest(Point p) {
        if((e - s).cross(p - s) > 0) return 1;
        else if((e - s).cross(p - s) < 0) return -1;
        return 0;
    }
    // 直线与直线位置关系 0-重合 1-平行 2-相交
    int linecrossline (Line l) {
        if(dcmp((e - s).cross(l.e - l.s)) == 0) {
            if(dcmp((l.s - e).cross(l.e - s)) == 0) {
                return 0;
            }
            return 1;
        }
        return 2;
    }
    // 直线与直线交点
    Point crosspoint(Line l) {
        double a1 = (l.e - l.s).cross(s - l.s);
        double a2 = (l.e - l.s).cross(e - l.s);
        double x = (s.x * a2 - e.x * a1) / (a2 - a1);
        double y = (s.y * a2 - e.y * a1) / (a2 - a1);
        if(dcmp(x) == 0) x = 0;
        if(dcmp(y) == 0) y = 0;
        return Point(x, y);
    }
};

// 凸包
typedef vector<Point> Polygon;
Polygon Andrew(vector<Point> p) {
    int n = p.size(), cnt = 0;
    Polygon ans(2 * n);
    sort(p.begin(), p.end());
    for (int i = 0; i < n; ++i) {
        while (cnt >= 2 && (ans[cnt - 1] - ans[cnt - 2]).cross(p[i] - ans[cnt - 2]) < eps) {
            --cnt;
        }
        ans[cnt++] = p[i];
    }
    int t = cnt + 1;
    for (int i = n - 1; i > 0; --i) {
        while (cnt >= t && (ans[cnt - 1] - ans[cnt - 2]).cross(p[i - 1] - ans[cnt - 2]) < eps) {
            --cnt;
        }
        ans[cnt++] = p[i - 1];
    }
    ans.resize(cnt - 1);
    return ans;
}

// 判断点在线段上
bool OnSegment(Point p, Point a1, Point a2) {
    return dcmp((a1 - p).cross(a2 - p)) == 0 && dcmp((a1 - p).dot(a2 - p)) < 0;
}

// 判断线段相交
bool Intersection(Point a1, Point a2, Point b1, Point b2) {
    double c1 = (a2 - a1).cross(b1 - a1), c2 = (a2 - a1).cross(b2 - a1),
            c3 = (b2 - b1).cross(a1 - b1), c4 = (b2 - b1).cross(a2 - b1);
    return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0;
}

// 判断点在凸包内
int isPointInPolygon(Point p, vector<Point> s) {
    int wn = 0, cc = s.size();
    for (int i = 0; i < cc; i++) {
        Point p1 = s[i];
        Point p2 = s[(i + 1) % cc];
        if (p1 == p || p2 == p || OnSegment(p, p1, p2)) return -1;
        int k = dcmp((p2 - p1).cross(p - p1));
        int d1 = dcmp(p1.y - p.y);
        int d2 = dcmp(p2.y - p.y);
        if (k > 0 && d1 <= 0 && d2 > 0) wn++;
        if (k < 0 && d2 <= 0 && d1 > 0) wn--;
    }
    if (wn != 0) return 1;
    return 0;
}

// 凸包面积
double PolygonArea(Polygon p) {
    double ans = 0;
    for(int i = 2; i < p.size() - 1; ++i) {
        ans += abs((p[i] - p[1]).cross(p[i + 1] - p[1]));
    }
    return ans * 0.5;
}

(更新中)

计算几何模板整理

原文:https://www.cnblogs.com/wulitaotao/p/11478653.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!