The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

276 lines
8.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. AffineTransform::AffineTransform (float m00, float m01, float m02,
  21. float m10, float m11, float m12) noexcept
  22. : mat00 (m00), mat01 (m01), mat02 (m02),
  23. mat10 (m10), mat11 (m11), mat12 (m12)
  24. {
  25. }
  26. bool AffineTransform::operator== (const AffineTransform& other) const noexcept
  27. {
  28. const auto tie = [] (const AffineTransform& a)
  29. {
  30. return std::tie (a.mat00, a.mat01, a.mat02, a.mat10, a.mat11, a.mat12);
  31. };
  32. return tie (*this) == tie (other);
  33. }
  34. bool AffineTransform::operator!= (const AffineTransform& other) const noexcept
  35. {
  36. return ! operator== (other);
  37. }
  38. //==============================================================================
  39. bool AffineTransform::isIdentity() const noexcept
  40. {
  41. return operator== (AffineTransform());
  42. }
  43. const AffineTransform AffineTransform::identity (1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
  44. //==============================================================================
  45. AffineTransform AffineTransform::followedBy (const AffineTransform& other) const noexcept
  46. {
  47. return { other.mat00 * mat00 + other.mat01 * mat10,
  48. other.mat00 * mat01 + other.mat01 * mat11,
  49. other.mat00 * mat02 + other.mat01 * mat12 + other.mat02,
  50. other.mat10 * mat00 + other.mat11 * mat10,
  51. other.mat10 * mat01 + other.mat11 * mat11,
  52. other.mat10 * mat02 + other.mat11 * mat12 + other.mat12 };
  53. }
  54. AffineTransform AffineTransform::translated (float dx, float dy) const noexcept
  55. {
  56. return { mat00, mat01, mat02 + dx,
  57. mat10, mat11, mat12 + dy };
  58. }
  59. AffineTransform AffineTransform::translation (float dx, float dy) noexcept
  60. {
  61. return { 1.0f, 0.0f, dx,
  62. 0.0f, 1.0f, dy };
  63. }
  64. AffineTransform AffineTransform::withAbsoluteTranslation (float tx, float ty) const noexcept
  65. {
  66. return { mat00, mat01, tx,
  67. mat10, mat11, ty };
  68. }
  69. AffineTransform AffineTransform::rotated (float rad) const noexcept
  70. {
  71. auto cosRad = std::cos (rad);
  72. auto sinRad = std::sin (rad);
  73. return { cosRad * mat00 - sinRad * mat10,
  74. cosRad * mat01 - sinRad * mat11,
  75. cosRad * mat02 - sinRad * mat12,
  76. sinRad * mat00 + cosRad * mat10,
  77. sinRad * mat01 + cosRad * mat11,
  78. sinRad * mat02 + cosRad * mat12 };
  79. }
  80. AffineTransform AffineTransform::rotation (float rad) noexcept
  81. {
  82. auto cosRad = std::cos (rad);
  83. auto sinRad = std::sin (rad);
  84. return { cosRad, -sinRad, 0,
  85. sinRad, cosRad, 0 };
  86. }
  87. AffineTransform AffineTransform::rotation (float rad, float pivotX, float pivotY) noexcept
  88. {
  89. auto cosRad = std::cos (rad);
  90. auto sinRad = std::sin (rad);
  91. return { cosRad, -sinRad, -cosRad * pivotX + sinRad * pivotY + pivotX,
  92. sinRad, cosRad, -sinRad * pivotX + -cosRad * pivotY + pivotY };
  93. }
  94. AffineTransform AffineTransform::rotated (float angle, float pivotX, float pivotY) const noexcept
  95. {
  96. return followedBy (rotation (angle, pivotX, pivotY));
  97. }
  98. AffineTransform AffineTransform::scaled (float factorX, float factorY) const noexcept
  99. {
  100. return { factorX * mat00, factorX * mat01, factorX * mat02,
  101. factorY * mat10, factorY * mat11, factorY * mat12 };
  102. }
  103. AffineTransform AffineTransform::scaled (float factor) const noexcept
  104. {
  105. return { factor * mat00, factor * mat01, factor * mat02,
  106. factor * mat10, factor * mat11, factor * mat12 };
  107. }
  108. AffineTransform AffineTransform::scale (float factorX, float factorY) noexcept
  109. {
  110. return { factorX, 0, 0, 0, factorY, 0 };
  111. }
  112. AffineTransform AffineTransform::scale (float factor) noexcept
  113. {
  114. return { factor, 0, 0, 0, factor, 0 };
  115. }
  116. AffineTransform AffineTransform::scaled (float factorX, float factorY,
  117. float pivotX, float pivotY) const noexcept
  118. {
  119. return { factorX * mat00, factorX * mat01, factorX * mat02 + pivotX * (1.0f - factorX),
  120. factorY * mat10, factorY * mat11, factorY * mat12 + pivotY * (1.0f - factorY) };
  121. }
  122. AffineTransform AffineTransform::scale (float factorX, float factorY,
  123. float pivotX, float pivotY) noexcept
  124. {
  125. return { factorX, 0, pivotX * (1.0f - factorX),
  126. 0, factorY, pivotY * (1.0f - factorY) };
  127. }
  128. AffineTransform AffineTransform::shear (float shearX, float shearY) noexcept
  129. {
  130. return { 1.0f, shearX, 0,
  131. shearY, 1.0f, 0 };
  132. }
  133. AffineTransform AffineTransform::sheared (float shearX, float shearY) const noexcept
  134. {
  135. return { mat00 + shearX * mat10,
  136. mat01 + shearX * mat11,
  137. mat02 + shearX * mat12,
  138. mat10 + shearY * mat00,
  139. mat11 + shearY * mat01,
  140. mat12 + shearY * mat02 };
  141. }
  142. AffineTransform AffineTransform::verticalFlip (float height) noexcept
  143. {
  144. return { 1.0f, 0.0f, 0.0f,
  145. 0.0f, -1.0f, height };
  146. }
  147. AffineTransform AffineTransform::inverted() const noexcept
  148. {
  149. double determinant = getDeterminant();
  150. if (! approximatelyEqual (determinant, 0.0))
  151. {
  152. determinant = 1.0 / determinant;
  153. auto dst00 = (float) ( mat11 * determinant);
  154. auto dst10 = (float) (-mat10 * determinant);
  155. auto dst01 = (float) (-mat01 * determinant);
  156. auto dst11 = (float) ( mat00 * determinant);
  157. return { dst00, dst01, -mat02 * dst00 - mat12 * dst01,
  158. dst10, dst11, -mat02 * dst10 - mat12 * dst11 };
  159. }
  160. // singularity..
  161. return *this;
  162. }
  163. bool AffineTransform::isSingularity() const noexcept
  164. {
  165. return exactlyEqual (mat00 * mat11 - mat10 * mat01, 0.0f);
  166. }
  167. AffineTransform AffineTransform::fromTargetPoints (float x00, float y00,
  168. float x10, float y10,
  169. float x01, float y01) noexcept
  170. {
  171. return { x10 - x00, x01 - x00, x00,
  172. y10 - y00, y01 - y00, y00 };
  173. }
  174. AffineTransform AffineTransform::fromTargetPoints (float sx1, float sy1, float tx1, float ty1,
  175. float sx2, float sy2, float tx2, float ty2,
  176. float sx3, float sy3, float tx3, float ty3) noexcept
  177. {
  178. return fromTargetPoints (sx1, sy1, sx2, sy2, sx3, sy3)
  179. .inverted()
  180. .followedBy (fromTargetPoints (tx1, ty1, tx2, ty2, tx3, ty3));
  181. }
  182. bool AffineTransform::isOnlyTranslation() const noexcept
  183. {
  184. return exactlyEqual (mat01, 0.0f)
  185. && exactlyEqual (mat10, 0.0f)
  186. && exactlyEqual (mat00, 1.0f)
  187. && exactlyEqual (mat11, 1.0f);
  188. }
  189. float AffineTransform::getDeterminant() const noexcept
  190. {
  191. return (mat00 * mat11) - (mat01 * mat10);
  192. }
  193. float AffineTransform::getScaleFactor() const noexcept
  194. {
  195. return (std::abs (mat00) + std::abs (mat11)) / 2.0f;
  196. }
  197. //==============================================================================
  198. //==============================================================================
  199. #if JUCE_UNIT_TESTS
  200. class AffineTransformTests final : public UnitTest
  201. {
  202. public:
  203. AffineTransformTests()
  204. : UnitTest ("AffineTransform", UnitTestCategories::maths)
  205. {}
  206. void runTest() override
  207. {
  208. beginTest ("Determinant");
  209. {
  210. constexpr float scale1 = 1.5f, scale2 = 1.3f;
  211. auto transform = AffineTransform::scale (scale1)
  212. .followedBy (AffineTransform::rotation (degreesToRadians (72.0f)))
  213. .followedBy (AffineTransform::translation (100.0f, 20.0f))
  214. .followedBy (AffineTransform::scale (scale2));
  215. expect (approximatelyEqual (std::sqrt (std::abs (transform.getDeterminant())), scale1 * scale2));
  216. }
  217. }
  218. };
  219. static AffineTransformTests timeTests;
  220. #endif
  221. } // namespace juce