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 package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
17 
18 class CubicEasing extends Easing {
19     float mType = 0;
20     float mX1 = 0f;
21     float mY1 = 0f;
22     float mX2 = 0f;
23     float mY2 = 0f;
24 
25     private static final float[] STANDARD = {0.4f, 0.0f, 0.2f, 1f};
26     private static final float[] ACCELERATE = {0.4f, 0.05f, 0.8f, 0.7f};
27     private static final float[] DECELERATE = {0.0f, 0.0f, 0.2f, 0.95f};
28     private static final float[] LINEAR = {1f, 1f, 0f, 0f};
29     private static final float[] ANTICIPATE = {0.36f, 0f, 0.66f, -0.56f};
30     private static final float[] OVERSHOOT = {0.34f, 1.56f, 0.64f, 1f};
31 
CubicEasing(int type)32     CubicEasing(int type) {
33         mType = type;
34         config(type);
35     }
36 
CubicEasing(float x1, float y1, float x2, float y2)37     CubicEasing(float x1, float y1, float x2, float y2) {
38         setup(x1, y1, x2, y2);
39     }
40 
config(int type)41     public void config(int type) {
42 
43         switch (type) {
44             case CUBIC_STANDARD:
45                 setup(STANDARD);
46                 break;
47             case CUBIC_ACCELERATE:
48                 setup(ACCELERATE);
49                 break;
50             case CUBIC_DECELERATE:
51                 setup(DECELERATE);
52                 break;
53             case CUBIC_LINEAR:
54                 setup(LINEAR);
55                 break;
56             case CUBIC_ANTICIPATE:
57                 setup(ANTICIPATE);
58                 break;
59             case CUBIC_OVERSHOOT:
60                 setup(OVERSHOOT);
61                 break;
62         }
63         mType = type;
64     }
65 
setup(float[] values)66     void setup(float[] values) {
67         setup(values[0], values[1], values[2], values[3]);
68     }
69 
setup(float x1, float y1, float x2, float y2)70     void setup(float x1, float y1, float x2, float y2) {
71         mX1 = x1;
72         mY1 = y1;
73         mX2 = x2;
74         mY2 = y2;
75     }
76 
getX(float t)77     private float getX(float t) {
78         float t1 = 1 - t;
79         // no need for because start at 0,0 float f0 = (1 - t) * (1 - t) * (1 - t)
80         float f1 = 3 * t1 * t1 * t;
81         float f2 = 3 * t1 * t * t;
82         float f3 = t * t * t;
83         return mX1 * f1 + mX2 * f2 + f3;
84     }
85 
getY(float t)86     private float getY(float t) {
87         float t1 = 1 - t;
88         // no need for testing because start at 0,0 float f0 = (1 - t) * (1 - t) * (1 - t)
89         float f1 = 3 * t1 * t1 * t;
90         float f2 = 3 * t1 * t * t;
91         float f3 = t * t * t;
92         return mY1 * f1 + mY2 * f2 + f3;
93     }
94 
getDiffX(float t)95     private float getDiffX(float t) {
96         float t1 = 1 - t;
97         return 3 * t1 * t1 * mX1 + 6 * t1 * t * (mX2 - mX1) + 3 * t * t * (1 - mX2);
98     }
99 
getDiffY(float t)100     private float getDiffY(float t) {
101         float t1 = 1 - t;
102         return 3 * t1 * t1 * mY1 + 6 * t1 * t * (mY2 - mY1) + 3 * t * t * (1 - mY2);
103     }
104 
105     /**
106      * binary search for the region and linear interpolate the answer
107      */
getDiff(float x)108     public float getDiff(float x) {
109         float t = 0.5f;
110         float range = 0.5f;
111         while (range > D_ERROR) {
112             float tx = getX(t);
113             range *= 0.5;
114             if (tx < x) {
115                 t += range;
116             } else {
117                 t -= range;
118             }
119         }
120         float x1 = getX(t - range);
121         float x2 = getX(t + range);
122         float y1 = getY(t - range);
123         float y2 = getY(t + range);
124         return (y2 - y1) / (x2 - x1);
125     }
126 
127     /**
128      * binary search for the region and linear interpolate the answer
129      */
get(float x)130     public float get(float x) {
131         if (x <= 0.0f) {
132             return 0f;
133         }
134         if (x >= 1.0f) {
135             return 1.0f;
136         }
137         float t = 0.5f;
138         float range = 0.5f;
139         while (range > ERROR) {
140             float tx = getX(t);
141             range *= 0.5f;
142             if (tx < x) {
143                 t += range;
144             } else {
145                 t -= range;
146             }
147         }
148         float x1 = getX(t - range);
149         float x2 = getX(t + range);
150         float y1 = getY(t - range);
151         float y2 = getY(t + range);
152         return (y2 - y1) * (x - x1) / (x2 - x1) + y1;
153     }
154 
155     private static final float ERROR = 0.01f;
156     private static final float D_ERROR = 0.0001f;
157 }
158