1 /*
2 * Copyright 2019 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.compose.animation.core
18
19 /**
20 * [AnimationVector] class that is the base class of [AnimationVector1D], [AnimationVector2D],
21 * [AnimationVector3D] and [AnimationVector4D]. In order to animate any arbitrary type, it is
22 * required to provide a [TwoWayConverter] that defines how to convert that arbitrary type T to an
23 * [AnimationVector], and vice versa. Depending on how many dimensions this type T has, it may need
24 * to be converted to any of the subclasses of [AnimationVector]. For example, a position based
25 * object should be converted to [AnimationVector2D], whereas an object that describes rectangle
26 * bounds should convert to [AnimationVector4D].
27 */
28 public sealed class AnimationVector {
resetnull29 internal abstract fun reset()
30
31 internal abstract fun newVector(): AnimationVector
32
33 internal abstract operator fun get(index: Int): Float
34
35 internal abstract operator fun set(index: Int, value: Float)
36
37 internal abstract val size: Int
38 }
39
40 /**
41 * Factory method to create an [AnimationVector1D]
42 *
43 * @param v1 value to set on the value field of [AnimationVector1D]
44 */
45 public fun AnimationVector(v1: Float): AnimationVector1D = AnimationVector1D(v1)
46
47 /**
48 * Factory method to create an [AnimationVector2D]
49 *
50 * @param v1 value to set on the first dimension
51 * @param v2 value to set on the second dimension
52 */
53 public fun AnimationVector(v1: Float, v2: Float): AnimationVector2D = AnimationVector2D(v1, v2)
54
55 /**
56 * Factory method to create an [AnimationVector3D]
57 *
58 * @param v1 value to set on the first dimension
59 * @param v2 value to set on the second dimension
60 * @param v3 value to set on the third dimension
61 */
62 public fun AnimationVector(v1: Float, v2: Float, v3: Float): AnimationVector3D =
63 AnimationVector3D(v1, v2, v3)
64
65 /**
66 * Factory method to create an [AnimationVector4D]
67 *
68 * @param v1 value to set on the first dimension
69 * @param v2 value to set on the second dimension
70 * @param v3 value to set on the third dimension
71 * @param v4 value to set on the fourth dimension
72 */
73 public fun AnimationVector(v1: Float, v2: Float, v3: Float, v4: Float): AnimationVector4D =
74 AnimationVector4D(v1, v2, v3, v4)
75
76 internal fun <T : AnimationVector> T.newInstance(): T {
77 @Suppress("UNCHECKED_CAST") return this.newVector() as T
78 }
79
copynull80 internal fun <T : AnimationVector> T.copy(): T {
81 val newVector = newInstance()
82 for (i in 0 until newVector.size) {
83 newVector[i] = this[i]
84 }
85 return newVector
86 }
87
copyFromnull88 internal fun <T : AnimationVector> T.copyFrom(source: T) {
89 for (i in 0 until size) {
90 this[i] = source[i]
91 }
92 }
93
94 /**
95 * This class defines a 1D vector. It contains only one Float value that is initialized in the
96 * constructor.
97 *
98 * @param initVal initial value to set the [value] field to.
99 */
100 public class AnimationVector1D(initVal: Float) : AnimationVector() {
101 /** This field holds the only Float value in this [AnimationVector1D] object. */
102 public var value: Float = initVal
103 internal set
104
105 // internal
resetnull106 override fun reset() {
107 value = 0f
108 }
109
newVectornull110 override fun newVector(): AnimationVector1D = AnimationVector1D(0f)
111
112 override fun get(index: Int): Float {
113 if (index == 0) {
114 return value
115 } else {
116 return 0f
117 }
118 }
119
setnull120 override fun set(index: Int, value: Float) {
121 if (index == 0) {
122 this.value = value
123 }
124 }
125
126 override val size: Int = 1
127
toStringnull128 override fun toString(): String {
129 return "AnimationVector1D: value = $value"
130 }
131
equalsnull132 override fun equals(other: Any?): Boolean = other is AnimationVector1D && other.value == value
133
134 override fun hashCode(): Int = value.hashCode()
135 }
136
137 /**
138 * This class defines a 2D vector that contains two Float values for the two dimensions.
139 *
140 * @param v1 initial value to set on the first dimension
141 * @param v2 initial value to set on the second dimension
142 */
143 public class AnimationVector2D(v1: Float, v2: Float) : AnimationVector() {
144 /** Float value field for the first dimension of the 2D vector. */
145 public var v1: Float = v1
146 internal set
147
148 /** Float value field for the second dimension of the 2D vector. */
149 public var v2: Float = v2
150 internal set
151
152 // internal
153 override fun reset() {
154 v1 = 0f
155 v2 = 0f
156 }
157
158 override fun newVector(): AnimationVector2D = AnimationVector2D(0f, 0f)
159
160 override fun get(index: Int): Float {
161 return when (index) {
162 0 -> v1
163 1 -> v2
164 else -> 0f
165 }
166 }
167
168 override fun set(index: Int, value: Float) {
169 when (index) {
170 0 -> v1 = value
171 1 -> v2 = value
172 }
173 }
174
175 override val size: Int = 2
176
177 override fun toString(): String {
178 return "AnimationVector2D: v1 = $v1, v2 = $v2"
179 }
180
181 override fun equals(other: Any?): Boolean =
182 other is AnimationVector2D && other.v1 == v1 && other.v2 == v2
183
184 override fun hashCode(): Int = v1.hashCode() * 31 + v2.hashCode()
185 }
186
187 /**
188 * This class defines a 3D vector that contains three Float value fields for the three dimensions.
189 *
190 * @param v1 initial value to set on the first dimension
191 * @param v2 initial value to set on the second dimension
192 * @param v3 initial value to set on the third dimension
193 */
194 public class AnimationVector3D(v1: Float, v2: Float, v3: Float) : AnimationVector() {
195 // Internally mutable, so we don't have to create a number of small objects per anim frame
196 /** Float value field for the first dimension of the 3D vector. */
197 public var v1: Float = v1
198 internal set
199
200 /** Float value field for the second dimension of the 3D vector. */
201 public var v2: Float = v2
202 internal set
203
204 /** Float value field for the third dimension of the 3D vector. */
205 public var v3: Float = v3
206 internal set
207
208 // internal
resetnull209 override fun reset() {
210 v1 = 0f
211 v2 = 0f
212 v3 = 0f
213 }
214
newVectornull215 override fun newVector(): AnimationVector3D = AnimationVector3D(0f, 0f, 0f)
216
217 override fun get(index: Int): Float {
218 return when (index) {
219 0 -> v1
220 1 -> v2
221 2 -> v3
222 else -> 0f
223 }
224 }
225
setnull226 override fun set(index: Int, value: Float) {
227 when (index) {
228 0 -> v1 = value
229 1 -> v2 = value
230 2 -> v3 = value
231 }
232 }
233
234 override val size: Int = 3
235
toStringnull236 override fun toString(): String {
237 return "AnimationVector3D: v1 = $v1, v2 = $v2, v3 = $v3"
238 }
239
equalsnull240 override fun equals(other: Any?): Boolean =
241 other is AnimationVector3D && other.v1 == v1 && other.v2 == v2 && other.v3 == v3
242
243 override fun hashCode(): Int = (v1.hashCode() * 31 + v2.hashCode()) * 31 + v3.hashCode()
244 }
245
246 /**
247 * This class defines a 4D vector that contains four Float fields for its four dimensions.
248 *
249 * @param v1 initial value to set on the first dimension
250 * @param v2 initial value to set on the second dimension
251 * @param v3 initial value to set on the third dimension
252 * @param v4 initial value to set on the fourth dimension
253 */
254 public class AnimationVector4D(v1: Float, v2: Float, v3: Float, v4: Float) : AnimationVector() {
255 // Internally mutable, so we don't have to create a number of small objects per anim frame
256 /** Float value field for the first dimension of the 4D vector. */
257 public var v1: Float = v1
258 internal set
259
260 /** Float value field for the second dimension of the 4D vector. */
261 public var v2: Float = v2
262 internal set
263
264 /** Float value field for the third dimension of the 4D vector. */
265 public var v3: Float = v3
266 internal set
267
268 /** Float value field for the fourth dimension of the 4D vector. */
269 public var v4: Float = v4
270 internal set
271
272 override fun reset() {
273 v1 = 0f
274 v2 = 0f
275 v3 = 0f
276 v4 = 0f
277 }
278
279 override fun newVector(): AnimationVector4D = AnimationVector4D(0f, 0f, 0f, 0f)
280
281 override fun get(index: Int): Float {
282 return when (index) {
283 0 -> v1
284 1 -> v2
285 2 -> v3
286 3 -> v4
287 else -> 0f
288 }
289 }
290
291 override fun set(index: Int, value: Float) {
292 when (index) {
293 0 -> v1 = value
294 1 -> v2 = value
295 2 -> v3 = value
296 3 -> v4 = value
297 }
298 }
299
300 override val size: Int = 4
301
302 override fun toString(): String {
303 return "AnimationVector4D: v1 = $v1, v2 = $v2, v3 = $v3, v4 = $v4"
304 }
305
306 override fun equals(other: Any?): Boolean =
307 other is AnimationVector4D &&
308 other.v1 == v1 &&
309 other.v2 == v2 &&
310 other.v3 == v3 &&
311 other.v4 == v4
312
313 override fun hashCode(): Int =
314 ((v1.hashCode() * 31 + v2.hashCode()) * 31 + v3.hashCode()) * 31 + v4.hashCode()
315 }
316