计算几何模板(第一版)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1e100
#define eps 1e-8
//用于浮点数正负判断,根据题目精度修改
const double pi = acos(-1.0);//圆周率
int sgn(double x){
    if(fabs(x)<eps)return 0;
    if(x<0)return -1;
    return 1;
}//判断浮点数正负
double sqr(double x){return x*x;}//距离等运算涉及大量平方,简便
//使用Point时注意部分函数是返回新Point而非修改本身值
struct Point{
    double x,y;
    /*构造函数*/
    Point(){}
    Point(double xx,double yy){
        x=xx;y=yy; 
    }
    /*重载一些点的基础运算符*/
    bool operator == (Point b)const{
        return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;
    }
    bool operator < (Point b)const{
        return sgn(x-b.x)== 0?sgn(y-b.y)<0:x<b.x;
    }
    Point operator -(const Point &b)const{
        return Point(x-b.x,y-b.y);
    }
    Point operator +(const Point &b)const{
        return Point(x+b.x,y+b.y);
    }
    Point operator *(const double &k)const{
        return Point(x*k,y*k);
    }
    Point operator /(const double &k)const{
        return Point(x/k,y/k);
    }
    //叉积
    double operator ^(const Point &b)const{
        return x*b.y - y*b.x;
    }
    //点积
    double operator *(const Point &b)const{
        return x*b.x + y*b.y;
    }
    /*当前点为p,求角apb大小*/
    double rad(Point a,Point b){
        Point p = *this;
        return fabs(atan2( fabs((a-p)^(b-p)),(a-p)*(b-p) ));
    }
    /*逆时针旋转90度*/
    Point rotleft(){
        return Point(-y,x);
    }
    /*顺时针旋转90度*/
    Point rotright(){
        return Point(y,-x);
    }
    //两点距离
    double dis(Point p){
        return sqrt(sqr(x-p.x)+sqr(y-p.y));
    }
    double abs(){
        return sqrt(abs2());
    }
    double abs2(){
        return sqr(x)+sqr(y);
    }
    //改变向量长度
    Point trunc(double r){
        double l = abs();
        if(!sgn(l))return *this;
        r /= l;
        return Point(x*r,y*r);
    }
    //单位化
    Point unit() { return *this/abs(); }
    //IO
    void input(){
        scanf("%lf%lf",&x,&y);
    }
    void output(){
        printf("%.7f %.7f\n",x,y);
    }
    //绕着p点逆时针旋转angle
    Point rotate(Point p,double angle){
        Point v = (*this) - p;
        double c = cos(angle), s = sin(angle);
        return Point(p.x + v.x*c - v.y*s,p.y + v.x*s + v.y*c);
    }
};
struct Line{
    //两点确定直线
    Point s,e;
    Line(){}
    Line(Point ss,Point ee){
        s=ss;e=ee;
    }
    void input(){
        s.input();
        e.input();
    }
    //点在线段上
    bool checkPS(Point p){
        return sgn((p-s)^(e-s)) == 0 && sgn((p-s)*(p-e)) <= 0;
    }
    //直线平行
    bool parallel(Line v){
        return sgn((e-s)^(v.e-v.s)) == 0;
    }
    //点和直线关系
    //1  在左侧
    //2  在右侧
    //3  在直线上
    int relation(Point p){
        int c = sgn((p-s)^(e-s));
        if(c < 0)return 1;
        else if(c > 0)return 2;
        else return 3;
    }
    //线段相交
    //2 规范相交
    //1 非规范相交
    //0 不相交
    int checkSS(Line v){
        int d1 = sgn((e-s)^(v.s-s));
        int d2 = sgn((e-s)^(v.e-s));
        int d3 = sgn((v.e-v.s)^(s-v.s));
        int d4 = sgn((v.e-v.s)^(e-v.s));
        if( (d1^d2)==-2 && (d3^d4)==-2 )return 2;
        return (d1==0 && sgn((v.s-s)*(v.s-e))<=0) ||
               (d2==0 && sgn((v.e-s)*(v.e-e))<=0) ||
               (d3==0 && sgn((s-v.s)*(s-v.e))<=0) ||
               (d4==0 && sgn((e-v.s)*(e-v.e))<=0);
    }
    //直线和线段相交
    //2 规范相交
    //1 非规范相交
    //0 不相交
    int checkLS(Line v){
        int d1 = sgn((e-s)^(v.s-s));
        int d2 = sgn((e-s)^(v.e-s));
        if((d1^d2)==-2) return 2;
        return (d1==0||d2==0);
    }
    //两直线关系
    //0 平行
    //1 重合
    //2 相交
    int checkLL(Line v){
        if((*this).parallel(v))
            return v.relation(s)==3;
        return 2;
    }
    //直线交点
    Point isLL(Line v){
        double a1 = (v.e-v.s)^(s-v.s);
        double a2 = (v.e-v.s)^(e-v.s);
        return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
    }
    //点到直线的距离
    double disPL(Point p){
        return fabs((p-s)^(e-s))/(s.dis(e));
    }
    //点到线段的距离
    double disPS(Point p){
        if(sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0)
            return min(p.dis(s),p.dis(e));
        return disPS(p);
    }
    //两线段距离
    double disSS(Line v){
        return min(min(disPS(v.s),disPS(v.e)),min(v.disPS(s),v.disPS(e)));
    }
    //点在直线上投影
    Point proj(Point p){
        return s + ( ((e-s)*((e-s)*(p-s)))/((e-s).abs2()) );
    }
    //向垂直有向直线的左侧移动x
    Line push(double x){
        Point tmp=e-s;
        tmp=tmp.rotleft().trunc(x);
        Point ss=s+tmp;
        Point ee=e+tmp;
        return {ss,ee};
    }
};

