transforms.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #include "transforms.h"
  2. #include "affine_matrix.h"
  3. #include <QMatrix4x4>
  4. #include <QVector3D>
  5. #include <cmath>
  6. namespace Render::Geom {
  7. namespace {
  8. const float k_epsilon = 1e-6F;
  9. const float k_epsilon_sq = k_epsilon * k_epsilon;
  10. inline void set_affine_columns(QMatrix4x4 &m, float xx, float xy, float xz,
  11. float yx, float yy, float yz, float zx, float zy,
  12. float zz, float tx, float ty, float tz) {
  13. float *d = m.data();
  14. d[0] = xx;
  15. d[1] = xy;
  16. d[2] = xz;
  17. d[3] = 0.0F;
  18. d[4] = yx;
  19. d[5] = yy;
  20. d[6] = yz;
  21. d[7] = 0.0F;
  22. d[8] = zx;
  23. d[9] = zy;
  24. d[10] = zz;
  25. d[11] = 0.0F;
  26. d[12] = tx;
  27. d[13] = ty;
  28. d[14] = tz;
  29. d[15] = 1.0F;
  30. }
  31. auto make_cylinder_local_matrix(const QVector3D &a, const QVector3D &b,
  32. float radius) -> QMatrix4x4 {
  33. const float ax = a.x();
  34. const float ay = a.y();
  35. const float az = a.z();
  36. const float bx = b.x();
  37. const float by = b.y();
  38. const float bz = b.z();
  39. const float dx = bx - ax;
  40. const float dy = by - ay;
  41. const float dz = bz - az;
  42. const float len_sq = dx * dx + dy * dy + dz * dz;
  43. const float cx = (ax + bx) * 0.5F;
  44. const float cy = (ay + by) * 0.5F;
  45. const float cz = (az + bz) * 0.5F;
  46. QMatrix4x4 m;
  47. if (len_sq <= k_epsilon_sq) {
  48. set_affine_columns(m, radius, 0.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, 0.0F,
  49. radius, cx, cy, cz);
  50. return m;
  51. }
  52. const float len = std::sqrt(len_sq);
  53. const float inv_len = 1.0F / len;
  54. const float ux = dx * inv_len;
  55. const float uy = dy * inv_len;
  56. const float uz = dz * inv_len;
  57. float tx = 0.0F;
  58. float ty = 0.0F;
  59. float tz = 0.0F;
  60. if (std::abs(uy) < 0.999F) {
  61. tx = uz;
  62. ty = 0.0F;
  63. tz = -ux;
  64. } else {
  65. tx = 0.0F;
  66. ty = -uz;
  67. tz = uy;
  68. }
  69. const float t_len_sq = tx * tx + ty * ty + tz * tz;
  70. if (t_len_sq > k_epsilon_sq) {
  71. const float inv_t_len = 1.0F / std::sqrt(t_len_sq);
  72. tx *= inv_t_len;
  73. ty *= inv_t_len;
  74. tz *= inv_t_len;
  75. } else {
  76. tx = 1.0F;
  77. ty = 0.0F;
  78. tz = 0.0F;
  79. }
  80. const float bxv = (uy * tz) - (uz * ty);
  81. const float byv = (uz * tx) - (ux * tz);
  82. const float bzv = (ux * ty) - (uy * tx);
  83. set_affine_columns(m, tx * radius, ty * radius, tz * radius, dx, dy, dz,
  84. bxv * radius, byv * radius, bzv * radius, cx, cy, cz);
  85. return m;
  86. }
  87. } // namespace
  88. auto cylinder_between(const QVector3D &a, const QVector3D &b,
  89. float radius) -> QMatrix4x4 {
  90. return make_cylinder_local_matrix(a, b, radius);
  91. }
  92. auto sphere_at(const QVector3D &pos, float radius) -> QMatrix4x4 {
  93. QMatrix4x4 m;
  94. m.translate(pos);
  95. m.scale(radius, radius, radius);
  96. return m;
  97. }
  98. auto sphere_at(const QMatrix4x4 &parent, const QVector3D &pos,
  99. float radius) -> QMatrix4x4 {
  100. QMatrix4x4 m = parent;
  101. m.translate(pos);
  102. m.scale(radius, radius, radius);
  103. return m;
  104. }
  105. auto cylinder_between(const QMatrix4x4 &parent, const QVector3D &a,
  106. const QVector3D &b, float radius) -> QMatrix4x4 {
  107. const QMatrix4x4 local = make_cylinder_local_matrix(a, b, radius);
  108. return multiply_affine(parent, local);
  109. }
  110. auto cone_from_to(const QVector3D &base_center, const QVector3D &apex,
  111. float base_radius) -> QMatrix4x4 {
  112. return cylinder_between(base_center, apex, base_radius);
  113. }
  114. auto cone_from_to(const QMatrix4x4 &parent, const QVector3D &base_center,
  115. const QVector3D &apex, float base_radius) -> QMatrix4x4 {
  116. return cylinder_between(parent, base_center, apex, base_radius);
  117. }
  118. auto capsule_between(const QVector3D &a, const QVector3D &b,
  119. float radius) -> QMatrix4x4 {
  120. return cylinder_between(a, b, radius);
  121. }
  122. auto capsule_between(const QMatrix4x4 &parent, const QVector3D &a,
  123. const QVector3D &b, float radius) -> QMatrix4x4 {
  124. return cylinder_between(parent, a, b, radius);
  125. }
  126. } // namespace Render::Geom