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