zoukankan      html  css  js  c++  java
  • 计算几何板子

    struct node{
        double x,y;
    };
    node a,b,c;
    //求两个点之间的长度
    double len(node a,node b) {
        double tmp = sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
        return tmp;
    }
    //给出三个点,求三角形的面积  海伦公式: p=(a+b+c)/2,S=sqrt(p(p-a)(p-b)(p-c))
    double Area(node a,node b,node c){
        double lena = len(a,b);
        double lenb = len(b,c);
        double lenc = len(a,c);
    
        double p = (lena + lenb + lenc) / 2.0;
        double S = sqrt(p * (p - lena) * (p - lenb) * (p - lenc));
        return S;
    }
    //三角形求每条边对应的圆心角
    void Ran() {
        double lena = len(a,b);
        double lenb = len(b,c);
        double lenc = len(a,c);
        double A = acos((lenb * lenb + lenc * lenc - lena * lena) / (2 * lenb * lenc));
        double B = acos((lena * lena + lenc * lenc - lenb * lenb) / (2 * lena * lenc));
        double C = acos((lena * lena + lenb * lenb - lenc * lenc) / (2 * lena * lenb));
    }
    //求外接圆半径r = a * b * c / 4S 
    double R(node a,node b,node c) {
        double lena = len(a,b);
        double lenb = len(b,c);
        double lenc = len(a,c);
        double S = Area(a,b,c);
        double R = lena * lenb * lenc / (4.0 * S);
    }
    const double eps = 1e-8, pi = acos(-1);
    const int N = 1e5 + 10;
    struct point {
        double x, y;
    
        point() {}
    
        point(double _x, double _y) {
            x = _x;
            y = _y;
        }
    
        point operator-(const point &p) const {
            return point(x - p.x, y - p.y);
        }
    
        point operator+(const point &p) const {
            return point(x + p.x, y + p.y);
        }
    
        double operator*(const point &p) const {
            return x * p.y - y * p.x;
        }
    
        double operator/(const point &p) const {
            return x * p.x + y * p.y;
        }
    }a[N], b[N << 1];
    
    struct line {
        point p1, p2;
        double ang;
    
        line() {}
    
        line(point p01, point p02) {
            p1 = p01;
            p2 = p02;
        }
    
        void getang() {
            ang = atan2(p2.y - p1.y, p2.x - p1.x);
        }
    }c[N], q[N];
    
    struct circle
    {
        double x, y, r;
    }cc;
    
    struct point3 {
        double x, y, z;
    
        point3() {}
    
        point3(double _x, double _y, double _z) {
            x = _x;
            y = _y;
            z = _z;
        }
    
        point3 operator-(const point3 &p) const {
            return point3(x - p.x, y - p.y, z - p.z);
        }
    
        point3 operator+(const point3 &p) const {
            return point3(x + p.x, y + p.y, z - p.z);
        }
    
        point3 operator*(const point3 &p) const {
            return point3(y * p.z - z * p.y, z * p.x - x * p.z, x * p.y - y * p.x);
        }
    
        double operator/(const point3 &p) const {
            return x * p.x + y * p.y + z * p.z;
        }
    };
    
    int n;
    
    bool cmp(const point &aa, const point &bb) {
        return aa.x < bb.x || (aa.x == bb.x && aa.y < bb.y);
    }
    
    bool cmpl(const line &aa, const line &bb) {
        if (abs(aa.ang - bb.ang) > eps)
            return aa.ang < bb.ang;
        return (bb.p2 - aa.p1) * (bb.p1 - bb.p2) > 0;
    }
    
    int sgn(double x) {
        if (x > eps)
            return 1;
        if (x < -eps)
            return -1;
        return 0;
    }
    
    double getdist2(const point &aa) {
        return (aa.x * aa.x + aa.y * aa.y);
    }
    
    bool online(const point &aa, const point &bb, const point &cc) {     //三点共线判断
        if (!(min(bb.x, cc.x) <= aa.x && aa.x <= max(bb.x, cc.x)))
            return 0;
        if (!(min(bb.y, cc.y) <= aa.y && aa.y <= max(bb.y, cc.y)))
            return 0;
        return !sgn((bb - aa) * (cc - aa));
    }
    
    bool checkline(const point &aa, const point &bb, const point &cc, const point &dd) {      //线段是否相交
        int c1 = sgn((bb - aa) * (cc - aa)), c2 = sgn((bb - aa) * (dd - aa)),
                c3 = sgn((dd - cc) * (aa - cc)), c4 = sgn((dd - cc) * (bb - cc));
        if (c1 * c2 < 0 && c3 * c4 < 0)
            return 1;//规范相交
        if (c1 == 0 && c2 == 0) {
            if (min(aa.x, bb.x) > max(cc.x, dd.x) || min(cc.x, dd.x) > max(aa.x, bb.x)
                || min(aa.y, bb.y) > max(cc.y, dd.y) || min(cc.y, dd.y) > max(aa.y, bb.y))
                return 0;
            return 1;//共线有重叠
        }
        if (online(cc, aa, bb) || online(dd, aa, bb)
            || online(aa, cc, dd) || online(bb, cc, dd))
            return 1;//端点相交
        return 0;
    }
    
    point getpoint(const point &aa, const point &bb,
                   const point &cc, const point &dd) {      //两直线交点
        double a1, b1, c1, a2, b2, c2;
        point re;
        a1 = aa.y - bb.y;
        b1 = bb.x - aa.x;
        c1 = aa * bb;
        a2 = cc.y - dd.y;
        b2 = dd.x - cc.x;
        c2 = cc * dd;
        //以下为交点横纵坐标
        re.x = (c1 * b2 - c2 * b1) / (a2 * b1 - a1 * b2);
        re.y = (a2 * c1 - a1 * c2) / (a1 * b2 - a2 * b1);
        return re;
    }
    
    bool protrusion(point aa[]){    //判断多边形凹(凸)
        int flag = sgn((aa[1] - aa[0]) * (aa[2] - aa[0]));
        for (int i = 1; i < n; ++i)
            if (sgn((aa[(i + 1) % n] - aa[i]) * (aa[(i + 2) % n] - aa[i])) != flag)
                return 1;
        return 0;
    }
    bool inpolygon(const point &aa) {   //点在凸多边形内(外)
        int flag = sgn((a[0] - aa) * (a[1] - aa));
        for (int i = 1; i < n; ++i)
            if (sgn((a[i] - aa) * (a[(i + 1) % n] - aa)) != flag)
                return 0;
        return 1;
    }
    
    void transline(line &aa, double dist) {     //逆时针方向平移线段
        double d = sqrt((aa.p1.x - aa.p2.x) * (aa.p1.x - aa.p2.x) +
                        (aa.p1.y - aa.p2.y) * (aa.p1.y - aa.p2.y));
        point ta;
        ta.x = aa.p1.x + dist / d * (aa.p1.y - aa.p2.y);
        ta.y = aa.p1.y - dist / d * (aa.p1.x - aa.p2.x);
        aa.p2 = ta + aa.p2 - aa.p1;
        aa.p1 = ta;
    }
    
    void convexhull(point aa[], point bb[]) {   //凸包
        int len = 0;
        sort(aa, aa + n, cmp);
        bb[len++] = aa[0];//bb数组要开2倍(防止出现直线)
        bb[len++] = aa[1];
        for (int i = 2; i < n; ++i) {
            while (len > 1 && (aa[i] - bb[len - 2]) * (bb[len - 1] - bb[len - 2]) > 0)
                //若严格则加上等于
                --len;
            bb[len++] = aa[i];
        }
        int t = len;
        for (int i = n - 2; i >= 0; --i) {
            while (len > t && (aa[i] - bb[len - 2]) * (bb[len - 1] - bb[len - 2]) > 0)
                //同上
                --len;
            bb[len++] = aa[i];
        }
        --len;
        n = len;
    }
    bool checkout(const line &aa, const line &bb, const line &cc) {     //检查交点是否在向量顺时针侧
        point p = getpoint(aa.p1, aa.p2, bb.p1, bb.p2);
        return (cc.p1 - p) * (cc.p2 - p) < 0;//如果不允许共线或算面积 则此处不取等
    }
    
    double halfplane(point aa[], line bb[]) {   //半平面交
        sort(bb, bb + n, cmpl);
        int n2 = 1;
        for (int i = 1; i < n; ++i) {
            if (bb[i].ang - bb[i - 1].ang > eps)
                ++n2;
            bb[n2 - 1] = bb[i];
        }
        n = n2;
        int front = 0, tail = 0;
        q[tail++] = bb[0], q[tail++] = bb[1];
        for (int i = 2; i < n; ++i) {
            while (front + 1 < tail && checkout(q[tail - 2], q[tail - 1], bb[i]))
                --tail;
            while (front + 1 < tail && checkout(q[front], q[front + 1], bb[i]))
                ++front;
            q[tail++] = bb[i];
        }
        while (front + 2 < tail && checkout(q[tail - 2], q[tail - 1], q[front]))
            --tail;
        while (front + 2 < tail && checkout(q[front], q[front + 1], q[tail - 1]))
            ++front;
        if (front + 2 >= tail)
            return 0;
        int j = 0;
        for (int i = front; i < tail; ++i, ++j) {
            aa[j] = getpoint(q[i].p1, q[i].p2, q[(i != tail - 1 ? i + 1 : front)].p1,
                             q[(i != tail - 1 ? i + 1 : front)].p2);
        }
        double re = 0;
        for (int i = 1; i < j - 1; ++i)
            re += (aa[i] - aa[0]) * (aa[i + 1] - aa[0]);
        return abs(re * 0.5);
    }
    double calipers(point aa[]) {   //旋转卡壳
        double re = 0;
        aa[n] = aa[0];
        int now = 1;
        for (int i = 0; i < n; ++i) {
            while ((aa[i + 1] - aa[i]) * (aa[now + 1] - aa[i]) >
                   (aa[i + 1] - aa[i]) * (aa[now] - aa[i]))
                now = (now == n - 1 ? 0 : now + 1);
            re = max(re, getdist2(aa[now] - aa[i]));
        }
        return re;
    }
    
    line bisector(const point &aa, const point &bb) {       //中垂线(正方形)
        double mx, my;
        mx = (aa.x + bb.x) / 2;
        my = (aa.y + bb.y) / 2;
        line cc;
        cc.p1.x = mx - (aa.y - bb.y) / 2;
        cc.p1.y = my + (aa.x - bb.x) / 2;
        cc.p2 = aa + bb - cc.p1;
        cc.getang();
        return cc;
    }
    
    point rotate(const point &p, double cost, double sint) {    //逆时针向量旋转
        double x = p.x, y = p.y;
        return point(x * cost - y * sint, x * sint + y * cost);
    }
    void getpoint(circle c1, circle c2) {   //已确保两圆有交点时求出两圆交点
        long double dab = sqrt(getdist2(point(c1.x, c1.y) -
                                        point(c2.x, c2.y)));
        if (c1.r > c2.r)
            swap(c1, c2);
        long double cost = (c1.r * c1.r + dab * dab - c2.r * c2.r) /
                           (c1.r * dab * 2);
        long double sint = sqrt(1 - cost * cost);
        point re = rotate(point(c2.x, c2.y) - point(c1.x, c1.y), cost, sint);
        re.x = c1.x + re.x * (c1.r / dab);
        re.y = c1.y + re.y * (c1.r / dab);
        point re2 = rotate(point(c2.x, c2.y) - point(c1.x, c1.y), cost, -sint);
        re2.x = c1.x + re2.x * (c1.r / dab);
        re2.y = c1.y + re2.y * (c1.r / dab);
    }
    
    double mycos(double B, double C, double A) {   //余弦定理 给定边长
        return (B * B + C * C - A * A) / (B * C * 2);
    }
    double mycos2(const point &aa, const point &bb, const point &cc) {//余弦定理 给定点坐标
        double C2 = getdist2(aa - bb), A2 = getdist2(bb - cc), B2 = getdist2(cc - aa);
        return (B2 + C2 - A2) / (sqrt(B2 * C2) * 2);
    }
    point mirror_point(const point &aa, const point &bb, const point &cc) {     //轴对称点 也可用来求垂足
        double cost, sint;
        cost = mycos2(bb, cc, aa);
        sint = sqrt(1 - cost * cost);
        if ((cc - bb) * (aa - bb) > 0)
            sint = -sint;
        point re;
        re = rotate(aa - bb, cost, sint) + bb;
        re = rotate(re - bb, cost, sint) + bb;
        return re;
    }
    double area(const point &aa, const point &bb, const point &cc) {//求三角形面积
        return abs((bb - aa) * (cc - aa) / 2);
    }
    void max_triangle(const point aa[]) {   //求凸包上最大三角形
        double ans = 0;
        int p1, p2, p3;
        for (int i = 0; i < n; ++i) {
            int j = (i + 1) % n;
            int k = (j + 1) % n;
            while (k != i && area(aa[i], aa[j], aa[k]) < area(aa[i], aa[j], aa[(k + 1) % n]))
                k = (k + 1) % n;
            if (k == i)
                continue;
            int kk = (k + 1) % n;
            while (j != kk && k != i) {
                if (ans < area(aa[i], aa[j], aa[k])) {
                    ans = area(aa[i], aa[j], aa[k]);//三角形面积
                    p1 = i;
                    p2 = j;
                    p3 = k;
                }
                while (k != i && area(aa[i], aa[j], aa[k]) < area(aa[i], aa[j], aa[(k + 1) % n]))
                    k = (k + 1) % n;
                j = (j + 1) % n;
            }
        }
        point q1, q2, q3;
        q1 = b[p2] + b[p3] - b[p1];
        q2 = b[p1] + b[p3] - b[p2];
        q3 = b[p1] + b[p2] - b[p3];
        //三角形上三个点
    }
    
    void get_panel(const point3 &p1, const point3 &p2, const point3 &p3,
                   double &A, double &B, double &C, double &D) {   //由三点确定一个平面方程
        A = ((p2.y - p1.y) * (p3.z - p1.z) - (p2.z - p1.z) * (p3.y - p1.y));
        B = ((p2.z - p1.z) * (p3.x - p1.x) - (p2.x - p1.x) * (p3.z - p1.z));
        C = ((p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x));
        D = (-(A * p1.x + B * p1.y + C * p1.z));
    }
    
    double dist_panel(const point3 &pt, double A, double B, double C, double D) {   //点到平面距离
        return abs(A * pt.x + B * pt.y + C * pt.z + D) /
               sqrt(A * A + B * B + C * C);
    }
  • 相关阅读:
    php模式设计之 工厂模式
    SDK以及部署的SDK的思路
    手机用fiddler抓包开发测试
    搭建GIT服务端
    TP5.0以上数据库增加数据异常
    lnmp一键安装后的配置改动建议
    TPshop5最新版 安装 nginx 开启PATHINFO 模式资源加载路径加载失败问题,适用tp3.2PATHINFO模式REWRITE模式
    jquery写拉动条
    JS(JQ)分页 个人查看,没注释
    ecshop 分页
  • 原文地址:https://www.cnblogs.com/smallhester/p/11361297.html
Copyright © 2011-2022 走看看