计算几何

准备

#include<bits/stdc++.h>
using namespace std;
const double eps=1e-6;
int n,m;
double x,y;
struct point{//vector
    double x,y;
};

基本运算

叉积

ab向量围成的平行四边形面积,如图红色部分

除以一边长后,为图形的高,即点线距

double len(point a){return sqrt(a.x*a.x+a.y*a.y);}//向量模 
point operator+(point a,point b){return (point){a.x+b.x,a.y+b.y};}
//点+向量=点  向量+向量=向量 
point operator-(point a,point b){return (point){a.x-b.x,a.y-b.y};}
//点-点=向量  向量-向量=向量 
point operator*(point a,double k){return (point){a.x*k,a.y*k};}//数乘
double dc(point a,point b){return a.x*b.x+a.y*b.y;}//点乘 
double operator*(point a,point b){return a.x*b.y-a.y*b.x;}//叉积

 

点线关系

点a关于直线b的对称点 

point ref(point a,line b){
    point vb=b.t-b.f;//用向量表示线 
    double dis=(b.f-a)*(b.t-a)/len(vb);//点线距 
    point dw={vb.y/len(vb),-vb.x/len(vb)};//单位向量旋转90 
    return a+(point){dw.x*2.0*dis,dw.y*2.0*dis}; 
}

左右关系

将点线转换成向量和向量,利用叉积正负判断向量的拐折关系

若(p2-p0)×(p1-p0)>0  p1p2由p1p0右拐得到,p0在p2p1左侧,向量p0p2在向量p0p1顺时针方向
若(p2-p0)×(p1-p0)<0  p1p2由p1p0左拐得到,p0在p2p1右侧,向量p0p2在向量p0p1逆时针方向
若(p2-p0)×(p1-p0)=0  p0p1p2共线

 线线关系

直线交点

inline point cross(line a,line b){
    point x=a.t-a.f,y=b.t-b.f,z=a.f-b.f;
    return a.f+x*(y*z/(x*y));
}

判断线段之间是否有交点(包括端点在另一线段上

inline int pan(line a,line b){
    double c1=(a.t-a.f)*(b.f-a.f),c2=(a.t-a.f)*(b.t-a.f);
    double d1=(b.t-b.f)*(a.f-b.f),d2=(b.t-b.f)*(a.t-b.f);
    return c1*c2<=eps&&d1*d2<=eps; 
} 

 极角排序

在平面取一定点O,引出射线Ox为定轴,规定正方向顺/逆时针。以点到定点连线与定轴所成角为关键词排序

atan2

    friend bool operator<(const point &a,const point &b){
        return atan2(a.y,a.x)<atan2(b.y,b.x);
    }

 atan2为tan反函数,值域-180~180

a为要求点A-定点O所得向量,即以O为坐标原点时A的坐标,y/x为tan即与x正半轴所成角

从小到大为从x负半轴逆时针到x负半轴,如图箭头方向

 凸包

半平面交

应用:求给出向量左侧所围成凸包

1、极角排序  若两向量同向,只要最左侧向量OP

2、单调队列  同时压入向量,此向量和队列中上一向量交点(凸包预备点)

 

若队尾交点在加入向量外侧,弹出队尾向量和交点

 进行到后面时,形成一个封闭图形,加入向量会对队头交点有影响,此时弹出队头

最后有一些无关向量,它们的左侧包含整个封闭图形,对答案没有限制作用。用队头向量弹出

放入队头和队尾交点后,交点队列(l,r]即为凸包点集

复制代码
struct line{
    point f,t;
    friend bool operator<(const line &a,const line &b){
        double t1=atan2(a.t.y-a.f.y,a.t.x-a.f.x);
        double t2=atan2(b.t.y-b.f.y,b.t.x-b.f.x);
        if(fabs(t1-t2)>eps)  return t1<t2;
        return (b.f-a.f)*(b.t-a.f)>eps;
    }friend bool operator!=(const line &a,const line &b){
        double t1=atan2(a.t.y-a.f.y,a.t.x-a.f.x);
        double t2=atan2(b.t.y-b.f.y,b.t.x-b.f.x);
        return fabs(t1-t2)>eps;
    }
} a[MAX],st[MAX];       
复制代码
复制代码
    sort(a+1,a+n+1);
    for(int i=1;i<=n;++i)
        if(a[i]!=a[i-1]){
            while(r-l>1&&(a[i].t-t[r])*(a[i].f-t[r])>eps)  --r;
            while(r-l>1&&(a[i].t-t[l+2])*(a[i].f-t[l+2])>eps)  ++l;
            st[++r]=a[i];
            if(r-l>1)  t[r]=cross(st[r],st[r-1]);
        }
    while(r-l>1&&(st[l+1].t-t[r])*(st[l+1].f-t[r])>eps)  --r;
    t[r+1]=cross(st[l+1],st[r]);++r;    
复制代码

 动态凸包

up上凸包,down下凸包

板子题

复制代码
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
const double inf=1e10*1.0;
#define IT set<point>::iterator
int q,opt;
double x,y;
struct point{
    double x,y;
    friend bool operator<(const point &a,const point &b){
        if(a.x==b.x)  return a.y<b.y;
        return a.x<b.x; 
    }
};
double len(point a){return sqrt(a.x*a.x+a.y*a.y);}
point operator+(point a,point b){return {a.x+b.x,a.y+b.y};}
point operator-(point a,point b){return {a.x-b.x,a.y-b.y};}
point operator*(point a,double k){return {a.x*k,a.y*k};}
double dc(point a,point b){return a.x*b.x+a.y*b.y;}
double operator*(point a,point b){return a.x*b.y-a.y*b.x;}
struct ch{
    int op;set<point>s;
    inline int PIP(point a){ 
        IT it=s.lower_bound({a.x,-inf});
        if(it==s.end())  return 0;
        if((*it).x==a.x)  return (a.y-(*it).y)*op<=0;
        if(it==s.begin())  return 0;
        IT j=it;--j;return (a-*j)*(*it-*j)*op>=0;
    }inline int ju(IT it){
        IT j=it,k=it;
        if(j--==s.begin())  return 0;
        if(++k==s.end())  return 0;
        return (*it-*j)*(*k-*j)*op>=0;
    }inline void in(point a){
        if(PIP(a))  return;
        IT tmp=s.lower_bound({a.x,-inf});
        if(tmp!=s.end()&&(*tmp).x==a.x)  s.erase(tmp);
        s.insert(a);IT it=s.find(a),p=it;
        if(p--!=s.begin())
            while(ju(p))  tmp=p--,s.erase(tmp);
        if(++it!=s.end())
            while(ju(it))  tmp=it++,s.erase(tmp);
    }
} up,down;
int main(){
    scanf("%d",&q);up.op=1;down.op=-1;
    while(q--){
        scanf("%d%lf%lf",&opt,&x,&y);
        if(opt==1)  up.in({x,y}),down.in({x,y});
        else  if(up.PIP({x,y})&&down.PIP({x,y}))  printf("YES\n");
                else  printf("NO\n");
    }    
} 
View Code
复制代码

面积

三角形直接套公式

复制代码
inline double mian(point xa,point xb,point xc){
    double a=len(xa-xb),b=len(xb-xc),c=len(xc-xa);
    double p=(a+b+c)*0.5;
    return sqrt(p*(p-a)*(p-b)*(p-c));
}
三角形
复制代码

凸包在点集找一定点,依次取相邻两点,分成若干三角形

 

posted @   yisiwunian  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示