计算几何模板

#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#define point Vector
#define ll long long
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
const double eps = 1e-8;  
struct Vector {
    double x, y;
    Vector(double X = 0.0, double Y = 0.0){
        x = X, y = Y;
    }
};
struct Line {
    point s, e;    
    Line() {}; 
    Line(point i, point j) {
        s = i, e = j; 
    }  
};   
int dcmp(double x) {
    if(fabs(x) < eps)
        return 0;  
    return x < 0 ? -1 : 1;
}
bool operator < (const point &a, const point & b) {
    if(dcmp(a.x - b.x) == 0)
        return a.y < b.y;
    else return a.x < b.x;
}
bool operator == (const point &a, const point & b) {
    if(dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0)
        return true;
    return false;
}
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); }
double dot(Vector a, Vector b) {
    return a.x * b.x + a.y * b.y;
}
double len(point a) {
    return sqrt(dot(a, a));
}
double sqr(double x) {
    return x * x;
}
double dis(point a, point b) {
    return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));    
}
// b 在 a 的逆时针为正,夹角为 a 转到 b 的有向角度(sin)  
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));
}
// 求法向量.   
Vector normal(Vector a) {
    double u = len(a);  
    return Vector(-a.y / u, a.x / u);
}       
// 看 tmp 是否在 ab 上
int Onsegment(point tmp, point a, point b) { 
    if(dcmp(cross(a - tmp, b - tmp)) == 0 && dcmp(dot(a - tmp, b - tmp)) <= 0)
        return 1;
    return 0;
}
// 前面是线段上,后面是不在线段上相交. 
int Line_Intersect(point a, point b, point c, point d) {  
    double x1 = cross(b - a, c - a), y1 = cross(b - a, d - a); 
    double x2 = cross(d - c, a - c), y2 = cross(d - c, b - c);  
    if(!dcmp(x1) || !dcmp(x2) || !dcmp(y1) || !dcmp(y2)) {
        bool f1 = Onsegment(a, c, d);
        bool f2 = Onsegment(b, c, d);
        bool f3 = Onsegment(c, a, b);
        bool f4 = Onsegment(d, a, b);
        bool f = (f1 | f2 | f3 | f4);
        return f;  
    }
    if(dcmp(x1) * dcmp(y1) < 0 && dcmp(x2) * dcmp(y2) < 0)
        return 1;
    return 0;
}
// l1 为直线,l2 为线段, 看是否相交   
int seg_inter_line(Line l1, Line l2) {    
    if(dcmp(cross(l1.e - l2.s, l1.s - l2.s)) * dcmp(cross(l1.e - l2.e, l1.s - l2.e)) <= 0) 
        return 1; 
    return 0; 
}   
// 看直线 l1 和 l2 的位置情况. 
int judge_Line(Line l1, Line l2) {
    if(dcmp(cross(l1.e - l1.s, l2.e - l2.s)) == 0) {
        // 0 : 共线,-1:平行. 
        if(seg_inter_line(l1, l2) == 1) 
            return 0;  
        else 
            return -1;  
    }
    return 1;   
}
// 求直线 l1 与 l2 的交点
point Get_Line(Line l1, Line l2) {
    Vector v1 = l1.e - l1.s, v2 = l2.e - l2.s;       
    double t = cross(l2.s - l1.s, v2) / cross(v1, v2);     
    return l1.s + v1 * t;   
}    
// 判断点 p 是否在多边形内. 
// -1: 在边界.  
// 0 : 在外部
// 1 : 在内部
int ispoly(point p, point poly[], int len) {
    int cnt = 0;    
    Line ray, side;   
    ray.s = p;   
    ray.e = point(-1000000000.0, p.y);      
    for(int i = 0; i < len; ++ i) {
        side = Line(poly[i], poly[(i + 1) % len]);     
        // 在边界
        if(Onsegment(p, side.e, side.s))  
            return -1; 
        // 平行线不用考虑
        if(dcmp(side.s.y - side.e.y) == 0) 
            continue; 
        if(Onsegment(side.s, ray.s, ray.e)) {
            // 凸包点在射线上.  
            if(dcmp(side.s.y - side.e.y) > 0) ++ cnt;    
        }  
        else if(Onsegment(side.e, ray.s, ray.e))  {
            if(dcmp(side.e.y - side.s.y) > 0) ++ cnt;   
        }
        else if(Line_Intersect(side.e, side.s, ray.s, ray.e) == 1) ++ cnt;  
    }
    if(cnt & 1) return 1;  
    return 0; 
}   

  

posted @ 2022-01-19 00:47  guangheli  阅读(55)  评论(0)    收藏  举报