transforms.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #include "transforms.h"
  2. #include <QMatrix4x4>
  3. #include <QQuaternion>
  4. #include <QVector3D>
  5. #include <algorithm>
  6. #include <cmath>
  7. namespace Render::Geom {
  8. namespace {
  9. const float k_epsilon = 1e-6F;
  10. const float k_epsilon_sq = k_epsilon * k_epsilon;
  11. constexpr float k_flip_rotation_degrees = 180.0F;
  12. } // namespace
  13. auto cylinder_between(const QVector3D &a, const QVector3D &b,
  14. float radius) -> QMatrix4x4 {
  15. const QVector3D diff = b - a;
  16. const float len_sq = diff.lengthSquared();
  17. QMatrix4x4 m;
  18. m.translate((a + b) * 0.5F);
  19. if (len_sq > k_epsilon_sq) {
  20. const float len = std::sqrt(len_sq);
  21. const QVector3D dir = diff / len;
  22. const QVector3D up(0.0F, 1.0F, 0.0F);
  23. if (QVector3D::dotProduct(up, dir) < -0.99999F) {
  24. m.rotate(180.0F, 1.0F, 0.0F, 0.0F);
  25. } else {
  26. QQuaternion rot = QQuaternion::rotationTo(up, dir);
  27. m.rotate(rot);
  28. }
  29. m.scale(radius, len, radius);
  30. } else {
  31. m.scale(radius, 1.0F, radius);
  32. }
  33. return m;
  34. }
  35. auto sphere_at(const QVector3D &pos, float radius) -> QMatrix4x4 {
  36. QMatrix4x4 m;
  37. m.translate(pos);
  38. m.scale(radius, radius, radius);
  39. return m;
  40. }
  41. auto sphere_at(const QMatrix4x4 &parent, const QVector3D &pos,
  42. float radius) -> QMatrix4x4 {
  43. QMatrix4x4 m = parent;
  44. m.translate(pos);
  45. m.scale(radius, radius, radius);
  46. return m;
  47. }
  48. auto cylinder_between(const QMatrix4x4 &parent, const QVector3D &a,
  49. const QVector3D &b, float radius) -> QMatrix4x4 {
  50. const QVector3D diff = b - a;
  51. const float len_sq = diff.lengthSquared();
  52. QMatrix4x4 m = parent;
  53. m.translate((a + b) * 0.5F);
  54. if (len_sq > k_epsilon_sq) {
  55. const float len = std::sqrt(len_sq);
  56. const QVector3D dir = diff / len;
  57. const QVector3D up(0.0F, 1.0F, 0.0F);
  58. if (QVector3D::dotProduct(up, dir) < -0.99999F) {
  59. m.rotate(k_flip_rotation_degrees, 1.0F, 0.0F, 0.0F);
  60. } else {
  61. QQuaternion rot = QQuaternion::rotationTo(up, dir);
  62. m.rotate(rot);
  63. }
  64. m.scale(radius, len, radius);
  65. } else {
  66. m.scale(radius, 1.0F, radius);
  67. }
  68. return m;
  69. }
  70. auto cone_from_to(const QVector3D &base_center, const QVector3D &apex,
  71. float base_radius) -> QMatrix4x4 {
  72. return cylinder_between(base_center, apex, base_radius);
  73. }
  74. auto cone_from_to(const QMatrix4x4 &parent, const QVector3D &base_center,
  75. const QVector3D &apex, float base_radius) -> QMatrix4x4 {
  76. return cylinder_between(parent, base_center, apex, base_radius);
  77. }
  78. auto capsule_between(const QVector3D &a, const QVector3D &b,
  79. float radius) -> QMatrix4x4 {
  80. return cylinder_between(a, b, radius);
  81. }
  82. auto capsule_between(const QMatrix4x4 &parent, const QVector3D &a,
  83. const QVector3D &b, float radius) -> QMatrix4x4 {
  84. return cylinder_between(parent, a, b, radius);
  85. }
  86. } // namespace Render::Geom