zoukankan      html  css  js  c++  java
  • 计算几何_直线求交点_线段判相交

    附上一水题

    double eps = 1e-8;
    
    struct Point {
        double x, y;
        Point () {}
        Point (double _x, double _y) : x(_x), y(_y) {}
        
        void Read() {
            scanf("%lf%lf", &x, &y);
        }
        
        Point operator + (const Point &a) const { return Point(x + a.x, y + a.y); }
        
        // 叉积=0是指两向量平行(重合)
        Point operator - (const Point &a) const { return Point(x - a.x, y - a.y); }
        
        double operator ^ (const Point &a) const { return x * a.y - y * a.x; }  // 叉积 
        double operator * (const Point &a) const { return x * a.x + y * a.y; }  // 点积 
        
        // 定义给map set 之类用的.. 不要用极角 可能会出错 
        bool operator <  (const Point &a) const {
            if (x != a.x) return x < a.x;
            return y < a.y;
        }
    };
    
    struct Triangle {
        Point pt1, pt2, pt3;
    };
    
    typedef Point Vector;
    
    double GetLenght(Vector A) { return A * A; } // 获取长度 
    double GetLenght(Point A, Point B) { return sqrt((A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y)); }
    
    double GetAngle(Vector A, Vector B) { return acos( (A*B) / GetLenght(A) / GetLenght(B)); } // 获取夹角[-pi/2, pi/2]
    
    double GetArea(Vector A, Vector B) { return A ^ B; } // 四边形面积, 有正负 
    
    // AB --> AC  A到B: B-A  
    double GetArea(Point A, Point B, Point C) { return GetArea(B-A, C-A); }  //  四边形面积, 有正负 
    
    double GetCross(Point st, Point ed1, Point ed2) { return (ed1 - st) ^ (ed2 - st); }
    
    
    /*点定位*/
    
    // 点是否在线段上 
    // 原理:  
    // 充要条件: 三点共线  同时 jpt 点在 线段 之间 
    // --------> 三点共线  同时 jpt 在st ed组成的矩阵里 
    bool IsPointInSegment(const Point &jpt, const Point &st, const Point &ed)
    {
        if (GetCross(jpt, st, ed) == 0.0 && 
            min(st.x, ed.x) <= jpt.x &&
            max(st.x, ed.x) >= jpt.x &&
            max(st.y, ed.y) <= jpt.y &&
            max(st.y, ed.y) >= jpt.y)
            return true;
        return false;
    }
    
    // 点是否在三角形内部
    // 原理:  
    // 点与三角形三个顶点构成的三个三角形的面积之和 与 三角形是否一样.
    // 如果一样说明点在三角形内部 
    bool IsPointInTriangle(const Point &jpt, const Triangle &t)
    {
        double s,s1, s2, s3;
        s = fabs(GetArea(t.pt1 - t.pt2, t.pt3 - t.pt2));
        s1  = fabs(GetArea(t.pt1 - jpt, t.pt2 - jpt));
        s1  = fabs(GetArea(t.pt1 - jpt, t.pt3 - jpt));
        s1  = fabs(GetArea(t.pt2 - jpt, t.pt3 - jpt));
        return s == s1 + s2 + s3;
    } 
    
    // 点在多边形内外
    // 一  扫描法
    // 二  叉乘判别法
    // 三  角度和判别法
    // 四  特别的 点在矩形或园中. 
    
    
    // 点是否在矩形
    // 矩形点是 st 和 ed 
    bool IsPointInRectangle(const Point &jpt, const Point &st, const Point &ed) 
    {
        
        if (min(st.x, ed.x) <= jpt.x &&
            max(st.x, ed.x) >= jpt.x &&
            min(st.y, ed.y) <= jpt.y &&
            max(st.y, ed.y) >= jpt.y) 
                return true;
        return false;
    }
    
    /*
    两线段相交分为"规范相交"和"非规范相交"。 
    "规范相交"指的是两条线段恰有唯一一个不是端点的公共点;
    而如果一条线段的一个端点在另一条线段上,或者两条线段部分重合,则视为“非规范相交”,
    */ 
    bool IsSegmentIntersect(const Point &A, const Point &B, const Point &C, const Point &D) {
        
        //  快速排斥 好理解版本  判断在不在矩形内.  重叠情况也可以判断 
        if (!IsPointInRectangle(C, A, B) && !IsPointInRectangle(D, A, B)) return false;
        if (GetCross(A, C, B) * GetCross(A, D, B) <= 0.0 &&
            GetCross(C, A, D) * GetCross(C, B, D) <= 0.0)  
            return true;
        return false;
        
        // 前3句是快速排斥 
        // 后2句是跨立实验  <= 表示允许重叠 端点在另一线段上 < 则不允许 
    /*    if (max(A.x, B.x) >= min(C.x, D.x) &&
            min(A.x, B.x) <= max(C.x, D.x) &&
            max(A.y, B.y) >= min(C.y, D.y) &&
            GetCross(A, C, B) * GetCross(A, D, B) <= 0.0 &&
            GetCross(C, A, D) * GetCross(C, B, D) <= 0.0 )
            return true;
        return false;*/
    } 
    
    struct Segment {
        Point st;
        Point ed;
        int id;
        void Read() {
            scanf("%lf%lf%lf%lf", &st.x, &st.y, &ed.x, &ed.y);
        } 
        Segment() {}
        Segment(Point A, Point B) { st = A; ed = B; } 
    };
    
    bool IsSegmentIntersect(const Segment &A,const Segment &B) {
        return IsSegmentIntersect(A.st, A.ed, B.st, B.ed);
    }
    
    // Ax + By + C = 0
    // y = kX + b; 使用克拉默法则的时候需要注意C的符号. 
    struct Line {
        Point st;
        Point ed;
        double A, B, C, k, b;
    //    Vector v;
    
        void Read() {
            scanf("%lf%lf%lf%lf", &st.x, &st.y, &ed.x, &ed.y);
            init();
        //    printf("%lf %lf %lf 
    ", A, B, C);
        }
        Line () {}
        Line (Point A, Point B) {
            st = A;
            ed = B;
            init();
        }
        Line (Segment s_g) {
            st = s_g.st;
            ed = s_g.ed;
            init();
        }
        
        void init() {
            if (ed.x - st.x == 0.0) {
                 k = 999999999999.99;
                 b = st.y;
            } else {
                k = (ed.y - st.y) / (ed.x - st.x);
                b = st.y - k * st.x;
            }
            A = st.y - ed.y;
            B = ed.x - st.x;
            C = st.x * (ed.y - st.y) - st.y * (ed.x - st.x);
    //        v = ed - st;
        }
    };
    
    // 判断两直线是否共线 
    bool IsLineLineCollinear(const Line &a,const Line &b) {
        return fabs(((a.ed - a.st) ^ (b.ed - b.st))) < eps ? true : false;
    }
    
    // 判断两直线是否平行
    bool IsLineLineParallel(const Line &a, const Line &b) {
        if (!IsLineLineCollinear(a, b)) return false;
        return fabs(((b.st - a.st) ^ (b.ed - a.st))) < eps ? false : true;
    }
    
    // 判断两直线是否重叠 
    bool IsLineLineOver(const Line &a, const Line &b) {
        if (!IsLineLineCollinear(a, b)) return false;
        return fabs(((b.st - a.st) ^ (b.ed - a.st))) < eps ? true : false;
    }
    
    
    // 使用前需 确保直线已经调用 init()初始化,  是根据已知直线2点来求的.
    // 使用克拉默法则 
    Point GetLineLineIntersect(const Line &a, const Line &b) {
        Point pt = a.st;
        if (IsLineLineCollinear(a, b)) return pt;  // 如果共线 或者平行 瞎返回 
        
        double D = a.A * b.B - a.B * b.A;
        double D1 = (-a.C) * b.B - a.B * (-b.C);
        double D2 = a.A * (-b.C) - b.A * (-a.C);
        pt.x = D1 / D;
        pt.y = D2 / D;
        return pt;
    }
    
    
    // 跨立实验的原理
    // 如果直线AB 跨立 CD 那么有 (AC ^ AB) * (AD ^ AB) > 0
    // 所以跨立实验要判2个GetCross   
    bool IsLineSegmentIntersect(const Line &line, const Segment &s_g) {
        if (GetCross(line.st, s_g.st, line.ed) * GetCross(line.st, s_g.ed, line.ed) > 0.0 ) return true;
        return false;
    } 
    
    //  叉积极角排序. 
    //  以Qcmppt为起点 做极角排序. 
    Point Qcmppt; 
    bool cmp_j_j_j(const Point &A, const Point &B) {  
        int m = (A-Qcmppt) ^ (B-Qcmppt); 
        if (m != 0.0) return m > 0.0;
        if (A.x != B.x)  return A.x < B.x;
        return false;
    }
    
    // 求多边形面积, 从pts从1开始求面积  有n个点 
    // 按照极角排序 
    double GetArea(Point pts[], int ss[], int n)
    {
        int i;
        double res = 0;
        // 只划分成n-2个三角形.  
        for (i=2; i<n; ++i) 
            res += GetCross(pts[ss[1]], pts[ss[i]], pts[ss[i+1]]); 
        res = res / 2.0; 
        return fabs(res);
    }
    
    // 求多边形周长  也需要先排序. 
    double GetLenght(Point pts[], int ss[], int n)
    {
        int i;
        double res = GetLenght(pts[ss[1]], pts[ss[n]]);
        // 只划分成n-2个三角形.  
        for (i=1; i<n; ++i) 
            res += GetLenght(pts[ss[i]], pts[ss[i+1]]);
        return fabs(res);
    } 
  • 相关阅读:
    P1772 [ZJOI2006]物流运输
    P3951 小凯的疑惑
    P1082 同余方程(【模板】exgcd)
    T107741 【模板】权值线段树合并
    P3205 [HNOI2010]合唱队
    P1062 数列
    P1144 最短路计数
    P1502 窗口的星星
    P4147 玉蟾宫(【模板】悬线法)
    CSP模拟赛#3 分段(T1-26)
  • 原文地址:https://www.cnblogs.com/cgjh/p/9413896.html
Copyright © 2011-2022 走看看