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;
}
时间: 2024-08-27 11:46:52

2D简单图形相关算法罗列的相关文章

探索推荐引擎内部的秘密,第 2 部分: 深入推荐引擎相关算法 - 协同过滤(转)

第 2 部分: 深入推荐引擎相关算法 - 协同过滤 本系列的第一篇为读者概要介绍了推荐引擎,下面几篇文章将深入介绍推荐引擎的相关算法,并帮助读者高效的实现这些算法. 在现今的推荐技术和算法中,最被大家广泛认可和采用的就是基于协同过滤的推荐方法.它以其方法模型简单,数据依赖性低,数据方便采集 , 推荐效果较优等多个优点成为大众眼里的推荐算法“No.1”.本文将带你深入了解协同过滤的秘密,并给出基于 Apache Mahout 的协同过滤算法的高效实现.Apache Mahout 是 ASF 的一个

cad动态的2D/3D图形控件VectorDraw Developer Framework (VDF)

VectorDraw Developer Framework (VDF)为您的应用程序增加动态的2D/3D图形.是一个可轻松创建爱你和管理及打印2D和3D图形的构件. 其对象可显示与大多数公共矢量格式和其他CAD对象兼容的方法和属性. 支持10多种矢量格式和多种离散格式.VectorDraw Developer Framework (VDF) 是完全基于对象的和支持 .NET 2的. 此构件是用.NET 2005 C# 代码写成的. 同时还提供了一个ActiveX组件. 此ActiveX组件为旧

探索推荐引擎内部的秘密,第 3 部分: 深入推荐引擎相关算法 - 聚类

聚类分析 什么是聚类分析? 聚类 (Clustering) 就是将数据对象分组成为多个类或者簇 (Cluster),它的目标是:在同一个簇中的对象之间具有较高的相似度,而不同簇中的对象差别较大.所以,在很多应用中,一个簇中的数据对象可以被作为一个整体来对待,从而减少计算量或者提高计算质量. 其实聚类是一个人们日常生活的常见行为,即所谓"物以类聚,人以群分",核心的思想也就是聚类.人们总是不断地改进下意识中的聚类模式来学习如何区分各个事物和人.同时,聚类分析已经广泛的应用在许多应用中,包

深入推荐引擎相关算法 - 协同过滤

集体智慧和协同过滤 什么是集体智慧 集体智慧 (Collective Intelligence) 并不是 Web2.0 时代特有的,只是在 Web2.0 时代,大家在 Web 应用中利用集体智慧构建更加有趣的应用或者得到更好的用户体验.集体智慧是指在大量的人群的行为和数据中收集答案,帮助你对整个人群得到统计意义上的结论,这些结论是我们在单个个体上无法得到的,它往往是某种趋势或者人群中共性的部分. Wikipedia 和 Google 是两个典型的利用集体智慧的 Web 2.0 应用: Wikip

学习笔记:HTML5 Canvas绘制简单图形

HTML5 Canvas绘制简单图形 1.添加Canvas标签,添加id供js操作. <canvas id="mycanvas" height="700" width="1024" style="border:1px solid #aaa;text-align:center;"> 你的浏览器不支持Canvas,请更新浏览器再试!!! </canvas> 在canvas标签之间应该做浏览器是否支持的检测,

数据结构——串的相关算法实现

数据结构--串的相关算法实现 顺序串的插入函数实现 在进行顺序串的插入时,插入pos将串分为两个部分(假设为A.B,长度为LA.LB)及待插入部分(假设为C,长度为LC),则串由插入前的AB变为ACB,由于是顺序串,插入会引起元素的移动.可能会出现以下的三种情况: ①插入后串长度(LA+LC+LB)<=MAXLEN,则将B后移LC个元素位置,再将C插入: ②插入后串长度 >=MAXLEN 且 pos+LC <=MAXLEN,则 B 后移时会有部分字符被舍弃; ③插入后串长度>MAX

[java,2017-05-15] 内存回收 (流程、时间、对象、相关算法)

内存回收的流程 java的垃圾回收分为三个区域新生代.老年代. 永久代 一个对象实例化时 先去看伊甸园有没有足够的空间:如果有 不进行垃圾回收 ,对象直接在伊甸园存储:如果伊甸园内存已满,会进行一次minor gc:然后再进行判断伊甸园中的内存是否足够:如果不足 则去看存活区的内存是否足够:如果内存足够,把伊甸园部分活跃对象保存在存活区,然后把对象保存在伊甸园:如果内存不足,向老年代发送请求,查询老年代的内存是否足够:如果老年代内存足够,将部分存活区的活跃对象存入老年代.然后把伊甸园的活跃对象放

采样方法(二)MCMC相关算法介绍及代码实现

采样方法(二)MCMC相关算法介绍及代码实现 2017-12-30 15:32:14 Dark_Scope 阅读数 10509更多 分类专栏: 机器学习 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/Dark_Scope/article/details/78937731 0.引子 书接前文,在采样方法(一)中我们讲到了拒绝采样.重要性采样一系列的蒙特卡洛采样方法,但这些方法在高维空间时都

数据结构(C语言版)顺序栈相关算法的代码实现

这两天完成了栈的顺序存储结构的相关算法,包括初始化.压栈.出栈.取栈顶元素.判断栈是否为空.返回栈长度.栈的遍历.清栈.销毁栈.这次的实现过程有两点收获,总结如下: 一.清楚遍历栈的概念 栈的遍历指的是从栈底想栈顶方向运行visit()函数,这是之前的学习中所忽略的:栈的遍历解除了栈的输出顺序只能从栈顶像栈底方向的限制. 二.清空栈时要不要将stacksize重置 网上看到有的人在实现清空栈这一功能时,将stacksize重置为0,我觉得有点问题,起初的想法是将其重置为初始化时的值,在与同学讨论