• 2D简单图形相关算法罗列


        因为平常在Qt开发过程中经常会与一些简单的2D几何图形打交道,因此学习和掌握一些基本的2D几何计算还是很有必要的,在这里罗列一些常用的基本情况,之后会适时补充。

    [1] 两点之间距离,根据两个点的差值算出对应的向量,然后算出这个向量的斜边开放即这两点的距离。

    qreal distance(const QPointF &pt1, const QPointF &pt2)
    {
        QPointF offset = pt1 - pt2;
        return sqrt(offset.x() * offset.x() + offset.y() * offset.y());
    }

    [2]  计算两条直线的交点

    QPointF intersection(const QPointF &pt1, const QPointF &pt2, const QPointF &pt3, const QPointF &pt4)
    {
        // 首先根据两点式 (y - y1) / (y2 - y1) = (x - x1) / (x2 - x1)
        // 得出 y = (y2 - y1) / (x2 - x1)(x - x1) + y1
        // 其中(y2 - y1) / (x2 - x1)为斜率k
        // 即 y = k(x - x1) + y1
        // 两线平行即k1 == k2
        // 一线平行y即 p1.x == p2.x
        int state -- 标志位 用来进行简单的情况判断
        if (pt1.x() != pt2.x())
        {
           a = (p2.y() - p1.y()) / (p2.x() - p1.x());
           state |= 1;         // 1即01 
        }
       if (pt3.x() != pt4.x())
        {
           b = (p4.y() - p3.y()) / (p4.x() - p3.x());
           state |= 2;         // 2即10 
        }
        switch(sate)
        {
          case 0: // 既不是01也不是10,即两线同时平行于Y
              return QPointF();
          case 1: // 第一条直线斜线,第二条直线平行于Y
             float x = p3.x();
             float y = a * x - a * p1.x() + p1.y();
             return QPointF(x, y);
          case 2: // 第二条直线斜线,第一条直线平行于Y
             float x = p1.x();
             float y = b * x - a * p3.x() + p3.y();
             return QPointF(x, y);
         case 3: // 两条直线都存在斜率
             if (a == b)
                return QPointF();
             float x = (a * p1.x() - b * p3.x() - p1.y() + p3.y()) / (a - b);
             float y = a * x - a * p1.x() + p1.y();
             return QPointF(x, y);   
         }
    }

    [3] 返回一点到直线的垂直交点的坐标

    QPointF Formula::verticalCrossPoint(const QPointF &pt1, const QPointF &pt2, const QPointF &pt3)
    {
    if
    ((fabs(pt1.x() - pt2.x()) < 1e-6)) // 判断是否平行于Y轴 { return QPointF(pt1.x(), pt3.y()); } // 直线 y = ax + b, 垂线则为 -ay = x - m // 直线斜率为k,垂线斜率为-1/k qreal a = (pt1.y()- pt2.y()) / (pt1.x()- pt2.x()); qreal b = (pt1.y()- a * pt1.x()); qreal m = pt3.x() + a * pt3.y(); // 硬解求出交点 QPointF ptCross; ptCross.setX((m - a * b) / (a * a + 1)); ptCross.setY(a * ptCross.x() + b); return ptCross
    }

    [4]  判断点是否在直线上,需要注意的是,浮点数与0的比较通常为 < 1e-6。

    bool isPointInLIne(const QPointF &pt1, const QPointF &pt2, const QPointF &pt3)
    {
        if((fabs(pt1.x() - pt2.x()) < 1e-6))   // 判断是否平行于Y轴
        {
            return (fabs(pt1.x() - pt3.x()) < 1e-6);
        }
    
        // 因为 y = ax + b
    
        qreal A = (pt1.y()- pt2.y()) / (pt1.x()- pt2.x());
        qreal B = (pt1.y()- A*pt1.x());
    
        return (fabs(A * pt3.x() - pt3.y() + B) < 1e-6);
    }

    [5] 根据直线的横坐标来求点

    QPointF getPointInLineByX(const QPointF &pt1, const QPointF &pt2, qreal x)
    {
    
        if((fabs(pt1.x() - pt2.x()) < 1e-6)) // 是否平行于Y
        {
            return  pt1;
        }
    
        if((fabs(pt1.y() - pt2.y()) < 1e-6)) // 是否平行于X
        {
            return QPointF(x, pt1.y());
        }
    
        // y = ax + b
        qreal A = (pt1.y()- pt2.y()) / (pt1.x()- pt2.x());
        qreal B = (pt1.y()- A*pt1.x());
    
        return QPointF(x, (A * x + B));
    }

     [6] 根据直线的纵坐标来求点

    QPointF getPointInLineByY(const QPointF &pt1, const QPointF &pt2, qreal y)
    {
    
        if((fabs(pt1.x() - pt2.x()) < 1e-6)) 
        {
            return  QPointF(pt1.x(), y);
        }
    
        if((fabs(pt1.y() - pt2.y()) < 1e-6))
        {
            return pt1;
        }
    
        // y = ax + b
        qreal A = (pt1.y()- pt2.y()) / (pt1.x()- pt2.x());
        qreal B = (pt1.y()- A*pt1.x());
    
        return  QPointF((qreal)(y - B) / A, y );
    
    }

     [7] 椭圆周长

    // 椭圆周长:L = 2 π b + 4(a-b)
    // a表示椭圆长半轴的长,b表示椭圆短半轴的长,且a>b>0
    qreal ellipsePerimeter(qreal a, qreal b)
    {
        qreal l = a / 2, s = b / 2;
        if(a < b)
        {
            l = b / 2;
            s = a / 2;
        }
    
        return 2 * M_PI * s + 4 * (l - s);
    }

    [8] 椭圆面积

    // 椭圆的面积:S=π×a×b
    // π圆周率,a是椭圆的长半轴,b是短半轴的长
    qreal ellipseArea(qreal a, qreal b)
    {
        return M_PI * a * b / 4;
    }

    [9] 上下左右反转,返回变换矩阵

    QTransform flipTransform(bool up,bool left)
    {
        int xSign = left ? 1 : -1;
        int ySign = up ? 1 : -1;
    
        return QTransform 
            (xSign, 0,    0,
             0,   ySign,  0,
             0,    0,     1);
    }

    [10] 根据两点直线,获取从x轴正方向转换到该直线的变换矩阵

    QTransform rotateTransform(const QPointF &fromPos, const QPointF& toPos)
    {
        QVector2D directionVec = QVector2D(toPos) - QVector2D(fromPos);
    
        const qreal  hypotenuse = directionVec.length();
    
        QTransform rotateTransfrom;
    
        if (hypotenuse!=0) 
        {
            const qreal
                angleCos = directionVec.x() / hypotenuse,
                angleSin = directionVec.y() / hypotenuse;
    
            rotateTransfrom=QTransform
                (angleCos,angleSin,    0,
                 -angleSin, angleCos,    0,
                 0,         0,          1);
        }
    
        return rotateTransfrom;
    }
  • 相关阅读:
    vite.config.ts:下载相关依赖还是报没有相关声明错误 前端
    vue3开发(第一期):Vite2.0+Typescript+Vue3.2 前端
    Gitlab私有npm包构建 前端
    创建.eslintrc.js文件 前端
    vite2+Vue3+elementPlus+eslint
    快捷获取视频首页第一帧
    js 动画补间 Tween
    js 图片查看器
    javascript3d编辑器例子three.jsTHREE.js
    javascript 进度条例子
  • 原文地址:https://www.cnblogs.com/rickyk/p/3981689.html
Copyright © 2020-2023  润新知