title : 计算几何(二维)
tags : ACM,数学,计算几何
date : 2021-10-23
author : Linno

向量
点乘与叉乘
叉乘一般用于求面积或者判断两点的相对位置:(x1,y1)×(x2,y2)=x1*y2-x2*y1;
点乘一般用于判断直线是否正交:(x1,y1)·(x2,y2)=x1*x2+y1*y2;
inline double Len(Vt a){return sqrt(Dot(a,a));}//模长
inline Vt operator +(Vt a,Vt b){
return Vt(a.x+b.x,a.y+b.y);
} //向量加减
inline Vt operator -(Vt a,Vt b){
return Vt(a.x-b.x,a.y-b.y);
}
inline Vt operator *(Vt a,double b){
return Vt(a.x*b,a.y*b); //数乘
}
inline double Dot(Vt a,Vt b){
return a.x*b.x+a.y*b.y; //点积
}
inline double Cross(Vt a,Vt b){
return a.x*b.y-a.y*b.x; //叉积
}
点与向量
点旋转
( x , y ) 绕 原 点 逆 时 针 旋 转 α ( x c o s α − y s i n α , x s i n α + y c o s α ) (x,y)绕原点逆时针旋转\alpha(xcos\alpha-ysin\alpha,xsin\alpha+ycos\alpha) (x,y)绕原点逆时针旋转α(xcosα−ysinα,xsinα+ycosα)
inline Point turn_P(Point a,double theta){
double x=a.x*cos(theta)+a.y*sin(theta);
double y=-a.x*sin(theta)+a.y*cos(theta);
return Point(x,y);
}//点a或向量(两点)关于原点顺时针旋转theta(弧度)
inline Point turn_PP(Point a,Point b,double theta){
double x=(a.x-b.x)*cos(theta)+(a.y-b.y)*(theta)+b.x;
double y=-(a.x-b.x)*sin(theta)+(a.y-b.y)*cos(theta)+b.y;
return Point(x,y);
}
点与线段
inline int dcmp(double a){
return a<-eps?-1:(a>eps?1:0); //处理精度
}
inline bool in_line(Point P,Point A,Point B){
return !dcmp(Cross(P-A,B-A))&&dcmp(Dot(P-A,P-B))<=0;
} //判断点P是否在AB上,判是否处于直线上可删去后面的条件
inline double dis_PL(Point P,Point A,Point B){
if(a==b) return Len(P-A);//AB点重合
Vt x=P-A,y=P-B,Z=B-A;
if(dcmp(Dot(x,z))<0) return Len(x); //P离A近
if(dcmp(Dot(y,z))>0) return Len(y); //P离B近
return Abs(Cross(x,z)/Len(z)); //面积处于底边长
}//P到线段AB的距离
点与直线
inline int in_Line(Point P,Point A,Point B){
return !dcmp(Cross(P-A,B-A)); //PA,AB共线
} //判断P是否在AB上
inline Point FootPoint(Point P,Point A,Point B){
Vt x=P-A,y=P-B,z=B-A;
double len1=Dot(x,z)/Len(z),len2=Dot(y,z)/Len(z);//分别计算AP,BP在AB,BA上的投影
return A+z*(len1/(len1+len2));//点A假设向量AF
} //获得P到AB的垂足
inline Point Symmetry_PL(Point P,Point A,Point B){
return P+(FootPoint(P,A,B)-P)*2;
} //获得P关于直线AB的对称点
线与线
两直线AB,CD的交点
inline Point cross_p(Point a,Point b,Point c,Point d){
Vt x=b-a,y=d-c,z=a-c;
return a+x*(Corss(y,z)/Cross(x,y)); //点A加向量AF
}//两直线AB,CD的交点
判断两线相交
inline bool is_cross(Point a,Point b,Point c,Point d){
return in_Line(cross_p(a,b,c,d),c,d); //直线AB与CD的焦点在线段CD上
} //判断直线AB与CD是否相交
inline int is_cross_ll(Point a,Point b,Point c,Point d){
double c1=Cross(b-a,c-a),c2=Cross(b-a,d-a);
double d1=Cross(d-c,a-c),d2=Cross(d-c,b-c);
return dcmp(c1)*dcmp(c2)<0&&dcmp(d1)*dcmp(d2)<0; //分别在两侧
}//判断两线段AB,CD是否相交
跨立实验:我们可以利用叉积,取A为原点,B夹在AC和AD中间,那么AC×AB与AB×AD同号,这时候AB可能处于CD之外,我们可以取C为原点再次进行实验。当两组通过时AB与CD是相交的。
double cross(P a,P b,P c){ //ab×ac
return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
bool isintersected(P a,P b,P c,P d){//判断ab和cd是否相交
double u,v,w,z;
u=cross(a,b,c);
v=cross(a,b,d);
w=cross(c,d,b);
z=corss(c,d,a);
return (u*v<=1e-7&&w*z<=1e-7) //1相交0不相交
}
点与多边形
判断点A是否在任意多边形Poly内(射线法)
inline int PIP(Point *P,int n,Point a){
int cnt=0;double tmp;
for(int i=1;i<=n;i++){
int j=i<n?i+1:1;
if(in_line(a,P[i],P[j])) return 2;//点在多边形上
if(a.y>=min(P[i].y,P[j].y)&&a.y<max(P[i].y,P[j].y)) //纵坐标在该线段两端点之间
tmp=P[i].x+(a.y-P[i].y)/(P[j].y-P[i].y)*(P[j].x-P[i].x),cnt+=dcmp(tmp-a.x)>0; //交点在A右方
}
return cnt&1; //穿过奇数次则在多边形中
}
判断点A是否在凸多边形Poly以内(二分法)
inline int judge(Point a,Point L,Point R){ //判断AL是否在AR右边
return dcmp(Cross(L-a,R-a))>0;//必须严格以内
}
inline int PIP_(Point *P,int n,Point a){ //二分法判断A是否在凸多边形Poly内
//点按逆时针给出
if(judge(P[1],a,P[2])||judge(P[1],P[n],a)) return 0; //在P[1_2]或P[1_n]外
if(in_line(a,P[1],P[2])||in_line(a,P[1],P[n])) return 2; //在P[1_2]或P[1_n]上
int l=2,r=n-1;
while(l<r){ //二分找到一个位置pos使得P[1]_A在P[1_pos],P[1_(pos+1

这篇博客详细介绍了二维计算几何中的核心概念,包括向量的点乘与叉乘、点的旋转、点线段及直线的关系、多边形内外判断、图形面积计算、凸包算法如Graham扫描法和旋转卡壳,以及圆的性质与交点计算。此外,还提供了多种求解问题的方法和参考资料。
最低0.47元/天 解锁文章
2918

被折叠的 条评论
为什么被折叠?



