transform.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef UI_GFX_GEOMETRY_TRANSFORM_H_
  5. #define UI_GFX_GEOMETRY_TRANSFORM_H_
  6. #include <iosfwd>
  7. #include <string>
  8. #include "third_party/skia/include/core/SkM44.h"
  9. #include "ui/gfx/geometry/geometry_skia_export.h"
  10. #include "ui/gfx/geometry/matrix44.h"
  11. #include "ui/gfx/geometry/vector2d_f.h"
  12. namespace gfx {
  13. class BoxF;
  14. class RectF;
  15. class RRectF;
  16. class Point;
  17. class PointF;
  18. class Point3F;
  19. class Quaternion;
  20. class Vector3dF;
  21. // 4x4 transformation matrix. Transform is cheap and explicitly allows
  22. // copy/assign.
  23. class GEOMETRY_SKIA_EXPORT Transform {
  24. public:
  25. enum SkipInitialization { kSkipInitialization };
  26. constexpr Transform() = default;
  27. // Skips initializing this matrix to avoid overhead, when we know it will be
  28. // initialized before use.
  29. explicit Transform(SkipInitialization)
  30. : matrix_(Matrix44::kUninitialized_Constructor) {}
  31. Transform(const Transform& rhs) = default;
  32. Transform& operator=(const Transform& rhs) = default;
  33. // Initialize with the concatenation of lhs * rhs.
  34. Transform(const Transform& lhs, const Transform& rhs)
  35. : matrix_(lhs.matrix_, rhs.matrix_) {}
  36. explicit Transform(const SkM44& matrix);
  37. explicit Transform(const Matrix44& matrix) : matrix_(matrix) {}
  38. explicit Transform(const SkMatrix& matrix) : matrix_(Matrix44(matrix)) {}
  39. // Constructs a transform from explicit 16 matrix elements. Elements
  40. // should be given in row-major order.
  41. Transform(SkScalar col1row1,
  42. SkScalar col2row1,
  43. SkScalar col3row1,
  44. SkScalar col4row1,
  45. SkScalar col1row2,
  46. SkScalar col2row2,
  47. SkScalar col3row2,
  48. SkScalar col4row2,
  49. SkScalar col1row3,
  50. SkScalar col2row3,
  51. SkScalar col3row3,
  52. SkScalar col4row3,
  53. SkScalar col1row4,
  54. SkScalar col2row4,
  55. SkScalar col3row4,
  56. SkScalar col4row4);
  57. // Constructs a transform from explicit 2d elements. All other matrix
  58. // elements remain the same as the corresponding elements of an identity
  59. // matrix.
  60. Transform(SkScalar col1row1,
  61. SkScalar col2row1,
  62. SkScalar col1row2,
  63. SkScalar col2row2,
  64. SkScalar x_translation,
  65. SkScalar y_translation);
  66. // Constructs a transform corresponding to the given quaternion.
  67. explicit Transform(const Quaternion& q);
  68. bool operator==(const Transform& rhs) const { return matrix_ == rhs.matrix_; }
  69. bool operator!=(const Transform& rhs) const { return matrix_ != rhs.matrix_; }
  70. // Resets this transform to the identity transform.
  71. void MakeIdentity() { matrix_.setIdentity(); }
  72. // Applies the current transformation on a 2d rotation and assigns the result
  73. // to |this|.
  74. void Rotate(double degrees) { RotateAboutZAxis(degrees); }
  75. // Applies the current transformation on an axis-angle rotation and assigns
  76. // the result to |this|.
  77. void RotateAboutXAxis(double degrees);
  78. void RotateAboutYAxis(double degrees);
  79. void RotateAboutZAxis(double degrees);
  80. void RotateAbout(const Vector3dF& axis, double degrees);
  81. // Applies the current transformation on a scaling and assigns the result
  82. // to |this|.
  83. void Scale(SkScalar x, SkScalar y);
  84. void Scale3d(SkScalar x, SkScalar y, SkScalar z);
  85. // Applies a scale to the current transformation and assigns the result to
  86. // |this|.
  87. void PostScale(SkScalar x, SkScalar y);
  88. // Applies the current transformation on a translation and assigns the result
  89. // to |this|.
  90. void Translate(const Vector2dF& offset);
  91. void Translate(SkScalar x, SkScalar y);
  92. void Translate3d(const Vector3dF& offset);
  93. void Translate3d(SkScalar x, SkScalar y, SkScalar z);
  94. // Applies a translation to the current transformation and assigns the result
  95. // to |this|.
  96. void PostTranslate(const Vector2dF& offset);
  97. void PostTranslate(SkScalar x, SkScalar y);
  98. // Applies the current transformation on a skew and assigns the result
  99. // to |this|.
  100. void Skew(double angle_x, double angle_y);
  101. // Applies the current transformation on a perspective transform and assigns
  102. // the result to |this|.
  103. void ApplyPerspectiveDepth(SkScalar depth);
  104. // Applies a transformation on the current transformation
  105. // (i.e. 'this = this * transform;').
  106. void PreconcatTransform(const Transform& transform);
  107. // Applies a transformation on the current transformation
  108. // (i.e. 'this = transform * this;').
  109. void ConcatTransform(const Transform& transform);
  110. // Returns true if this is the identity matrix.
  111. // This function modifies a mutable variable in |matrix_|.
  112. bool IsIdentity() const { return matrix_.isIdentity(); }
  113. // Returns true if the matrix is either identity or pure translation.
  114. bool IsIdentityOrTranslation() const { return matrix_.isTranslate(); }
  115. // Returns true if the matrix is either the identity or a 2d translation.
  116. bool IsIdentityOr2DTranslation() const {
  117. return matrix_.isTranslate() && matrix_.rc(2, 3) == 0;
  118. }
  119. // Returns true if the matrix is either identity or pure translation,
  120. // allowing for an amount of inaccuracy as specified by the parameter.
  121. bool IsApproximatelyIdentityOrTranslation(SkScalar tolerance) const;
  122. bool IsApproximatelyIdentityOrIntegerTranslation(SkScalar tolerance) const;
  123. // Returns true if the matrix is either a positive scale and/or a translation.
  124. bool IsPositiveScaleOrTranslation() const {
  125. if (!IsScaleOrTranslation())
  126. return false;
  127. return matrix_.rc(0, 0) > 0.0 && matrix_.rc(1, 1) > 0.0 &&
  128. matrix_.rc(2, 2) > 0.0;
  129. }
  130. // Returns true if the matrix is identity or, if the matrix consists only
  131. // of a translation whose components can be represented as integers. Returns
  132. // false if the translation contains a fractional component or is too large to
  133. // fit in an integer.
  134. bool IsIdentityOrIntegerTranslation() const;
  135. // Returns true if the matrix has only scaling components.
  136. bool IsScale() const { return matrix_.isScale(); }
  137. // Returns true if the matrix has only x and y scaling components.
  138. bool IsScale2d() const { return IsScale() && matrix_.rc(2, 2) == 1; }
  139. // Returns true if the matrix is has only scaling and translation components.
  140. bool IsScaleOrTranslation() const { return matrix_.isScaleTranslate(); }
  141. // Returns true if axis-aligned 2d rects will remain axis-aligned after being
  142. // transformed by this matrix.
  143. bool Preserves2dAxisAlignment() const;
  144. // Returns true if axis-aligned 2d rects will remain axis-aligned and not
  145. // clipped by perspective (w > 0) after being transformed by this matrix,
  146. // and distinct points in the x/y plane will remain distinct after being
  147. // transformed by this matrix and mapped back to the x/y plane.
  148. bool NonDegeneratePreserves2dAxisAlignment() const;
  149. // Returns true if the matrix has any perspective component that would
  150. // change the w-component of a homogeneous point.
  151. bool HasPerspective() const { return matrix_.hasPerspective(); }
  152. // Returns true if this transform is non-singular.
  153. bool IsInvertible() const { return matrix_.invert(nullptr); }
  154. // Returns true if a layer with a forward-facing normal of (0, 0, 1) would
  155. // have its back side facing frontwards after applying the transform.
  156. bool IsBackFaceVisible() const;
  157. // Inverts the transform which is passed in. Returns true if successful, or
  158. // sets |transform| to the identify matrix on failure.
  159. [[nodiscard]] bool GetInverse(Transform* transform) const;
  160. // Transposes this transform in place.
  161. void Transpose();
  162. // Set 3rd row and 3rd column to (0, 0, 1, 0). Note that this flattening
  163. // operation is not quite the same as an orthographic projection and is
  164. // technically not a linear operation.
  165. //
  166. // One useful interpretation of doing this operation:
  167. // - For x and y values, the new transform behaves effectively like an
  168. // orthographic projection was added to the matrix sequence.
  169. // - For z values, the new transform overrides any effect that the transform
  170. // had on z, and instead it preserves the z value for any points that are
  171. // transformed.
  172. // - Because of linearity of transforms, this flattened transform also
  173. // preserves the effect that any subsequent (multiplied from the right)
  174. // transforms would have on z values.
  175. //
  176. void FlattenTo2d();
  177. // Returns true if the 3rd row and 3rd column are both (0, 0, 1, 0).
  178. bool IsFlat() const;
  179. // Returns the x and y translation components of the matrix.
  180. Vector2dF To2dTranslation() const;
  181. // Returns the x and y scale components of the matrix.
  182. gfx::Vector2dF To2dScale() const {
  183. return gfx::Vector2dF(matrix_.rc(0, 0), matrix_.rc(1, 1));
  184. }
  185. // Applies the transformation to the point.
  186. void TransformPoint(Point3F* point) const;
  187. // Applies the transformation to the point.
  188. void TransformPoint(PointF* point) const;
  189. // Applies the transformation to the point.
  190. void TransformPoint(Point* point) const;
  191. // Applies the transformation to the vector.
  192. void TransformVector(Vector3dF* vector) const;
  193. // Applies the transformation to the vector.
  194. void TransformVector4(SkV4* vector) const;
  195. // Applies the reverse transformation on the point. Returns true if the
  196. // transformation can be inverted.
  197. bool TransformPointReverse(Point3F* point) const;
  198. // Applies the reverse transformation on the point. Returns true if the
  199. // transformation can be inverted. Rounds the result to the nearest point.
  200. bool TransformPointReverse(Point* point) const;
  201. // Applies transformation on the given rect. After the function completes,
  202. // |rect| will be the smallest axis aligned bounding rect containing the
  203. // transformed rect.
  204. void TransformRect(RectF* rect) const;
  205. // Applies the reverse transformation on the given rect. After the function
  206. // completes, |rect| will be the smallest axis aligned bounding rect
  207. // containing the transformed rect. Returns false if the matrix cannot be
  208. // inverted.
  209. bool TransformRectReverse(RectF* rect) const;
  210. // Applies transformation on the given |rrect|. Returns false if the transform
  211. // matrix cannot be applied to rrect.
  212. bool TransformRRectF(RRectF* rrect) const;
  213. // Applies transformation on the given box. After the function completes,
  214. // |box| will be the smallest axis aligned bounding box containing the
  215. // transformed box.
  216. void TransformBox(BoxF* box) const;
  217. // Applies the reverse transformation on the given box. After the function
  218. // completes, |box| will be the smallest axis aligned bounding box
  219. // containing the transformed box. Returns false if the matrix cannot be
  220. // inverted.
  221. bool TransformBoxReverse(BoxF* box) const;
  222. // Decomposes |this| and |from|, interpolates the decomposed values, and
  223. // sets |this| to the reconstituted result. Returns false if either matrix
  224. // can't be decomposed. Uses routines described in this spec:
  225. // http://www.w3.org/TR/css3-3d-transforms/.
  226. //
  227. // Note: this call is expensive since we need to decompose the transform. If
  228. // you're going to be calling this rapidly (e.g., in an animation) you should
  229. // decompose once using gfx::DecomposeTransforms and reuse your
  230. // DecomposedTransform.
  231. bool Blend(const Transform& from, double progress);
  232. void RoundTranslationComponents();
  233. // Returns |this| * |other|.
  234. Transform operator*(const Transform& other) const {
  235. return Transform(*this, other);
  236. }
  237. // Sets |this| = |this| * |other|
  238. Transform& operator*=(const Transform& other) {
  239. PreconcatTransform(other);
  240. return *this;
  241. }
  242. // Returns the underlying matrix.
  243. const Matrix44& matrix() const { return matrix_; }
  244. Matrix44& matrix() { return matrix_; }
  245. // TODO(crbug.com/1167153) This is to help in moving Matrix44 towards SkM44.
  246. SkM44 GetMatrixAsSkM44() const;
  247. bool ApproximatelyEqual(const gfx::Transform& transform) const;
  248. std::string ToString() const;
  249. private:
  250. void TransformPointInternal(const Matrix44& xform, Point* point) const;
  251. void TransformPointInternal(const Matrix44& xform, PointF* point) const;
  252. void TransformPointInternal(const Matrix44& xform, Point3F* point) const;
  253. void TransformVectorInternal(const Matrix44& xform, Vector3dF* vector) const;
  254. Matrix44 matrix_;
  255. // copy/assign are allowed.
  256. };
  257. // This is declared here for use in gtest-based unit tests but is defined in
  258. // the //ui/gfx:test_support target. Depend on that to use this in your unit
  259. // test. This should not be used in production code - call ToString() instead.
  260. void PrintTo(const Transform& transform, ::std::ostream* os);
  261. } // namespace gfx
  262. #endif // UI_GFX_GEOMETRY_TRANSFORM_H_