计算几何
1.点,线段,极角序
实数(double)
小数部分11位,实数部位53位,相对精度2^(-53)
long double 2^(-64)
//基础模板
typedef double db;
const db EPS =1e-9;
//符号函数
inline int sign(db a){return a<-EPS?-1:a>EPS;}//等于0返回0,小于0返回-1,,大于0返回1
//比较函数
inline int cmp(db a,db b){return sign(a-b);}//如果a>b,返回1,a==b返回0,a<b返回-1
struct P{
db x,y;
P(){}
P(db _x,db _y):x(_x),y(_y){}
P operator+(P p){return {x+p.x,y+p.y};}
P operator-(P p){return {x-p.x,y-p.y};}
P operator*(db d){return {x*d,y*d};}
P operator/(db d){return {x/d,y/d};}
//字典序意义上的排序,x从小到大,y从小到大
bool operator<(P p) const{
int c=cmp(x,p.x);
if(c) return c==-1;//如果要用大到小,return c==1即可
return cmp(y,p.y)==-1;//如果要用大到小,return c==1即可
}
//判断等于
bool operator==(P o) const{return cmp(x,o.x)==0&&cmp(y,o.y)==0;}
db distTo(P p){return (*this-p).abs();}//求两点之间的距离
db dot(P p){return x*p.x+y*p.y;}//点积
db det(P p){return x*p.y-y*p.x;}//差积
db abs2(){return x*x+y*y;}
db abs(){return sqrt(abs2());}//返回模长
db alpha(){return atan2(y,x);}//返回极角,long double 版本是atan2l(y,x)
P rot90(){return P(-y,x);}//转90度(逆时针)
P unit(){return *this/abs();}//方向向量
int quad()const{return sign(y)==1||(sign(y)==0&&sign(x)>=0);}
P rot(db an){return {x*cos(an)-y*sin(an),x*sin(an)+y*cos(an)};} //顺时针旋转an角度
};
#define cross(p1,p2,p3) ((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y)) //求p1p2叉乘p1p3
#define crossop(p1,p2,p3) sign(cross(p1,p2,p3)) //求p1p2叉乘p1p3的符号
//直线p1p2,q1q2是否恰有一个交点
bool chkLL(P p1,P p2,P q1,P q2){//判断两条直线是不是相交关系
db a1=cross(q1,q2,p1),a2=-cross(q1,q2,p2);//判断这两的方向向量是不是相同的
return sign(a1+a2)!=0;
}
//求直线p1p2,q1q2的交点
P isLL(P p1,P p2,P q1,P q2){
db a1=cross(q1,q2,p1),a2=-cross(q1,q2,p2);
return (p1*a2+p2*a1)/(a1+a2);
}
//判断区间[l1,r1],[l2,r2]是否相交,相交返回1,不相交返回0
bool intersect(db l1,db r1,db l2,db r2){
if(l1>r1) swap(l1,r1);if(l2>r2) swap(l2,r2);
return !(cmp(r1,l2)==-1||cmp(r2,l1)==-1);
}
//线段p1p2,q1q2相交
bool isSS(P p1,P p2,P q1,P q2){
return intersect(p1.x,p2.x,q1.x,q2.x)&&intersect(p1.y,p2.y,q1.y,q2.y)&&
crossop(p1,p2,q1)*crossop(p1,p2,q2)<=0&&crossop(q1,q2,p1)*crossop(q1,q2,p2)<=0;
}
//线段p1p2,q1q2严格相交,不能相交在端点,并且相交部分是一个点,而不是一条线段
bool isSS_strict(P p1,P p2,P q1,P q2){
return crossop(p1,p2,q1)*crossop(p1,p2,q2)<0&&crossop(q1,q2,p1)*crossop(q1,q2,p2)<0;
}
//m是否在[a,b]之间
bool isMiddle(db a,db m,db b){
return sign(a-m)==0||sign(b-m)==0||(a<m!=b<m);
}
//点m的横坐标是否在a.x和b.x之间,纵坐标是否在a.y和b.y之间
bool isMiddle(P a,P m,P b){
return isMiddle(a.x,m.x,b.x)&&isMiddle(a.y,m.y,b.y);
}
//点p在线段p1p2上
bool onSeg(P p1,P p2,P q){
return crossop(p1,p2,q)==0&&isMiddle(p1,q,p2);
}
//点p严格在线段p1p2上,即不在端点上
bool onSeg_strict(P p1,P p2,P q){
return crossop(p1,p2,q)==0&&sign((q-p1).dot(p1-p2))*sign((q-p2).dot(p1-p2))<0;
}
//求q到直线p1p2的投影(垂足),注:p1!=p2
P proj(P p1,P p2,P q){
P dir=p2-p1;
return p1+dir*(dir.dot(q-p1)/dir.abs2());
}
//求q以直线p1p2为轴的反射
P reflect(P p1,P p2,P q){
return proj(p1,p2,q)*2-q;
}
//求q到线段p1p2的最小距离
db nearest(P p1,P p2,P q){
if(p1==p2) return p1.distTo(q);
P h=proj(p1,p2,q);
if(isMiddle(p1,h,p2)) return q.distTo(h);
return min(p1.distTo(q),p2.distTo(q));
}
//求线段p1p2与线段q1q2的最小距离
db disSS(P p1,P p2,P q1,P q2){
if(isSS(p1,p2,q1,q2)) return 0;
return min(min(nearest(p1,p2,q1),nearest(p1,p2,q2)),min(nearest(q1,q2,p1),nearest(q1,q2,p2)));
}
//极角排序
sort(p,p+n,[&](P a,const P b){
int qa=a.quad(),qb=b.quad();
if(qa!=qb) return qa<qb;
else return sign(a.det(b))<0;
});