1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.ink.geometry 18 19 import androidx.annotation.RestrictTo 20 import androidx.annotation.Size 21 import kotlin.math.cos 22 import kotlin.math.sin 23 24 /** 25 * An affine transformation in the plane. The transformation can be thought of as a 3x3 matrix: 26 * ``` 27 * ⎡m00 m10 m20⎤ 28 * ⎢m01 m11 m21⎥ 29 * ⎣ 0 0 1 ⎦ 30 * ``` 31 * 32 * Applying the transformation can be thought of as a matrix multiplication, with the 33 * to-be-transformed point represented as a column vector with an extra 1: 34 * ``` 35 * ⎡m00 m10 m20⎤ ⎡x⎤ ⎡m00*x + m10*y + m20⎤ 36 * ⎢m01 m11 m21⎥ * ⎢y⎥ = ⎢m01*x + m11*y + m21⎥ 37 * ⎣ 0 0 1 ⎦ ⎣1⎦ ⎣ 1 ⎦ 38 * ``` 39 * 40 * Transformations are composed via multiplication. Multiplication is not commutative (i.e. A*B != 41 * B*A), and the left-hand transformation is composed "after" the right hand transformation. E.g., 42 * if you have: 43 * ``` 44 * val rotate = ImmutableAffineTransform.rotate(Angle.degreesToRadians(45)) 45 * val translate = ImmutableAffineTransform.translate(Vec(10, 0)) 46 * ``` 47 * 48 * then `rotate * translate` first translates 10 units in the positive x-direction, then rotates 45° 49 * about the origin. 50 * 51 * See [ImmutableAffineTransform] for an immutable alternative to this class. 52 * 53 * @constructor Constructs this transform with 6 float values, starting with the top left corner of 54 * the matrix and proceeding in row-major order. Prefer to create this object with functions that 55 * apply specific transform operations, such as [populateFromScale] or [populateFromRotate], 56 * rather than directly passing in the actual numeric values of this transform. This constructor 57 * is useful for when the values are needed to be provided all at once, for example for 58 * serialization. To access these values in the same order as they are passed in here, use 59 * [AffineTransform.getValues]. To construct this object using an array as input, there is another 60 * public constructor for that. 61 */ 62 public class MutableAffineTransform 63 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 64 public constructor( 65 @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // NonPublicApi 66 @set:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // NonPublicApi 67 override var m00: Float, 68 @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // NonPublicApi 69 @set:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // NonPublicApi 70 override var m10: Float, 71 @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // NonPublicApi 72 @set:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // NonPublicApi 73 override var m20: Float, 74 @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // NonPublicApi 75 @set:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // NonPublicApi 76 override var m01: Float, 77 @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // NonPublicApi 78 @set:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // NonPublicApi 79 override var m11: Float, 80 @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // NonPublicApi 81 @set:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // NonPublicApi 82 override var m21: Float, 83 ) : AffineTransform() { 84 85 /** 86 * Constructs an identity [MutableAffineTransform]: 87 * ``` 88 * ⎡1 0 0⎤ 89 * ⎢0 1 0⎥ 90 * ⎣0 0 1⎦ 91 * ``` 92 * 93 * This is useful when pre-allocating a scratch instance to be filled later. 94 */ 95 public constructor() : this(1f, 0f, 0f, 0f, 1f, 0f) 96 97 /** 98 * Populates this transform with the given values, starting with the top left corner of the 99 * matrix and proceeding in row-major order. 100 * 101 * Prefer to modify this object with functions that apply specific transform operations, such as 102 * [populateFromScale] or [populateFromRotate], rather than directly setting the actual numeric 103 * values of this transform. This function is useful for when the values are needed to be 104 * provided in bulk, for example for serialization. 105 * 106 * To access these values in the same order as they are set here, use 107 * [AffineTransform.getValues]. 108 */ setValuesnull109 public fun setValues(m00: Float, m10: Float, m20: Float, m01: Float, m11: Float, m21: Float) { 110 this.m00 = m00 111 this.m10 = m10 112 this.m20 = m20 113 this.m01 = m01 114 this.m11 = m11 115 this.m21 = m21 116 } 117 118 /** Like [setValues], but accepts a [FloatArray] instead of individual float values. */ setValuesnull119 public fun setValues(@Size(min = 6) values: FloatArray) { 120 m00 = values[0] 121 m10 = values[1] 122 m20 = values[2] 123 m01 = values[3] 124 m11 = values[4] 125 m21 = values[5] 126 } 127 128 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) asImmutablenull129 override fun asImmutable(): ImmutableAffineTransform = 130 ImmutableAffineTransform(m00, m10, m20, m01, m11, m21) 131 132 /** 133 * Fills this [MutableAffineTransform] with the same values contained in [input]. Returns 134 * [this]. 135 */ 136 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview 137 public fun populateFrom(input: AffineTransform): MutableAffineTransform { 138 m00 = input.m00 139 m10 = input.m10 140 m20 = input.m20 141 m01 = input.m01 142 m11 = input.m11 143 m21 = input.m21 144 return this 145 } 146 147 /** 148 * Fills this [MutableAffineTransform] with an identity transformation, which maps a point to 149 * itself, i.e. it leaves it unchanged. Returns [this]. 150 */ 151 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview populateFromIdentitynull152 public fun populateFromIdentity(): MutableAffineTransform { 153 m00 = 1f 154 m10 = 0f 155 m20 = 0f 156 m01 = 0f 157 m11 = 1f 158 m21 = 0f 159 return this 160 } 161 162 /** 163 * Fills this [MutableAffineTransform] with a transformation that translates by the given 164 * [offset] vector. Returns [this]. 165 */ 166 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview populateFromTranslatenull167 public fun populateFromTranslate(offset: Vec): MutableAffineTransform { 168 m00 = 1f 169 m10 = 0f 170 m20 = offset.x 171 m01 = 0f 172 m11 = 1f 173 m21 = offset.y 174 return this 175 } 176 177 /** 178 * Fills this [MutableAffineTransform] with a transformation that scales in both the x- and 179 * y-direction by the given [scaleFactor], centered about the origin. Returns [this]. 180 */ 181 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview populateFromScalenull182 public fun populateFromScale(scaleFactor: Float): MutableAffineTransform { 183 m00 = scaleFactor 184 m10 = 0f 185 m20 = 0f 186 m01 = 0f 187 m11 = scaleFactor 188 m21 = 0f 189 return this 190 } 191 192 /** 193 * Fills this [MutableAffineTransform] with a transformation that scales in both the x- and 194 * y-direction by the given pair of factors; [xScaleFactor] and [yScaleFactor] respectively, 195 * centered about the origin. Returns [this]. 196 */ 197 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview populateFromScalenull198 public fun populateFromScale(xScaleFactor: Float, yScaleFactor: Float): MutableAffineTransform { 199 m00 = xScaleFactor 200 m10 = 0f 201 m20 = 0f 202 m01 = 0f 203 m11 = yScaleFactor 204 m21 = 0f 205 return this 206 } 207 208 /** 209 * Fills this [MutableAffineTransform] with a transformation that scales in the x-direction by 210 * the given factor, centered about the origin. Returns [this]. 211 */ 212 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview populateFromScaleXnull213 public fun populateFromScaleX(scaleFactor: Float): MutableAffineTransform { 214 m00 = scaleFactor 215 m10 = 0f 216 m20 = 0f 217 m01 = 0f 218 m11 = 1f 219 m21 = 0f 220 return this 221 } 222 223 /** 224 * Fills this [MutableAffineTransform] with a transformation that scales in the y-direction by 225 * the given factor, centered about the origin. Returns [this]. 226 */ 227 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview populateFromScaleYnull228 public fun populateFromScaleY(scaleFactor: Float): MutableAffineTransform { 229 m00 = 1f 230 m10 = 0f 231 m20 = 0f 232 m01 = 0f 233 m11 = scaleFactor 234 m21 = 0f 235 return this 236 } 237 238 /** 239 * Fills this [MutableAffineTransform] with a transformation that shears in the x-direction by 240 * the given factor. Returns [this]. 241 */ 242 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview populateFromShearXnull243 public fun populateFromShearX(shearFactor: Float): MutableAffineTransform { 244 m00 = 1f 245 m10 = shearFactor 246 m20 = 0f 247 m01 = 0f 248 m11 = 1f 249 m21 = 0f 250 return this 251 } 252 253 /** 254 * Fills this [MutableAffineTransform] with a transformation that shears in the y-direction by 255 * the given factor. Returns [this]. 256 */ 257 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview populateFromShearYnull258 public fun populateFromShearY(shearFactor: Float): MutableAffineTransform { 259 m00 = 1f 260 m10 = 0f 261 m20 = 0f 262 m01 = shearFactor 263 m11 = 1f 264 m21 = 0f 265 return this 266 } 267 268 /** 269 * Fills this [MutableAffineTransform] with a transformation that rotates by the given angle, 270 * centered about the origin. Returns [this]. 271 */ 272 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview populateFromRotatenull273 public fun populateFromRotate( 274 @AngleRadiansFloat angleOfRotation: Float 275 ): MutableAffineTransform { 276 val sin = sin(angleOfRotation) 277 val cos = cos(angleOfRotation) 278 m00 = cos 279 m10 = -sin 280 m20 = 0f 281 m01 = sin 282 m11 = cos 283 m21 = 0f 284 return this 285 } 286 287 /** 288 * Component-wise equality operator for [MutableAffineTransform]. 289 * 290 * Due to the propagation floating point precision errors, operations that may be equivalent 291 * over the real numbers are not always equivalent for floats, and might return false for 292 * [equals] in some cases. 293 */ equalsnull294 override fun equals(other: Any?): Boolean = 295 other === this || (other is AffineTransform && areEquivalent(this, other)) 296 297 // NOMUTANTS -- not testing exact hashCode values, just that equality implies same hashCode 298 override fun hashCode(): Int = hash(this) 299 300 override fun toString(): String = "Mutable${string(this)}" 301 } 302