【计算几何全家桶】计算几何二维板子套路详解

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

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
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RWLinno

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值