Transform3D.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // zlib open source license
  2. //
  3. // Copyright (c) 2017 to 2019 David Forsgren Piuva
  4. //
  5. // This software is provided 'as-is', without any express or implied
  6. // warranty. In no event will the authors be held liable for any damages
  7. // arising from the use of this software.
  8. //
  9. // Permission is granted to anyone to use this software for any purpose,
  10. // including commercial applications, and to alter it and redistribute it
  11. // freely, subject to the following restrictions:
  12. //
  13. // 1. The origin of this software must not be misrepresented; you must not
  14. // claim that you wrote the original software. If you use this software
  15. // in a product, an acknowledgment in the product documentation would be
  16. // appreciated but is not required.
  17. //
  18. // 2. Altered source versions must be plainly marked as such, and must not be
  19. // misrepresented as being the original software.
  20. //
  21. // 3. This notice may not be removed or altered from any source
  22. // distribution.
  23. #ifndef DFPSR_GEOMETRY_TRANSFORM3D
  24. #define DFPSR_GEOMETRY_TRANSFORM3D
  25. #include "FVector.h"
  26. #include "FMatrix3x3.h"
  27. namespace dsr {
  28. class Transform3D {
  29. public:
  30. FVector3D position;
  31. FMatrix3x3 transform;
  32. Transform3D() : position(0.0f, 0.0f, 0.0f), transform(FVector3D(1.0f, 0.0f, 0.0f), FVector3D(0.0f, 1.0f, 0.0f), FVector3D(0.0f, 0.0f, 1.0f)) {}
  33. Transform3D(const FVector3D &position, const FMatrix3x3 &transform) :
  34. position(position),
  35. transform(transform) {}
  36. // Transform the point by multiplying with the 3x3 matrix and adding the translation
  37. FVector3D transformPoint(const FVector3D &p) const {
  38. return this->transform.transform(p) + this->position;
  39. }
  40. // Transform the vector by multiplying with the 3x3 matrix
  41. FVector3D transformVector(const FVector3D &p) const {
  42. return this->transform.transform(p);
  43. }
  44. // Transform the a vector by multiplying with the transpose of the 3x3 matrix
  45. // The transpose is the inverse for axis aligned normalized matrices
  46. // Precondition: The transform must be normalized and axis aligned (Allows rotation but no shear nor scaling)
  47. FVector3D transformPointTransposedInverse(const FVector3D &p) const {
  48. return this->transform.transformTransposed(p - this->position);
  49. }
  50. };
  51. inline Transform3D operator*(const Transform3D &left, const Transform3D &right) {
  52. return Transform3D(right.transformPoint(left.position), left.transform * right.transform);
  53. }
  54. // The determinant of a transform is the volume of a cube transformed by the matrix.
  55. // Inside-out transforms have a negative volume. (mirrored by negating one axis or swapping two)
  56. inline float determinant(const Transform3D& m) {
  57. return determinant(m.transform);
  58. }
  59. inline Transform3D inverseUsingInvDet(const Transform3D& m, float invDet) {
  60. Transform3D result;
  61. result.transform.xAxis.x = invDet * (m.transform.yAxis.y * m.transform.zAxis.z - m.transform.yAxis.z * m.transform.zAxis.y);
  62. result.transform.xAxis.y = -invDet * (m.transform.xAxis.y * m.transform.zAxis.z - m.transform.xAxis.z * m.transform.zAxis.y);
  63. result.transform.xAxis.z = invDet * (m.transform.xAxis.y * m.transform.yAxis.z - m.transform.xAxis.z * m.transform.yAxis.y);
  64. result.transform.yAxis.x = -invDet * (m.transform.yAxis.x * m.transform.zAxis.z - m.transform.yAxis.z * m.transform.zAxis.x);
  65. result.transform.yAxis.y = invDet * (m.transform.xAxis.x * m.transform.zAxis.z - m.transform.xAxis.z * m.transform.zAxis.x);
  66. result.transform.yAxis.z = -invDet * (m.transform.xAxis.x * m.transform.yAxis.z - m.transform.xAxis.z * m.transform.yAxis.x);
  67. result.transform.zAxis.x = invDet * (m.transform.yAxis.x * m.transform.zAxis.y - m.transform.yAxis.y * m.transform.zAxis.x);
  68. result.transform.zAxis.y = -invDet * (m.transform.xAxis.x * m.transform.zAxis.y - m.transform.xAxis.y * m.transform.zAxis.x);
  69. result.transform.zAxis.z = invDet * (m.transform.xAxis.x * m.transform.yAxis.y - m.transform.xAxis.y * m.transform.yAxis.x);
  70. result.position.x = -(m.position.x * result.transform.xAxis.x + m.position.y * result.transform.yAxis.x + m.position.z * result.transform.zAxis.x);
  71. result.position.y = -(m.position.x * result.transform.xAxis.y + m.position.y * result.transform.yAxis.y + m.position.z * result.transform.zAxis.y);
  72. result.position.z = -(m.position.x * result.transform.xAxis.z + m.position.y * result.transform.yAxis.z + m.position.z * result.transform.zAxis.z);
  73. return result;
  74. }
  75. inline Transform3D inverse(const Transform3D& m) {
  76. return inverseUsingInvDet(m, 1.0f / determinant(m));
  77. }
  78. inline String& string_toStreamIndented(String& target, const Transform3D& source, const ReadableString& indentation) {
  79. string_append(target, indentation, U"XAxis(", source.transform.xAxis, U"), YAxis(", source.transform.yAxis, U"), ZAxis(", source.transform.zAxis, U"), Position(", source.position, U")");
  80. return target;
  81. }
  82. }
  83. #endif