transforms.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. #include "transforms.h"
  2. #include <algorithm>
  3. #include <cmath>
  4. namespace Render::Geom {
  5. namespace {
  6. const QVector3D kYAxis(0, 1, 0);
  7. const float kRadToDeg = 57.2957795131f;
  8. const float kEpsilon = 1e-6f;
  9. const float kEpsilonSq = kEpsilon * kEpsilon;
  10. } // namespace
  11. QMatrix4x4 cylinderBetween(const QVector3D &a, const QVector3D &b,
  12. float radius) {
  13. const float dx = b.x() - a.x();
  14. const float dy = b.y() - a.y();
  15. const float dz = b.z() - a.z();
  16. const float lenSq = dx * dx + dy * dy + dz * dz;
  17. QMatrix4x4 M;
  18. M.translate((a.x() + b.x()) * 0.5f, (a.y() + b.y()) * 0.5f,
  19. (a.z() + b.z()) * 0.5f);
  20. if (lenSq > kEpsilonSq) {
  21. const float len = std::sqrt(lenSq);
  22. const float invLen = 1.0f / len;
  23. const float ndx = dx * invLen;
  24. const float ndy = dy * invLen;
  25. const float ndz = dz * invLen;
  26. const float dot = std::clamp(ndy, -1.0f, 1.0f);
  27. const float angleDeg = std::acos(dot) * kRadToDeg;
  28. const float axisX = ndz;
  29. const float axisZ = -ndx;
  30. const float axisLenSq = axisX * axisX + axisZ * axisZ;
  31. if (axisLenSq < kEpsilonSq) {
  32. if (dot < 0.0f) {
  33. M.rotate(180.0f, 1.0f, 0.0f, 0.0f);
  34. }
  35. } else {
  36. const float axisInvLen = 1.0f / std::sqrt(axisLenSq);
  37. M.rotate(angleDeg, axisX * axisInvLen, 0.0f, axisZ * axisInvLen);
  38. }
  39. M.scale(radius, len, radius);
  40. } else {
  41. M.scale(radius, 1.0f, radius);
  42. }
  43. return M;
  44. }
  45. QMatrix4x4 sphereAt(const QVector3D &pos, float radius) {
  46. QMatrix4x4 M;
  47. M.translate(pos);
  48. M.scale(radius, radius, radius);
  49. return M;
  50. }
  51. QMatrix4x4 sphereAt(const QMatrix4x4 &parent, const QVector3D &pos,
  52. float radius) {
  53. QMatrix4x4 M = parent;
  54. M.translate(pos);
  55. M.scale(radius, radius, radius);
  56. return M;
  57. }
  58. QMatrix4x4 cylinderBetween(const QMatrix4x4 &parent, const QVector3D &a,
  59. const QVector3D &b, float radius) {
  60. const float dx = b.x() - a.x();
  61. const float dy = b.y() - a.y();
  62. const float dz = b.z() - a.z();
  63. const float lenSq = dx * dx + dy * dy + dz * dz;
  64. QMatrix4x4 M = parent;
  65. M.translate((a.x() + b.x()) * 0.5f, (a.y() + b.y()) * 0.5f,
  66. (a.z() + b.z()) * 0.5f);
  67. if (lenSq > kEpsilonSq) {
  68. const float len = std::sqrt(lenSq);
  69. const float invLen = 1.0f / len;
  70. const float ndx = dx * invLen;
  71. const float ndy = dy * invLen;
  72. const float ndz = dz * invLen;
  73. const float dot = std::clamp(ndy, -1.0f, 1.0f);
  74. const float angleDeg = std::acos(dot) * kRadToDeg;
  75. const float axisX = ndz;
  76. const float axisZ = -ndx;
  77. const float axisLenSq = axisX * axisX + axisZ * axisZ;
  78. if (axisLenSq < kEpsilonSq) {
  79. if (dot < 0.0f) {
  80. M.rotate(180.0f, 1.0f, 0.0f, 0.0f);
  81. }
  82. } else {
  83. const float axisInvLen = 1.0f / std::sqrt(axisLenSq);
  84. M.rotate(angleDeg, axisX * axisInvLen, 0.0f, axisZ * axisInvLen);
  85. }
  86. M.scale(radius, len, radius);
  87. } else {
  88. M.scale(radius, 1.0f, radius);
  89. }
  90. return M;
  91. }
  92. QMatrix4x4 coneFromTo(const QVector3D &baseCenter, const QVector3D &apex,
  93. float baseRadius) {
  94. return cylinderBetween(baseCenter, apex, baseRadius);
  95. }
  96. QMatrix4x4 coneFromTo(const QMatrix4x4 &parent, const QVector3D &baseCenter,
  97. const QVector3D &apex, float baseRadius) {
  98. return cylinderBetween(parent, baseCenter, apex, baseRadius);
  99. }
  100. } // namespace Render::Geom