计算几何板子(持续更新)

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef double db;
const db Pi = acos(-1);
const db inf = 1e15; 
const db eps = 1e-11;

// 判断正、负还是0
inline int dcmp(db x){
    if(fabs(x) < eps)  return 0;
    return x > 0 ? 1 : -1; 
}

db Acos(db x){
	if(x <= -1)	 return Pi;
	if(x >= 1)	 return 0;
	return acos(x);
}

db Asin(db x){
	if(x >= 1)  return Pi / 2;
	if(x <= -1)  return -Pi / 2;
	return asin(x); 	
}

db Tan(db x){
    if(dcmp(x - Pi / 2) == 0)  return 4e18;
    return tan(x);
}

typedef struct Point{
    db x, y;
    Point(db a = 0, db b = 0) { x = a, y = b; }
    Point operator -(const Point &ret)const { return Point{x - ret.x, y - ret.y}; }
    Point operator +(const Point &ret)const { return Point{x + ret.x, y + ret.y}; }
    Point operator *(db mul)const { return Point{x * mul, y * mul}; }
    Point operator /(db div)const { return Point{x / div, y / div}; }
    //db operator *(const Point &ret) { return x * ret.x + y * ret.y; }  // 点积
    //db operator ^(const Point &ret) { return x * ret.y - y * ret.x; }  // 叉积
    db length() { return sqrt(x * x + y * y); }
}Vector;

struct Line{
    Point p[2];
    db k, b;
    Line(db a = 0, db b = 0, db c = 0, db d = 0) { p[0].x = a, p[0].y = b, p[1].x = c, p[1].y = d; }
    Line(Point a, Point b) { p[0] = a, p[1] = b; }

    db length(){
        return sqrt((p[0].x - p[1].x) * (p[0].x - p[1].x) + (p[0].y - p[1].y) * (p[0].y - p[1].y));
    }

    // 获取直线k,b参数
    void get_para(){
        if(dcmp(p[0].x - p[1].x) == 0){
            k = inf;
            b = inf;
        }
        else{
            k = (p[1].y - p[0].y) / (p[1].x - p[0].x);
            b = p[0].y - k * p[0].x;
        }
    }

    // 点到直线距离
    db dis_Point(Point ret){
        db x = ret.x,  y = ret.y;
        if(k == inf)  return fabs(x - p[0].x);
        return fabs(k * x - y + b) / sqrt(1 + k * k);
    }
};

// 点积
db dot(Vector a, Vector b) { return a.x * b.x + a.y * b.y; }
// 叉积
db cross(Vector a, Vector b) { return a.x * b.y - a.y * b.x; }

// 判断两直线是否相交,包含端点
bool intersection(const Line &l1, const Line &l2){
    //  快速排斥实验
    if(max(l1.p[0].x, l1.p[1].x) < min(l2.p[0].x, l2.p[1].x) || max(l2.p[0].x, l2.p[1].x) < min(l1.p[0].x, l1.p[1].x))  return false;
    if(max(l1.p[0].y, l1.p[1].y) < min(l2.p[0].y, l2.p[1].y) || max(l2.p[0].y, l2.p[1].y) < min(l1.p[0].y, l1.p[1].y))  return false;
    //  跨立实验
    Vector L1 = {l1.p[1].x - l1.p[0].x, l1.p[1].y - l1.p[0].y},  L2 = {l2.p[1].x - l2.p[0].x, l2.p[1].y - l2.p[0].y};
    Vector h = {l2.p[0].x - l1.p[0].x, l2.p[0].y - l1.p[0].y},  hh = {l2.p[1].x - l1.p[0].x, l2.p[1].y - l1.p[0].y};
    if(dcmp(cross(L1, h) * cross(L1, hh)) > 0)  return false;
    h = {l1.p[0].x - l2.p[0].x, l1.p[0].y - l2.p[0].y},  hh = {l1.p[1].x - l2.p[0].x, l1.p[1].y - l2.p[0].y};
    if(dcmp(cross(L2, h) * cross(L2, hh)) > 0)  return false;
    return true;
}

// 逆时针旋转,顺时针的话角度取反即可
Point rorate_point(const Point &p, db A){
    return Point{p.x * cos(A) - p.y * sin(A), p.x * sin(A) + p.y * cos(A)};
}

// 找直线交点
bool inter_point(const Line &l1, const Line &l2, Point &ans){	
	Point a = l1.p[0], b = l2.p[0];
    if(l1.k == l2.k)  return 0;
    if(l1.k == inf)  ans = {a.x, l2.k * a.x + l2.b};
    else if(l2.k == inf)  ans = {b.x, l1.k * b.x + l1.b};
    else{
        ans.x = (l1.b - l2.b) / (l2.k - l1.k);
        ans.y = l1.k * ans.x + l1.b;
    }
    return 1;
}

// 两点距离
db point_dis(const Point &a, const Point &b){
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

// 极角排序  p0是基准点
Point p0;
bool cmp_jijiao(Point p1, Point p2){
    Vector a = p1 - p0,  b = p2 - p0;
    return dcmp(cross(a, b)) > 0;
}

// 凸包,返回凸包周长,n是点的个数
db Graham(int n){
    // goal是构成凸包的点,n是点的个数, 基准点是1
    Point p[100], goal[100];
    int cnt = 1;
    for(int i = 2; i <= n; ++i){
        if(p[i].y < p[1].y)  swap(p[1], p[i]);
    }
    sort(p + 2, p + 1 + n, cmp_jijiao);
    goal[1] = p[1];
    for(int i = 2; i <= n; ++i){
        while(cnt > 1 && dcmp(cross(goal[cnt] - goal[cnt - 1], p[i] - goal[cnt])) < 0)  --cnt;
        goal[++cnt] = p[i];
    }
    goal[++cnt] = p[1];
    db len = 0;
    for(int i = 2; i <= cnt; ++i)
        len += point_dis(goal[i], goal[i - 1]);
    return len;
}

// 任意多边形面积,顶点按照顺时针或逆时针排序,n是顶点数
db GetPolygonArea(int n){
    Point p[100];
    if(n < 3)  return 0;
    db ans = 0;
    for(int i = 2; i < n; ++i)  ans += cross(p[i] - p[1], p[i + 1] - p[1]);
    return fabs(ans / 2);
}
posted @ 2020-12-19 00:18  のNice  阅读(155)  评论(0编辑  收藏  举报