struct circle{
    Point p;//圆心
    double r;//半径
    circle(){}
    circle(Point pp,double rr){
        p = pp;
        r = rr;
    }
    void input(){
        p.input();
        scanf("%lf",&r);
    }
    bool operator == (circle v){
        return (p==v.p) && sgn(r-v.r)==0;
    }
    //面积
    double area(){
        return pi*r*r;
    }
    //周长
    double cir(){
        return 2*pi*r;
    }
    //点和圆的关系
    //0 圆外
    //1 圆上
    //2 圆内
    int relation(Point B){
        double dst = B.dis(p);
        if(sgn(dst-r) < 0)return 2;
        else if(sgn(dst-r)==0)return 1;
        return 0;
    }
    //两圆的关系
    //5 相离
    //4 外切
    //3 相交
    //2 内切
    //1 内含
    int checkCC(circle v){
        double d = p.dis(v.p);
        if(sgn(d-r-v.r) > 0)return 5;
        if(sgn(d-r-v.r) == 0)return 4;
        double l = fabs(r-v.r);
        if(sgn(d-r-v.r)<0 && sgn(d-l)>0)return 3;
        if(sgn(d-l)==0)return 2;
        if(sgn(d-l)<0)return 1;
    }
    //求两个圆的交点,返回0表示没有交点,返回1是一个交点,2是两个交点
    int isCC(circle v,Point &p1,Point &p2){
        int rel = checkCC(v);
        if(rel == 1 || rel == 5)return 0;
        double d = p.dis(v.p);
        double l = (d*d+r*r-v.r*v.r)/(2*d);
        double h = sqrt(r*r-l*l);
        Point tmp = p + (v.p-p).trunc(l);
        p1 = tmp + ((v.p-p).rotleft().trunc(h));
        p2 = tmp + ((v.p-p).rotright().trunc(h));
        if(rel == 2 || rel == 4)
            return 1;
        return 2;
    }
    //求直线和圆的交点,返回交点个数
    int isCL(Line v,Point &p1,Point &p2){
        if(sgn(v.disPL(p)-r)>0)return 0;
        Point A = v.proj(p);
        double d = v.disPL(p);
        d = sqrt(r*r-d*d);
        if(sgn(d) == 0){
            p1 = A;
            p2 = A;
            return 1;
        }
        p1 = A + (v.e-v.s).trunc(d);
        p2 = A - (v.e-v.s).trunc(d);
        return 2;
    }
    //点到圆切线
    int tanCP(Point q,Line &u,Line &v){
        int x = relation(q);
        if(x == 2)return 0;
        if(x == 1){
            u = Line(q,q + (q-p).rotleft());
            v = u;
            return 1;
        }
        double d = p.dis(q);
        double l = r*r/d;
        double h = sqrt(r*r-l*l);
        u = Line(q,p + ((q-p).trunc(l) + (q-p).rotleft().trunc(h)));
        v = Line(q,p + ((q-p).trunc(l) + (q-p).rotright().trunc(h)));
        return 2;
    }
    //两圆相交面积
    double areaCC(circle v){
        int rel = checkCC(v);
        if(rel >= 4)return 0.0;
        if(rel <= 2)return min(area(),v.area());
        double d = p.dis(v.p);
        double hf = (r+v.r+d)/2.0;
        double ss = 2*sqrt(hf*(hf-r)*(hf-v.r)*(hf-d));
        double a1 = acos((r*r+d*d-v.r*v.r)/(2.0*r*d));
        a1 = a1*r*r;
        double a2 = acos((v.r*v.r+d*d-r*r)/(2.0*v.r*d));
        a2 = a2*v.r*v.r;
        return a1+a2-ss;
    }
    //求圆和三角形pab的相交面积
    double areaCT(Point a,Point b){
        if(sgn((p-a)^(p-b)) == 0)return 0.0;
        Point q[5];
        int len = 0;
        q[len++] = a;
        Line l(a,b);
        Point p1,p2;
        if(isCL(l,q[1],q[2])==2){
            if(sgn((a-q[1])*(b-q[1]))<0)q[len++] = q[1];
            if(sgn((a-q[2])*(b-q[2]))<0)q[len++] = q[2];
        }
        q[len++] = b;
        if(len == 4 && sgn((q[0]-q[1])*(q[2]-q[1]))>0)swap(q[1],q[2]);
        double res = 0;
        for(int i = 0;i < len-1;i++){
            if(relation(q[i])==0||relation(q[i+1])==0){
                double arg = p.rad(q[i],q[i+1]);
                res += r*r*arg/2.0;
            }
            else{
                res += fabs((q[i]-p)^(q[i+1]-p))/2.0;
            }
        }
        return res;
    }
};
//多边形面积,需保证A逆时针
double area(vector<Point> A) {
    double ans = 0;
    for (int i = 0; i < A.size(); i++) ans += (A[i]^A[(i + 1) % A.size()]);
    return ans / 2;
}
int contain(vector<Point>A, Point q) { // 2 内部 1 边界 0 外部
    int pd = 0; A.push_back(A[0]);
    for (int i = 1; i < A.size(); i++) {
        Point u = A[i - 1], v = A[i];
        if (Line(u,v).checkPS(q)) return 1; if (sgn(u.y-v.y) > 0) swap(u, v);
        if (sgn(u.y-q.y) >= 0 || sgn(v.y-q.y) < 0) continue;
        if (sgn((u - v) ^(q - v)) < 0) pd ^= 1;
    }
    return pd << 1;
}
//凸包
vector<Point> ConvexHull(vector<Point>A, int flag = 1) { // flag=0 不严格 flag=1 严格
    int n = A.size(); vector<Point>ans(n * 2);
    sort(A.begin(), A.end()); int now = -1;
    for (int i = 0; i < A.size(); i++) {
        while (now > 0 && sgn((ans[now] - ans[now - 1])^(A[i] - ans[now - 1])) < flag) now--;
        ans[++now] = A[i];
    } int pre = now;
    for (int i = n - 2; i >= 0; i--) {
        while (now > pre && sgn((ans[now] - ans[now - 1])^(A[i] - ans[now - 1])) < flag) now--;
        ans[++now] = A[i];
    } ans.resize(now); return ans;
}
// 最近点对 , 先要按照 x 坐标排序
double closepoint(vector<Point>&A, int l, int r) {
    if (r - l <= 5) {
        double ans = 1e20;
        for (int i = l; i <= r; i++) for (int j = i + 1; j <= r; j++) ans = min(ans, A[i].dis(A[j]));
        return ans;
    }
    int mid = l + r >> 1; double ans = min(closepoint(A, l, mid), closepoint(A, mid + 1, r));
    vector<Point>B; for (int i = l; i <= r; i++) if (abs(A[i].x - A[mid].x) <= ans) B.push_back(A[i]);
    sort(B.begin(), B.end(), [&](Point k1, Point k2) {return k1.y < k2.y;});
    for (int i = 0; i < B.size(); i++) for (int j = i + 1; j < B.size() && B[j].y - B[i].y < ans; j++) ans = min(ans, B[i].dis(B[j]));
    return ans;
}
//凸包直径
double convexDiameter(vector<Point>A) {
    int now = 0, n = A.size(); double ans = 0;
    for (int i = 0; i < A.size(); i++) {
        now = max(now, i);
        while (1) {
            double k1 = A[i].dis(A[now % n]), k2 = A[i].dis(A[(now + 1) % n]);
            ans = max(ans, max(k1, k2)); if (k2 > k1) now++; else break;
        }
    }
    return ans;
}
//多边形和圆交面积
double areaPC(vector<Point> p,circle c){
    double ans = 0;
    int n=p.size();
    for(int i = 0;i < n;i++){
        int j = (i+1)%n;
        if(sgn( (p[j]-c.p)^(p[i]-c.p) ) >= 0)
            ans += c.areaCT(p[i],p[j]);
        else ans -= c.areaCT(p[i],p[j]);
    }
    return fabs(ans);
}

int main(){

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值