zoukankan      html  css  js  c++  java
  • 几何中点/线/多边形模板


    ----------

    #include<vector>
    #include<list>
    #include<map>
    #include<set>
    #include<deque>
    #include<queue>
    #include<stack>
    #include<bitset>
    #include<algorithm>
    #include<functional>
    #include<numeric>
    #include<utility>
    #include<iostream>
    #include<sstream>
    #include<iomanip>
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cctype>
    #include<string>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<ctime>
    #include<climits>
    #include<complex>
    #define mp make_pair
    #define pb push_back
    using namespace std;
    const double eps=1e-8;//精度
    const double pi=acos(-1.0);//π
    const double inf=1e20;//无穷大
    const int maxp=1111;//最大点数
    /*
        判断d是否在精度内等于0
    */
    int dblcmp(double d)
    {
        if (fabs(d)<eps)return 0;
        return d>eps?1:-1;
    }
    /*
        求x的平方
    */
    inline double sqr(double x){return x*x;}
    /*
        点/向量
    */
    struct point
    {
        double x,y;
        point(){}
        point(double _x,double _y):x(_x),y(_y){};
        //读入一个点
        void input()
        {
            scanf("%lf%lf",&x,&y);
        }
        //输出一个点
        void output()
        {
            printf("%.2f %.2f\n",x,y);
        }
        //判断两点是否相等
        bool operator==(point a)const
        {
            return dblcmp(a.x-x)==0&&dblcmp(a.y-y)==0;
        }
        //判断两点大小
        bool operator<(point a)const
        {
            return dblcmp(a.x-x)==0?dblcmp(y-a.y)<0:x<a.x;
        }
        //点到源点的距离/向量的长度
        double len()
        {
            return hypot(x,y);
        }
        //点到源点距离的平方
        double len2()
        {
            return x*x+y*y;
        }
        //两点间的距离
        double distance(point p)
        {
            return hypot(x-p.x,y-p.y);
        }
        //向量加
        point add(point p)
        {
            return point(x+p.x,y+p.y);
        }
        //向量减
        point sub(point p)
        {
            return point(x-p.x,y-p.y);
        }
        //向量乘
        point mul(double b)
        {
            return point(x*b,y*b);
        }
        //向量除
        point div(double b)
        {
            return point(x/b,y/b);
        }
        //点乘
        double dot(point p)
        {
            return x*p.x+y*p.y;
        }
        //叉乘
        double det(point p)
        {
            return x*p.y-y*p.x;
        }
        //XXXXXXX
        double rad(point a,point b)
        {
            point p=*this;
            return fabs(atan2(fabs(a.sub(p).det(b.sub(p))),a.sub(p).dot(b.sub(p))));
        }
        //截取长度r
        point trunc(double r)
        {
            double l=len();
            if (!dblcmp(l))return *this;
            r/=l;
            return point(x*r,y*r);
        }
        //左转90度
        point rotleft()
        {
            return point(-y,x);
        }
        //右转90度
        point rotright()
        {
            return point(y,-x);
        }
        //绕点p逆时针旋转angle角度
        point rotate(point p,double angle)
        {
            point v=this->sub(p);
            double c=cos(angle),s=sin(angle);
            return point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c);
        }
    };
    /*
        线段/直线
    */
    struct line
    {
        point a,b;
        line(){}
        line(point _a,point _b)
        {
            a=_a;
            b=_b;
        }
        //判断线段相等
        bool operator==(line v)
        {
            return (a==v.a)&&(b==v.b);
        }
        //点p做倾斜角为angle的射线
        line(point p,double angle)
        {
            a=p;
            if (dblcmp(angle-pi/2)==0)
            {
                b=a.add(point(0,1));
            }
            else
            {
                b=a.add(point(1,tan(angle)));
            }
        }
        //直线一般式ax+by+c=0
        line(double _a,double _b,double _c)
        {
            if (dblcmp(_a)==0)
            {
                a=point(0,-_c/_b);
                b=point(1,-_c/_b);
            }
            else if (dblcmp(_b)==0)
            {
                a=point(-_c/_a,0);
                b=point(-_c/_a,1);
            }
            else
            {
                a=point(0,-_c/_b);
                b=point(1,(-_c-_a)/_b);
            }
        }
        //读入一个线段
        void input()
        {
            a.input();
            b.input();
        }
        //校准线段两点
        void adjust()
        {
            if (b<a)swap(a,b);
        }
        //线段长度
        double length()
        {
            return a.distance(b);
        }
        //直线倾斜角 0<=angle<180
        double angle()
        {
            double k=atan2(b.y-a.y,b.x-a.x);
            if (dblcmp(k)<0)k+=pi;
            if (dblcmp(k-pi)==0)k-=pi;
            return k;
        }
        //点和线段关系
        //1 在逆时针
        //2 在顺时针
        //3 平行
        int relation(point p)
        {
            int c=dblcmp(p.sub(a).det(b.sub(a)));
            if (c<0)return 1;
            if (c>0)return 2;
            return 3;
        }
        //点是否在线段上
        bool pointonseg(point p)
        {
            return dblcmp(p.sub(a).det(b.sub(a)))==0&&dblcmp(p.sub(a).dot(p.sub(b)))<=0;
        }
        //两线是否平行
        bool parallel(line v)
        {
            return dblcmp(b.sub(a).det(v.b.sub(v.a)))==0;
        }
        //线段和线段关系
        //0 不相交
        //1 非规范相交
        //2 规范相交
        int segcrossseg(line v)
        {
            int d1=dblcmp(b.sub(a).det(v.a.sub(a)));
            int d2=dblcmp(b.sub(a).det(v.b.sub(a)));
            int d3=dblcmp(v.b.sub(v.a).det(a.sub(v.a)));
            int d4=dblcmp(v.b.sub(v.a).det(b.sub(v.a)));
            if ((d1^d2)==-2&&(d3^d4)==-2)return 2;
            return (d1==0&&dblcmp(v.a.sub(a).dot(v.a.sub(b)))<=0||
                    d2==0&&dblcmp(v.b.sub(a).dot(v.b.sub(b)))<=0||
                    d3==0&&dblcmp(a.sub(v.a).dot(a.sub(v.b)))<=0||
                    d4==0&&dblcmp(b.sub(v.a).dot(b.sub(v.b)))<=0);
        }
        //线段和直线v关系
        int linecrossseg(line v)//*this seg v line
        {
            int d1=dblcmp(b.sub(a).det(v.a.sub(a)));
            int d2=dblcmp(b.sub(a).det(v.b.sub(a)));
            if ((d1^d2)==-2)return 2;
            return (d1==0||d2==0);
        }
        //直线和直线关系
        //0 平行
        //1 重合
        //2 相交
        int linecrossline(line v)
        {
            if ((*this).parallel(v))
            {
                return v.relation(a)==3;
            }
            return 2;
        }
        //求两线交点
        point crosspoint(line v)
        {
            double a1=v.b.sub(v.a).det(a.sub(v.a));
            double a2=v.b.sub(v.a).det(b.sub(v.a));
            return point((a.x*a2-b.x*a1)/(a2-a1),(a.y*a2-b.y*a1)/(a2-a1));
        }
        //点p到直线的距离
        double dispointtoline(point p)
        {
            return fabs(p.sub(a).det(b.sub(a)))/length();
        }
        //点p到线段的距离
        double dispointtoseg(point p)
        {
            if (dblcmp(p.sub(b).dot(a.sub(b)))<0||dblcmp(p.sub(a).dot(b.sub(a)))<0)
            {
                return min(p.distance(a),p.distance(b));
            }
            return dispointtoline(p);
        }
        //XXXXXXXX
        point lineprog(point p)
        {
            return a.add(b.sub(a).mul(b.sub(a).dot(p.sub(a))/b.sub(a).len2()));
        }
        //点p关于直线的对称点
        point symmetrypoint(point p)
        {
            point q=lineprog(p);
            return point(2*q.x-p.x,2*q.y-p.y);
        }
    };
    
    /*
        多边形
    */
    struct polygon
    {
        int n;//点个数
        point p[maxp];//顶点
        line l[maxp];//边
        //读入一个多边形
        void input(int n=4)
        {
            for (int i=0;i<n;i++)
            {
                p[i].input();
            }
        }
        //添加一个点
        void add(point q)
        {
            p[n++]=q;
        }
        //取得边
        void getline()
        {
            for (int i=0;i<n;i++)
            {
                l[i]=line(p[i],p[(i+1)%n]);
            }
        }
        struct cmp
        {
            point p;
            cmp(const point &p0){p=p0;}
            bool operator()(const point &aa,const point &bb)
            {
                point a=aa,b=bb;
                int d=dblcmp(a.sub(p).det(b.sub(p)));
                if (d==0)
                {
                    return dblcmp(a.distance(p)-b.distance(p))<0;
                }
                return d>0;
            }
        };
        void norm()
        {
            point mi=p[0];
            for (int i=1;i<n;i++)mi=min(mi,p[i]);
            sort(p,p+n,cmp(mi));
        }
        //求凸包存入多边形convex
        void getconvex(polygon &convex)
        {
            int i,j,k;
            sort(p,p+n);
            convex.n=n;
            for (i=0;i<min(n,2);i++)
            {
                convex.p[i]=p[i];
            }
            if (n<=2)return;
            int &top=convex.n;
            top=1;
            for (i=2;i<n;i++)
            {
                while (top&&convex.p[top].sub(p[i]).det(convex.p[top-1].sub(p[i]))<=0)
                    top--;
                convex.p[++top]=p[i];
            }
            int temp=top;
            convex.p[++top]=p[n-2];
            for (i=n-3;i>=0;i--)
            {
                while (top!=temp&&convex.p[top].sub(p[i]).det(convex.p[top-1].sub(p[i]))<=0)
                    top--;
                convex.p[++top]=p[i];
            }
        }
        //判断是否凸多边形
        bool isconvex()
        {
            bool s[3];
            memset(s,0,sizeof(s));
            int i,j,k;
            for (i=0;i<n;i++)
            {
                j=(i+1)%n;
                k=(j+1)%n;
                s[dblcmp(p[j].sub(p[i]).det(p[k].sub(p[i])))+1]=1;
                if (s[0]&&s[2])return 0;
            }
            return 1;
        }
        //点与多边形关系
        //0 外部
        //1 内部
        //2 边上
        //3 点上
        int relationpoint(point q)
        {
            int i,j;
            for (i=0;i<n;i++)
            {
                if (p[i]==q)return 3;
            }
            getline();
            for (i=0;i<n;i++)
            {
                if (l[i].pointonseg(q))return 2;
            }
            int cnt=0;
            for (i=0;i<n;i++)
            {
                j=(i+1)%n;
                int k=dblcmp(q.sub(p[j]).det(p[i].sub(p[j])));
                int u=dblcmp(p[i].y-q.y);
                int v=dblcmp(p[j].y-q.y);
                if (k>0&&u<0&&v>=0)cnt++;
                if (k<0&&v<0&&u>=0)cnt--;
            }
            return cnt!=0;
        }
        //线段与多边形关系
        //0 无任何交点
        //1 在多边形内长度为正
        //2 相交或与边平行
        int relationline(line u)
        {
            int i,j,k=0;
            getline();
            for (i=0;i<n;i++)
            {
                if (l[i].segcrossseg(u)==2)return 1;
                if (l[i].segcrossseg(u)==1)k=1;
            }
            if (!k)return 0;
            vector<point>vp;
            for (i=0;i<n;i++)
            {
                if (l[i].segcrossseg(u))
                {
                    if (l[i].parallel(u))
                    {
                        vp.pb(u.a);
                        vp.pb(u.b);
                        vp.pb(l[i].a);
                        vp.pb(l[i].b);
                        continue;
                    }
                    vp.pb(l[i].crosspoint(u));
                }
            }
            sort(vp.begin(),vp.end());
            int sz=vp.size();
            for (i=0;i<sz-1;i++)
            {
                point mid=vp[i].add(vp[i+1]).div(2);
                if (relationpoint(mid)==1)return 1;
            }
            return 2;
        }
        //直线u切割凸多边形左侧
        //注意直线方向
        void convexcut(line u,polygon &po)
        {
            int i,j,k;
            int &top=po.n;
            top=0;
            for (i=0;i<n;i++)
            {
                int d1=dblcmp(p[i].sub(u.a).det(u.b.sub(u.a)));
                int d2=dblcmp(p[(i+1)%n].sub(u.a).det(u.b.sub(u.a)));
                if (d1>=0)po.p[top++]=p[i];
                if (d1*d2<0)po.p[top++]=u.crosspoint(line(p[i],p[(i+1)%n]));
            }
        }
        //取得周长
        double getcircumference()
        {
            double sum=0;
            int i;
            for (i=0;i<n;i++)
            {
                sum+=p[i].distance(p[(i+1)%n]);
            }
            return sum;
        }
        //取得面积
        double getarea()
        {
            double sum=0;
            int i;
            for (i=0;i<n;i++)
            {
                sum+=p[i].det(p[(i+1)%n]);
            }
            return fabs(sum)/2;
        }
        bool getdir()//1代表逆时针 0代表顺时针
        {
            double sum=0;
            int i;
            for (i=0;i<n;i++)
            {
                sum+=p[i].det(p[(i+1)%n]);
            }
            if (dblcmp(sum)>0)return 1;
            return 0;
        }
        //取得重心
        point getbarycentre()
        {
            point ret(0,0);
            double area=0;
            int i;
            for (i=1;i<n-1;i++)
            {
                double tmp=p[i].sub(p[0]).det(p[i+1].sub(p[0]));
                if (dblcmp(tmp)==0)continue;
                area+=tmp;
                ret.x+=(p[0].x+p[i].x+p[i+1].x)/3*tmp;
                ret.y+=(p[0].y+p[i].y+p[i+1].y)/3*tmp;
            }
            if (dblcmp(area))ret=ret.div(area);
            return ret;
        }
        //点在凸多边形内部的判定
        int pointinpolygon(point q)
        {
            if (getdir())reverse(p,p+n);
            if (dblcmp(q.sub(p[0]).det(p[n-1].sub(p[0])))==0)
            {
                if (line(p[n-1],p[0]).pointonseg(q))return n-1;
                return -1;
            }
            int low=1,high=n-2,mid;
            while (low<=high)
            {
                mid=(low+high)>>1;
                if (dblcmp(q.sub(p[0]).det(p[mid].sub(p[0])))>=0&&dblcmp(q.sub(p[0]).det(p[mid+1].sub(p[0])))<0)
                {
                    polygon c;
                    c.p[0]=p[mid];
                    c.p[1]=p[mid+1];
                    c.p[2]=p[0];
                    c.n=3;
                    if (c.relationpoint(q))return mid;
                    return -1;
                }
                if (dblcmp(q.sub(p[0]).det(p[mid].sub(p[0])))>0)
                {
                    low=mid+1;
                }
                else
                {
                    high=mid-1;
                }
            }
            return -1;
        }
    };


    ----------



  • 相关阅读:
    面试问题
    知识点整合
    前端错误
    基于.NET平台常用的框架整理
    BFC和haslayout
    javascript面向对象
    javascript变量的作用域
    2014-05-26 总结
    2014-05-23 总结
    PHP实现mvc模式的思想
  • 原文地址:https://www.cnblogs.com/cyendra/p/3226293.html
Copyright © 2011-2022 走看看