计算几何基础

参考文章 https://blog.csdn.net/clover_hxy/article/details/53966405

预备知识

先来个小数读入优化

double read() {
    double x = 0, f = 1, y = 0.1; char ch = getchar();
    for (; !isdigit(ch)&&ch!='.'; ch=getchar()) if (ch=='-') f = -1;
    for (; isdigit(ch); ch=getchar()) x = x * 10 + ch - '0';
    if (ch == '.') ch = getchar();
    for (; isdigit(ch); ch=getchar()) x += (ch - '0') * y, y *= 0.1;
    return x * f;
}

常用模板

const double eps = 1e-8;
const double Pi = acos(-1.0);

struct Vector{
    double x,y;
    Vector() {}
    Vector(double a,double b) { x = a, y = b; }
};
typedef Vector Point;

Vector operator + (Vector a,Vector b) { return Vector(a.x+b.x, a.y+b.y); }
Vector operator - (Vector a,Vector b) { return Vector(a.x-b.x, a.y-b.y); }
Vector operator * (Vector a,double p) { return Vector(a.x * p, a.y * p); }
Vector operator / (Vector a,double p) { return Vector(a.x / p, a.y / p); }
bool operator == (Point a,Point b) { return (a.x == b.x) && (a.y == b.y); }

精度控制

int dcmp(double x) {
    if (fabs(x) <= eps) return 0;
    return x > 0 ? x : -x;
}

向量

向量模长

double len(Vector a) {
    return sqrt(a.x * a.x + a.y * a.y);
}

点积

double dot(Vector a, Vector b) {
    return a.x * b.x + a.y * b.y;
}

叉积

叉积判断两向量的位置,将两向量共起点,设一号向量为A,另一个为B,若B可以由A逆时针旋转某个度数(大于等于0,小于等于180),那么Cross(A,B) > 0,否则小于0

double cross(Vector a, Vector b) {
    return a.x * b.y - a.y * b.x;
}

向量之间的夹角

double Angle(Vector a, Vector b) {
    return acos(dot(a,b)/len(a)/len(b));
}

旋转,p是旋转角度(逆时针),弧度制。

Vector rotate(Vector a,double p) {
    return Vector(a.x * cos(p) - a.y * sin(p), a.x * sin(p) + a.y * cos(p));
}

法向量

Vector normal(Vector a) {
    double L = len(a);
    return Vector(-a.y/L, a.x/L);
}

点与直线

点到直线的距离

double distl(Point p,Point a,Point b) {
    Vector v = p - a, u = b - a;
    return fabs(cross(v,u)) / len(u);
}

点到线段的距离

double dists(Point p,Point a,Point b) {
    if (a==b) return len(p-a);
    Vector v1 = p - a, v2 = p - b, v3 = b - a;
    if (dcmp(dot(v1,v3)) < 0) return len(v1);
    else if (dcmp(dot(v2,a-b)) < 0) return len(v2);
    return fabs(cross(v2,v3))/len(v3);
}

判断直线是否相交

bool xiangjiao(Point a,Point b,Point c,Point d) {
    double u1 = cross(b-a,c-a), u2 = cross(b-a,d-a);
    double v1 = cross(d-c,a-c), v2 = cross(d-c,b-c);
    return dcmp(u1 * u2) < 0 && dcmp(v1 * v2) < 0;
}

求两直线的交点

Point jiaodian(Line a, Line b) {
    Point A = a.s, B = a.t, C = b.s, D = b.t;
    double t1 = cross(D - A, B - A), t2 = cross(B - A, C - A);
    double t = t1 / (t1 + t2);
    return C * t + D * (1 - t);
}

多边形

判断点是否在多边形内

int pointin(Point p,Point* a,int n) {
    int flag = 0;
    for (int i=1; i<=n; ++i) {
        Point s = a[i], t = a[i % n + 1];
        if (p == s || p == t) return -1; // 在点上 
        if ((s.y < p.y && t.y >= p.y) ||  (s.y >= p.y && t.y < p.y)) {
            int x = s.x + (p.y - s.y) * (t.x - s.x) / (t.y - s.y); // 射线与线段的交点的横坐标 
            if (x == p.x) return -1; // 在边上 
            if (x > p.x) flag ++; // 过这条边,且在p的右边 
        }
    }
    return flag & 1; 
}

求多边形的面积

double Area(Point *a,int n) {
    double ans = 0;
    for (int i=2; i<n; ++i) 
        ans += cross(a[i]-a[1],a[i+1]-a[1]);
    return ans / 2.0;
} 
原文地址:https://www.cnblogs.com/mjtcn/p/9526120.html