Transform3D.h 4.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  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. struct Transform3D {
  29. FVector3D position;
  30. FMatrix3x3 transform;
  31. 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)) {}
  32. Transform3D(const FVector3D &position, const FMatrix3x3 &transform) :
  33. position(position),
  34. transform(transform) {}
  35. // Transform the point by multiplying with the 3x3 matrix and adding the translation
  36. FVector3D transformPoint(const FVector3D &p) const {
  37. return this->transform.transform(p) + this->position;
  38. }
  39. // Transform the vector by multiplying with the 3x3 matrix
  40. FVector3D transformVector(const FVector3D &p) const {
  41. return this->transform.transform(p);
  42. }
  43. // Transform the a vector by multiplying with the transpose of the 3x3 matrix
  44. // The transpose is the inverse for axis aligned normalized matrices
  45. // Precondition: The transform must be normalized and axis aligned (Allows rotation but no shear nor scaling)
  46. FVector3D transformPointTransposedInverse(const FVector3D &p) const {
  47. return this->transform.transformTransposed(p - this->position);
  48. }
  49. };
  50. inline Transform3D operator*(const Transform3D &left, const Transform3D &right) {
  51. return Transform3D(right.transformPoint(left.position), left.transform * right.transform);
  52. }
  53. // The determinant of a transform is the volume of a cube transformed by the matrix.
  54. // Inside-out transforms have a negative volume. (mirrored by negating one axis or swapping two)
  55. inline float determinant(const Transform3D& m) {
  56. return determinant(m.transform);
  57. }
  58. inline Transform3D inverseUsingInvDet(const Transform3D& m, float invDet) {
  59. Transform3D result;
  60. result.transform.xAxis.x = invDet * (m.transform.yAxis.y * m.transform.zAxis.z - m.transform.yAxis.z * m.transform.zAxis.y);
  61. result.transform.xAxis.y = -invDet * (m.transform.xAxis.y * m.transform.zAxis.z - m.transform.xAxis.z * m.transform.zAxis.y);
  62. result.transform.xAxis.z = invDet * (m.transform.xAxis.y * m.transform.yAxis.z - m.transform.xAxis.z * m.transform.yAxis.y);
  63. result.transform.yAxis.x = -invDet * (m.transform.yAxis.x * m.transform.zAxis.z - m.transform.yAxis.z * m.transform.zAxis.x);
  64. result.transform.yAxis.y = invDet * (m.transform.xAxis.x * m.transform.zAxis.z - m.transform.xAxis.z * m.transform.zAxis.x);
  65. result.transform.yAxis.z = -invDet * (m.transform.xAxis.x * m.transform.yAxis.z - m.transform.xAxis.z * m.transform.yAxis.x);
  66. result.transform.zAxis.x = invDet * (m.transform.yAxis.x * m.transform.zAxis.y - m.transform.yAxis.y * m.transform.zAxis.x);
  67. result.transform.zAxis.y = -invDet * (m.transform.xAxis.x * m.transform.zAxis.y - m.transform.xAxis.y * m.transform.zAxis.x);
  68. result.transform.zAxis.z = invDet * (m.transform.xAxis.x * m.transform.yAxis.y - m.transform.xAxis.y * m.transform.yAxis.x);
  69. result.position.x = -(m.position.x * result.transform.xAxis.x + m.position.y * result.transform.yAxis.x + m.position.z * result.transform.zAxis.x);
  70. result.position.y = -(m.position.x * result.transform.xAxis.y + m.position.y * result.transform.yAxis.y + m.position.z * result.transform.zAxis.y);
  71. result.position.z = -(m.position.x * result.transform.xAxis.z + m.position.y * result.transform.yAxis.z + m.position.z * result.transform.zAxis.z);
  72. return result;
  73. }
  74. inline Transform3D inverse(const Transform3D& m) {
  75. return inverseUsingInvDet(m, 1.0f / determinant(m));
  76. }
  77. inline String& string_toStreamIndented(String& target, const Transform3D& source, const ReadableString& indentation) {
  78. string_append(target, indentation, U"XAxis(", source.transform.xAxis, U"), YAxis(", source.transform.yAxis, U"), ZAxis(", source.transform.zAxis, U"), Position(", source.position, U")");
  79. return target;
  80. }
  81. }
  82. #endif