1 /*
2  * Copyright (C) 2021 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 com.android.car.carlauncher.displayarea;
18 
19 /**
20  * Represents a cubic bezier curve in one dimension. Returns out-of-bounds t values using a straight
21  * line instead of continuing the curve into infinity, because this is useful for bezier animations,
22  * and beziers for drawing are rarely allowed to use these values.
23  * <p>
24  * For reference material on bezier curves, try http://pomax.github.io/bezierinfo/
25  */
26 public final class CarBezierFunction {
27     // Control points.
28     private final double mA;
29     private final double mB;
30     private final double mC;
31     private final double mD;
32 
33     /**
34      * Constructs bezier curve with the given control points.
35      */
CarBezierFunction(double a, double b, double c, double d)36     CarBezierFunction(double a, double b, double c, double d) {
37         this.mA = a;
38         this.mB = b;
39         this.mC = c;
40         this.mD = d;
41     }
42 
43     /**
44      * Constructs bezier curve that's just a solitary point. This is a degenerate curve when trying
45      * to
46      * draw using a bezier curve, but useful when using bezier curves as animations.
47      */
CarBezierFunction(double value)48     CarBezierFunction(double value) {
49         mA = mB = mC = mD = value;
50     }
51 
52     /**
53      * Gets the bezier value at given t for the bezier defined by control points {@code a, b, c, d}.
54      * The bezier function is defined for {@code t} in [0, 1], and the area outside this range is
55      * replaced with a linear function.
56      */
getValue(double t, double a, double b, double c, double d)57     public static double getValue(double t, double a, double b, double c, double d) {
58         // Treat outside bounds as linear.
59         if (t > 1) {
60             return d + getDerivative(1, a, b, c, d) * (t - 1);
61         }
62         if (t < 0) {
63             return a + getDerivative(0, a, b, c, d) * t;
64         }
65         // Normal bezier equation.
66         return cube(1 - t) * a + 3 * square(1 - t) * t * b + 3 * (1 - t) * square(t) * c + cube(t)
67                 * d;
68     }
69 
70     /**
71      * Gets the bezier value at given {@code t}. The bezier function is defined for {@code t} in
72      * [0, 1], and the area outside this range is replaced with a linear function.
73      */
getValue(double t)74     public double getValue(double t) {
75         return getValue(t, mA, mB, mC, mD);
76     }
77 
78     /**
79      * Gets the derivative of the bezier value at given {@code t}. Since {@link #getValue} becomes
80      * linear outside the range [0, 1], the derivative outside this range is constant.
81      */
getDerivative(double t, double a, double b, double c, double d)82     public static double getDerivative(double t, double a, double b, double c, double d) {
83         // Clamp to [0, 1] to make values linear outside this range.
84         t = Math.max(0, t);
85         t = Math.min(1, t);
86         return 3 * square(1 - t) * (b - a) + 3 * 2 * (1 - t) * t * (c - b) + 3 * square(t) * (d
87                 - c);
88     }
89 
90     /**
91      * Gets derivative of bezier value at given t for the bezier defined by control points a, b, c,
92      * d.
93      * Since {@link #getValue} becomes linear outside the range [0, 1], the derivative outside this
94      * range is constant.
95      */
getDerivative(double t)96     public double getDerivative(double t) {
97         return getDerivative(t, mA, mB, mC, mD);
98     }
99 
100     /**
101      * Squares x. Math.pow() is significantly slower than multiplying directly for small integer
102      * exponents.
103      */
square(double x)104     private static double square(double x) {
105         return x * x;
106     }
107 
108     /**
109      * Cubes x. Math.pow() is significantly slower than multiplying directly for small integer
110      * exponents.
111      */
cube(double x)112     private static double cube(double x) {
113         return x * x * x;
114     }
115 }
116