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