• 三维空间常用函数(二) c++ Qt


            上一篇文章介绍完了点、线、面的基本函数,链接如下。

    三维空间常用函数(一) c++ Qt_嘟嘟噜噜噜啦啦的博客-CSDN博客

            接下来介绍一下投影以及求交的方法。

    1、点投影到平面与直线

            点投影到平面

            求点到平面的投影点,可以看成以这个点为起点,以平面法向量为方向的直线,与平面的交点,直线可以表示为:p + t * dir,只需求出平面上的点的t值大小即可,如图:

            从图中可以看出,投影点 P = P0 + t * nor,而 t = cenP0 * cosθ,cenP0为以cen和P0组成线段的长度,而θ为cenP0与nor的夹角,从之前点乘的定义,很容易得到 t = cenP0 * nor,所以点投影到三维平面的函数如下

    1. // 点投影到平面
    2. QVector3D ProjectionToPlane(const QVector3D& plane_center, const QVector3D& plane_normal, const QVector3D& point)
    3. {
    4. QVector3D nor = plane_normal.normalized();
    5. QVector3D temp_point;
    6. // 求点到平面的距离
    7. double t = QVector3D::dotProduct(nor, (plane_center - point));
    8. temp_point = t * nor + point;// 点到平面的距离乘法向量
    9. return temp_point;
    10. }

            点投影到直线

            有了点投影到平面之后,点投影到直线就十分简单了,如图:

            点P0投影到以cen为起点,dir为方向向量的直线上的投影点P,可以看成是点cen投影到以P0为中心点,以dir为法向量的平面的投影点,所以点投影到三维直线的函数如下:

    1. QVector3D ProjectionToLine(const QVector3D& line_center, const QVector3D& line_dir, const QVector3D& point)
    2. {
    3. return ProjectionToPlane(point, line_dir, line_center);
    4. }

    2.线与面相交

            直线与平面相交

            直线与平面相交,需要先对直线的方向向量进行判断,当直线与平面不平行的时候,那就一定会有一个交点,平行根据直线方向向量与法向量是否垂直判断即可。有交点的时候如图:

            图中平面的中心点为cen,法向量为nor,直线上一点为P0,方向向量为dir,直线与平面的交点假设为P,则根据之前点投影到平面的公式,有 t = cenP0 * nor = PP0 * nor,而线段PP0  = P - P0, 因为P在直线上,所以P = P0 + x * dir,其中x为线段PP0的长度。所以可以得到

            cenP0 * nor = (P - P0) * nor = (P0 + x * dir - P0) * nor = x * dir * nor

    → x = cenP0 * nor / (dir * nor) 

            得到了x之后,交点P的坐标就可以用P0 + x * dir得到。所以计算直线和平面的交点的函数如下:

    1. bool LineIntersectPlane(const QVector3D& line_p, const QVector3D& line_dir, const QVector3D& plane_cen, const QVector3D& plane_nor, QVector3D& out_point)
    2. {
    3. if (qAbs(QVector3D::dotProduct(line_dir, plane_nor)) < 0.0001) // 平行
    4. return false;
    5. double t = QVector3D::dotProduct(plane_cen - line_p, plane_nor) / QVector3D::dotProduct(line_dir, plane_nor);
    6. out_point = line_p + t * line_dir;
    7. return true;
    8. }

            如果判断是射线的话,只要加个t大于等于0的判断即可。如果为线段,则判断t的值是否在线段的范围内即可。

            参考链接:【寒江雪】计算直线与平面的交点坐标_平面img_285与直线img_286的交点坐标为__寒江雪_的博客-CSDN博客

            射线与三角形相交

            原理和代码参考:

    https://www.cnblogs.com/graphics/archive/2010/08/09/1795348.html

            这里给出改成Qt使用的函数:

    1. // 求射线与三角形的交点,射线起点,方向向量,三角形三个顶点坐标,交点方向分量,有交点返回真,无交点返回假
    2. bool IntersectTriangle(QVector3D orig, QVector3D dir, QVector3D v0, QVector3D v1, QVector3D v2, double& t)
    3. {
    4. // 射线上的点表示为 起点 + t * 方向向量,三角形内部所以点的参数方程为(1-u-v)*v0+u*v1+v*v2,他们相等就是交点
    5. // 三未知量u,v,t使用三阶齐次矩阵来求解
    6. // 三向量的行列式等于x1点乘x2叉乘x3
    7. double u, v;
    8. QVector3D E1 = v1 - v0;
    9. QVector3D E2 = v2 - v0;
    10. QVector3D P = QVector3D::crossProduct(dir, E2);
    11. double det = QVector3D::dotProduct(E1, P);
    12. QVector3D T;
    13. if (det > 0)
    14. {
    15. T = orig - v0;
    16. }
    17. else
    18. {
    19. T = v0 - orig;
    20. det = -det;
    21. }
    22. if (det < 0.0001f)
    23. {
    24. return false;
    25. }
    26. u = QVector3D::dotProduct(T, P);
    27. if (u<0.0f || u>det)// 没有交点,返回假
    28. return false;
    29. QVector3D Q = QVector3D::crossProduct(T, E1);
    30. v = QVector3D::dotProduct(dir, Q);
    31. if (v<0.0f || u + v>det)// 没有交点,返回假
    32. return false;
    33. t = QVector3D::dotProduct(E2, Q);
    34. t = t / det;
    35. return true;// 计算完毕之后,返回真
    36. }

  • 相关阅读:
    《算法通关村——幂运算问题解析》
    VoLTE端到端业务详解 | 空口主要信令过程
    19-springcloud(中)
    数学建模中所需要使用到的Matlab(从零开始介绍)
    Linux系统下的硬盘分区与挂载
    web概述18
    Mysql的事务以及存储引擎
    linux脚本笔记
    英语口语常用1368词汇
    数据结构与算法编程题2
  • 原文地址:https://blog.csdn.net/sk_main_void/article/details/132456101