计算几何

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;
}); 
posted @ 2024-07-11 20:41  MENDAXZ  阅读(20)  评论(0编辑  收藏  举报