1 /* 2 ============================================================================== 3 4 This file is part of the JUCE library. 5 Copyright (c) 2020 - Raw Material Software Limited 6 7 JUCE is an open source library subject to commercial or open-source 8 licensing. 9 10 By using JUCE, you agree to the terms of both the JUCE 6 End-User License 11 Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). 12 13 End User License Agreement: www.juce.com/juce-6-licence 14 Privacy Policy: www.juce.com/juce-privacy-policy 15 16 Or: You may also use this code under the terms of the GPL v3 (see 17 www.gnu.org/licenses). 18 19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER 20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE 21 DISCLAIMED. 22 23 ============================================================================== 24 */ 25 26 namespace juce 27 { 28 29 //============================================================================== 30 /** 31 Represents a 2D affine-transformation matrix. 32 33 An affine transformation is a transformation such as a rotation, scale, shear, 34 resize or translation. 35 36 These are used for various 2D transformation tasks, e.g. with Path objects. 37 38 @see Path, Point, Line 39 40 @tags{Graphics} 41 */ 42 class JUCE_API AffineTransform final 43 { 44 public: 45 //============================================================================== 46 /** Creates an identity transform. */ 47 AffineTransform() = default; 48 49 /** Creates a copy of another transform. */ 50 AffineTransform (const AffineTransform&) = default; 51 52 /** Creates a transform from a set of raw matrix values. 53 54 The resulting matrix is: 55 56 (mat00 mat01 mat02) 57 (mat10 mat11 mat12) 58 ( 0 0 1 ) 59 */ 60 AffineTransform (float mat00, float mat01, float mat02, 61 float mat10, float mat11, float mat12) noexcept; 62 63 /** Copies from another AffineTransform object */ 64 AffineTransform& operator= (const AffineTransform&) = default; 65 66 /** Compares two transforms. */ 67 bool operator== (const AffineTransform& other) const noexcept; 68 69 /** Compares two transforms. */ 70 bool operator!= (const AffineTransform& other) const noexcept; 71 72 //============================================================================== 73 /** Transforms a 2D coordinate using this matrix. */ 74 template <typename ValueType> transformPoint(ValueType & x,ValueType & y)75 void transformPoint (ValueType& x, ValueType& y) const noexcept 76 { 77 auto oldX = x; 78 x = static_cast<ValueType> (mat00 * oldX + mat01 * y + mat02); 79 y = static_cast<ValueType> (mat10 * oldX + mat11 * y + mat12); 80 } 81 82 /** Transforms two 2D coordinates using this matrix. 83 This is just a shortcut for calling transformPoint() on each of these pairs of 84 coordinates in turn. (And putting all the calculations into one function hopefully 85 also gives the compiler a bit more scope for pipelining it). 86 */ 87 template <typename ValueType> transformPoints(ValueType & x1,ValueType & y1,ValueType & x2,ValueType & y2)88 void transformPoints (ValueType& x1, ValueType& y1, 89 ValueType& x2, ValueType& y2) const noexcept 90 { 91 auto oldX1 = x1, oldX2 = x2; 92 x1 = static_cast<ValueType> (mat00 * oldX1 + mat01 * y1 + mat02); 93 y1 = static_cast<ValueType> (mat10 * oldX1 + mat11 * y1 + mat12); 94 x2 = static_cast<ValueType> (mat00 * oldX2 + mat01 * y2 + mat02); 95 y2 = static_cast<ValueType> (mat10 * oldX2 + mat11 * y2 + mat12); 96 } 97 98 /** Transforms three 2D coordinates using this matrix. 99 This is just a shortcut for calling transformPoint() on each of these pairs of 100 coordinates in turn. (And putting all the calculations into one function hopefully 101 also gives the compiler a bit more scope for pipelining it). 102 */ 103 template <typename ValueType> transformPoints(ValueType & x1,ValueType & y1,ValueType & x2,ValueType & y2,ValueType & x3,ValueType & y3)104 void transformPoints (ValueType& x1, ValueType& y1, 105 ValueType& x2, ValueType& y2, 106 ValueType& x3, ValueType& y3) const noexcept 107 { 108 auto oldX1 = x1, oldX2 = x2, oldX3 = x3; 109 x1 = static_cast<ValueType> (mat00 * oldX1 + mat01 * y1 + mat02); 110 y1 = static_cast<ValueType> (mat10 * oldX1 + mat11 * y1 + mat12); 111 x2 = static_cast<ValueType> (mat00 * oldX2 + mat01 * y2 + mat02); 112 y2 = static_cast<ValueType> (mat10 * oldX2 + mat11 * y2 + mat12); 113 x3 = static_cast<ValueType> (mat00 * oldX3 + mat01 * y3 + mat02); 114 y3 = static_cast<ValueType> (mat10 * oldX3 + mat11 * y3 + mat12); 115 } 116 117 //============================================================================== 118 /** Returns a new transform which is the same as this one followed by a translation. */ 119 AffineTransform translated (float deltaX, 120 float deltaY) const noexcept; 121 122 /** Returns a new transform which is the same as this one followed by a translation. */ 123 template <typename PointType> translated(PointType delta)124 AffineTransform translated (PointType delta) const noexcept 125 { 126 return translated ((float) delta.x, (float) delta.y); 127 } 128 129 /** Returns a new transform which is a translation. */ 130 static AffineTransform translation (float deltaX, 131 float deltaY) noexcept; 132 133 /** Returns a new transform which is a translation. */ 134 template <typename PointType> translation(PointType delta)135 static AffineTransform translation (PointType delta) noexcept 136 { 137 return translation ((float) delta.x, (float) delta.y); 138 } 139 140 /** Returns a copy of this transform with the specified translation matrix values. */ 141 AffineTransform withAbsoluteTranslation (float translationX, 142 float translationY) const noexcept; 143 144 /** Returns a transform which is the same as this one followed by a rotation. 145 146 The rotation is specified by a number of radians to rotate clockwise, centred around 147 the origin (0, 0). 148 */ 149 AffineTransform rotated (float angleInRadians) const noexcept; 150 151 /** Returns a transform which is the same as this one followed by a rotation about a given point. 152 153 The rotation is specified by a number of radians to rotate clockwise, centred around 154 the coordinates passed in. 155 */ 156 AffineTransform rotated (float angleInRadians, 157 float pivotX, 158 float pivotY) const noexcept; 159 160 /** Returns a new transform which is a rotation about (0, 0). */ 161 static AffineTransform rotation (float angleInRadians) noexcept; 162 163 /** Returns a new transform which is a rotation about a given point. */ 164 static AffineTransform rotation (float angleInRadians, 165 float pivotX, 166 float pivotY) noexcept; 167 168 /** Returns a transform which is the same as this one followed by a re-scaling. 169 The scaling is centred around the origin (0, 0). 170 */ 171 AffineTransform scaled (float factorX, 172 float factorY) const noexcept; 173 174 /** Returns a transform which is the same as this one followed by a re-scaling. 175 The scaling is centred around the origin (0, 0). 176 */ 177 AffineTransform scaled (float factor) const noexcept; 178 179 /** Returns a transform which is the same as this one followed by a re-scaling. 180 The scaling is centred around the origin provided. 181 */ 182 AffineTransform scaled (float factorX, float factorY, 183 float pivotX, float pivotY) const noexcept; 184 185 /** Returns a new transform which is a re-scale about the origin. */ 186 static AffineTransform scale (float factorX, 187 float factorY) noexcept; 188 189 /** Returns a new transform which is a re-scale about the origin. */ 190 static AffineTransform scale (float factor) noexcept; 191 192 /** Returns a new transform which is a re-scale centred around the point provided. */ 193 static AffineTransform scale (float factorX, float factorY, 194 float pivotX, float pivotY) noexcept; 195 196 /** Returns a transform which is the same as this one followed by a shear. 197 The shear is centred around the origin (0, 0). 198 */ 199 AffineTransform sheared (float shearX, float shearY) const noexcept; 200 201 /** Returns a shear transform, centred around the origin (0, 0). */ 202 static AffineTransform shear (float shearX, float shearY) noexcept; 203 204 /** Returns a transform that will flip coordinates vertically within a window of the given height. 205 This is handy for converting between upside-down coordinate systems such as OpenGL or CoreGraphics. 206 */ 207 static AffineTransform verticalFlip (float height) noexcept; 208 209 /** Returns a matrix which is the inverse operation of this one. 210 211 Some matrices don't have an inverse - in this case, the method will just return 212 an identity transform. 213 */ 214 AffineTransform inverted() const noexcept; 215 216 /** Returns the transform that will map three known points onto three coordinates 217 that are supplied. 218 219 This returns the transform that will transform (0, 0) into (x00, y00), 220 (1, 0) to (x10, y10), and (0, 1) to (x01, y01). 221 */ 222 static AffineTransform fromTargetPoints (float x00, float y00, 223 float x10, float y10, 224 float x01, float y01) noexcept; 225 226 /** Returns the transform that will map three specified points onto three target points. */ 227 static AffineTransform fromTargetPoints (float sourceX1, float sourceY1, float targetX1, float targetY1, 228 float sourceX2, float sourceY2, float targetX2, float targetY2, 229 float sourceX3, float sourceY3, float targetX3, float targetY3) noexcept; 230 231 /** Returns the transform that will map three specified points onto three target points. */ 232 template <typename PointType> fromTargetPoints(PointType source1,PointType target1,PointType source2,PointType target2,PointType source3,PointType target3)233 static AffineTransform fromTargetPoints (PointType source1, PointType target1, 234 PointType source2, PointType target2, 235 PointType source3, PointType target3) noexcept 236 { 237 return fromTargetPoints (source1.x, source1.y, target1.x, target1.y, 238 source2.x, source2.y, target2.x, target2.y, 239 source3.x, source3.y, target3.x, target3.y); 240 } 241 242 //============================================================================== 243 /** Returns the result of concatenating another transformation after this one. */ 244 AffineTransform followedBy (const AffineTransform& other) const noexcept; 245 246 /** Returns true if this transform has no effect on points. */ 247 bool isIdentity() const noexcept; 248 249 /** Returns true if this transform maps to a singularity - i.e. if it has no inverse. */ 250 bool isSingularity() const noexcept; 251 252 /** Returns true if the transform only translates, and doesn't scale or rotate the 253 points. */ 254 bool isOnlyTranslation() const noexcept; 255 256 /** If this transform is only a translation, this returns the X offset. 257 @see isOnlyTranslation 258 */ getTranslationX()259 float getTranslationX() const noexcept { return mat02; } 260 261 /** If this transform is only a translation, this returns the X offset. 262 @see isOnlyTranslation 263 */ getTranslationY()264 float getTranslationY() const noexcept { return mat12; } 265 266 /** Returns the determinant of the transform. */ 267 float getDeterminant() const noexcept; 268 269 /** This method has been deprecated. 270 271 You can calculate the scale factor using: 272 @code 273 std::sqrt (std::abs (AffineTransform::getDeterminant())) 274 @endcode 275 276 This method produces incorrect values for transforms containing rotations. 277 278 Returns the approximate scale factor by which lengths will be transformed. 279 Obviously a length may be scaled by entirely different amounts depending on its 280 direction, so this is only appropriate as a rough guide. 281 */ 282 JUCE_DEPRECATED (float getScaleFactor() const noexcept); 283 284 /* A ready-to-use identity transform - now deprecated. 285 @deprecated If you need an identity transform, just use AffineTransform() or {}. 286 */ JUCE_DEPRECATED_STATIC(static const AffineTransform identity;)287 JUCE_DEPRECATED_STATIC (static const AffineTransform identity;) 288 289 //============================================================================== 290 /* The transform matrix is: 291 292 (mat00 mat01 mat02) 293 (mat10 mat11 mat12) 294 ( 0 0 1 ) 295 */ 296 float mat00 { 1.0f }, mat01 { 0.0f }, mat02 { 0.0f }; 297 float mat10 { 0.0f }, mat11 { 1.0f }, mat12 { 0.0f }; 298 }; 299 300 } // namespace juce 301