欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

计算几何模板——点类以及线段类

程序员文章站 2022-04-02 18:58:03
...
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include <iostream>
#include <string>
#include <set>
#include <map>
using namespace std;
const int MAXN = 500+10;
const int INF=1e9+7;
const double eps=1e-8;
const double pi=acos(-1.0);
//计算几何误差修正
//输入为一个double类型的数,返回-1表示负数,1表示正数,0表示x为0
int cmp(double x){
    if(fabs(x)<eps)
        return 0;
    if(x>0) return 1;
    return -1;
}

//计算几何点类
inline double sqr(double x){
    return x*x;
}

struct point{
    double x,y;
    double xx;
    point(){}
    point(double a,double b):x(a),y(b){}
    void input(){
        scanf("%lf%lf",&x,&y);
    }
    //加法
    friend point operator + (const point &a,const point &b){
        return point(a.x+b.x,a.y+b.y);
    }
    //减法
    friend point operator - (const point &a,const point &b){
        return point(a.x-b.x,a.y-b.y);
    }
    //判断相等
    friend bool operator == (const point &a,const point &b){
        return cmp(a.x-b.x)==0&&cmp(a.y-b.y)==0;
    }
    //倍增
    friend point operator * (const point &a,const double &b){
        return point(a.x*b,a.y*b);
    }
    //倍增
    friend point operator * (const double &b,const point &a){
        return point(a.x*b,a.y*b);
    }
    //除法
    friend point operator / (const point &a,const double b){
        return point(a.x/b,a.y/b);
    }
    //模长
    double norm(){
        return sqrt(sqrt(x)+sqr(y));
    }
};

//叉积,a×b>0代表a在b的顺时针方向,<0代表a在b的逆时针方向,等于0代表a和b向量共线,但不确定方向是否相同
double det(const point &a,const point &b){
    return a.x*b.y-a.y*b.x;
}
//点积
double dot(const point &a,const point &b){
    return a.x*b.x+a.y*b.y;
}
//距离
double dist(const point &a,const point &b){
    return (a-b).norm();
}
//op向量绕原点逆时针旋转A(弧度)
point rotate_point(const point &p,double A){
    double tx=p.x,ty=p.y;
    return point(tx*cos(A)-ty*sin(A),tx*sin(A)+ty*cos(A));
}

//计算几何线段类
struct line{
    point a,b;
    line(){}
    line(point x,point y):a(x),b(y){}
    void input(){
        a.input();
        b.input();
    }
};

//用两个点a,b生成的一个线段或者直线
line point_make_line(point a,point b){
    return line(a,b);
}

//求点p到线段st的距离
double dis_point_segment(point p,point s,point t){
    if(cmp(dot(p-s,t-s))<0) return (p-s).norm();
    if(cmp(dot(p-s,s-t))<0) return (p-t).norm();
    return fabs(det(s-p,t-p)/dist(s,t));
}
//求点p到线段st的垂足,保存在cp中
void PointProjLine(point p,point s,point t,point &cp){
    double r=dot((t-s),(p-s))/dot(t-s,t-s);
    cp=s+(t-s)*r;
}

//判断p点是否在线段st上
bool PointOnSegment(point p,point s,point t){
    return cmp(det(p-s,t-s))==0&&cmp(dot(p-s,p-t))<=0;
}

//判断a和b是否平行
bool parallel(line a,line b){
    return !cmp(det(a.a-a.b,b.a-b.b));
}

//判断a和b是否共线
bool contribution(line a,line b){
    if(!parallel(a, b))
        return false;
    if(!cmp(det(a.b-a.a,b.a-a.b)))
        return true;
    return false;
}

//判断a和b是否相交,若相交则返回true且交点保存在res中
bool line_make_point(line a,line b,point &res){
    if(parallel(a, b))
        return false;
    double s1=det(a.a-b.a,b.b-b.a);
    double s2=det(a.b-b.a,b.b-b.a);
    res=(s1*a.b-s2*a.a)/(s1-s2);
    return true;
}
//判断线段是否相交
bool segment_make_point(line a,line b,point &res){
    if(!line_make_point(a,b,res))
        return false;
    if(PointOnSegment(res, a.a, a.b)&&PointOnSegment(res, b.a, b.b))
        return true;
    return false;
}
//判断线段和直线是否相交,a是直线,b是线段
bool line_across_segment(line a,line b){
    if(cmp(det(a.b-a.a,b.a-a.a)*det(a.b-a.a,b.b-a.a))==1){
        return false;
    }
    return true;
}

//将直线a沿法向量方向平移距离len得到的直线
line move_d(line a,const double &len){
    point d=a.b-a.a;
    d=d/d.norm();
    d=rotate_point(d, pi/2);
    return line(a.a+d*len,a.b+d*len);
}

相关标签: 算法 几何