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