1987ee64612e2510004fdf08536746c87234d01c1Paul Rohde/* 2987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * Copyright (C) 2014 The Android Open Source Project 3987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * 4987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * Licensed under the Apache License, Version 2.0 (the "License"); 5987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * you may not use this file except in compliance with the License. 6987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * You may obtain a copy of the License at 7987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * 8987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * http://www.apache.org/licenses/LICENSE-2.0 9987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * 10987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * Unless required by applicable law or agreed to in writing, software 11987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * distributed under the License is distributed on an "AS IS" BASIS, 12987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * See the License for the specific language governing permissions and 14987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * limitations under the License. 15987ee64612e2510004fdf08536746c87234d01c1Paul Rohde */ 16987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 17987ee64612e2510004fdf08536746c87234d01c1Paul Rohdepackage com.android.camera.ui.motion; 18987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 19987ee64612e2510004fdf08536746c87234d01c1Paul Rohde/** 20987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * This represents is a precomputed cubic bezier curve starting at (0,0) and 21987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * going to (1,1) with two configurable control points. Once the instance is 22987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * created, the control points cannot be modified. 23987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * 24987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * Generally, this will be used for computing timing curves for with control 25987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * points where an x value will be provide from 0.0 - 1.0, and the y value will 26987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * be solved for where y is used as the timing value in some linear 27987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * interpolation of a value. 28987ee64612e2510004fdf08536746c87234d01c1Paul Rohde */ 29987ee64612e2510004fdf08536746c87234d01c1Paul Rohdepublic class UnitBezier implements UnitCurve { 30987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 31987ee64612e2510004fdf08536746c87234d01c1Paul Rohde private static final float EPSILON = 1e-6f; 32987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 33987ee64612e2510004fdf08536746c87234d01c1Paul Rohde private final DerivableFloatFn mXFn; 34987ee64612e2510004fdf08536746c87234d01c1Paul Rohde private final DerivableFloatFn mYFn; 35987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 36987ee64612e2510004fdf08536746c87234d01c1Paul Rohde /** 37987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * Build and pre-compute a unit bezier. This assumes a starting point of 38987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * (0, 0) and end point of (1.0, 1.0). 39987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * 40987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * @param c0x control point x value for p0 41987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * @param c0y control point y value for p0 42987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * @param c1x control point x value for p1 43987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * @param c1y control point y value for p1 44987ee64612e2510004fdf08536746c87234d01c1Paul Rohde */ 45987ee64612e2510004fdf08536746c87234d01c1Paul Rohde public UnitBezier(float c0x, float c0y, float c1x, float c1y) { 46987ee64612e2510004fdf08536746c87234d01c1Paul Rohde mXFn = new CubicBezierFn(c0x, c1x); 47987ee64612e2510004fdf08536746c87234d01c1Paul Rohde mYFn = new CubicBezierFn(c0y, c1y); 48987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 49987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 50987ee64612e2510004fdf08536746c87234d01c1Paul Rohde /** 51987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * Given a unit bezier curve find the height of the curve at t (which is 52987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * internally represented as the xAxis). 53987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * 54987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * @param t the x position between 0 and 1 to solve for y. 55987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * @return the closest approximate height of the curve at x. 56987ee64612e2510004fdf08536746c87234d01c1Paul Rohde */ 57987ee64612e2510004fdf08536746c87234d01c1Paul Rohde @Override 58987ee64612e2510004fdf08536746c87234d01c1Paul Rohde public float valueAt(float t) { 59987ee64612e2510004fdf08536746c87234d01c1Paul Rohde return mYFn.value(solve(t, mXFn)); 60987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 61987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 62987ee64612e2510004fdf08536746c87234d01c1Paul Rohde /** 63987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * Given a unit bezier curve find a value along the x axis such that 64987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * valueAt(result) produces the input value. 65987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * 66987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * @param value the y position between 0 and 1 to solve for x 67987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * @return the closest approximate input that will produce value when provided 68987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * to the valueAt function. 69987ee64612e2510004fdf08536746c87234d01c1Paul Rohde */ 70987ee64612e2510004fdf08536746c87234d01c1Paul Rohde @Override 71987ee64612e2510004fdf08536746c87234d01c1Paul Rohde public float tAt(float value) { 72987ee64612e2510004fdf08536746c87234d01c1Paul Rohde return mXFn.value(solve(value, mYFn)); 73987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 74987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 75987ee64612e2510004fdf08536746c87234d01c1Paul Rohde private float solve(float target, DerivableFloatFn fn) { 76987ee64612e2510004fdf08536746c87234d01c1Paul Rohde // For a linear fn, t = value. This makes value a good starting guess. 77987ee64612e2510004fdf08536746c87234d01c1Paul Rohde float input = target; 78987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 79987ee64612e2510004fdf08536746c87234d01c1Paul Rohde // Newton's method (Faster than bisection) 80987ee64612e2510004fdf08536746c87234d01c1Paul Rohde for (int i = 0; i < 8; i++) { 81987ee64612e2510004fdf08536746c87234d01c1Paul Rohde float value = fn.value(input) - target; 82987ee64612e2510004fdf08536746c87234d01c1Paul Rohde if (Math.abs(value) < EPSILON) { 83987ee64612e2510004fdf08536746c87234d01c1Paul Rohde return input; 84987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 85987ee64612e2510004fdf08536746c87234d01c1Paul Rohde float derivative = fn.derivative(input); 86987ee64612e2510004fdf08536746c87234d01c1Paul Rohde if (Math.abs(derivative) < EPSILON) { 87987ee64612e2510004fdf08536746c87234d01c1Paul Rohde break; 88987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 89987ee64612e2510004fdf08536746c87234d01c1Paul Rohde input = input - value / derivative; 90987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 91987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 92987ee64612e2510004fdf08536746c87234d01c1Paul Rohde // Fallback on bi-section 93987ee64612e2510004fdf08536746c87234d01c1Paul Rohde float min = 0.0f; 94987ee64612e2510004fdf08536746c87234d01c1Paul Rohde float max = 1.0f; 95987ee64612e2510004fdf08536746c87234d01c1Paul Rohde input = target; 96987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 97987ee64612e2510004fdf08536746c87234d01c1Paul Rohde if (input < min) { 98987ee64612e2510004fdf08536746c87234d01c1Paul Rohde return min; 99987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 100987ee64612e2510004fdf08536746c87234d01c1Paul Rohde if (input > max) { 101987ee64612e2510004fdf08536746c87234d01c1Paul Rohde return max; 102987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 103987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 104987ee64612e2510004fdf08536746c87234d01c1Paul Rohde while (min < max) { 105987ee64612e2510004fdf08536746c87234d01c1Paul Rohde float value = fn.value(input); 106987ee64612e2510004fdf08536746c87234d01c1Paul Rohde if (Math.abs(value - target) < EPSILON) { 107987ee64612e2510004fdf08536746c87234d01c1Paul Rohde return input; 108987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 109987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 110987ee64612e2510004fdf08536746c87234d01c1Paul Rohde if (target > value) { 111987ee64612e2510004fdf08536746c87234d01c1Paul Rohde min = input; 112987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } else { 113987ee64612e2510004fdf08536746c87234d01c1Paul Rohde max = input; 114987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 115987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 116987ee64612e2510004fdf08536746c87234d01c1Paul Rohde input = (max - min) * .5f + min; 117987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 118987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 119987ee64612e2510004fdf08536746c87234d01c1Paul Rohde // Give up, return the closest match we got too. 120987ee64612e2510004fdf08536746c87234d01c1Paul Rohde return input; 121987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 122987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 123987ee64612e2510004fdf08536746c87234d01c1Paul Rohde private interface DerivableFloatFn { 124987ee64612e2510004fdf08536746c87234d01c1Paul Rohde float value(float x); 125987ee64612e2510004fdf08536746c87234d01c1Paul Rohde float derivative(float x); 126987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 127987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 128987ee64612e2510004fdf08536746c87234d01c1Paul Rohde /** 129987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * Precomputed constants for a given set of control points along a given 130987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * cubic bezier axis. 131987ee64612e2510004fdf08536746c87234d01c1Paul Rohde */ 132987ee64612e2510004fdf08536746c87234d01c1Paul Rohde private static class CubicBezierFn implements DerivableFloatFn { 133987ee64612e2510004fdf08536746c87234d01c1Paul Rohde private final float c; 134987ee64612e2510004fdf08536746c87234d01c1Paul Rohde private final float a; 135987ee64612e2510004fdf08536746c87234d01c1Paul Rohde private final float b; 136987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 137987ee64612e2510004fdf08536746c87234d01c1Paul Rohde /** 138987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * Build and pre-compute a single axis for a unit bezier. This assumes p0 139987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * is 0 and p1 is 1. 140987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * 141987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * @param c0 start control point. 142987ee64612e2510004fdf08536746c87234d01c1Paul Rohde * @param c1 end control point. 143987ee64612e2510004fdf08536746c87234d01c1Paul Rohde */ 144987ee64612e2510004fdf08536746c87234d01c1Paul Rohde public CubicBezierFn(float c0, float c1) { 145987ee64612e2510004fdf08536746c87234d01c1Paul Rohde c = 3.0f * c0; 146987ee64612e2510004fdf08536746c87234d01c1Paul Rohde b = 3.0f * (c1 - c0) - c; 147987ee64612e2510004fdf08536746c87234d01c1Paul Rohde a = 1.0f - c - b; 148987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 149987ee64612e2510004fdf08536746c87234d01c1Paul Rohde 150987ee64612e2510004fdf08536746c87234d01c1Paul Rohde public float value(float x) { 151987ee64612e2510004fdf08536746c87234d01c1Paul Rohde return ((a * x + b) * x + c) * x; 152987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 153987ee64612e2510004fdf08536746c87234d01c1Paul Rohde public float derivative(float x) { 154987ee64612e2510004fdf08536746c87234d01c1Paul Rohde return (3.0f * a * x + 2.0f * b) * x + c; 155987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 156987ee64612e2510004fdf08536746c87234d01c1Paul Rohde } 157987ee64612e2510004fdf08536746c87234d01c1Paul Rohde} 158