From d8420e3702c5504e45a51fd29642167b4ab66312 Mon Sep 17 00:00:00 2001 From: Paul Rohde Date: Fri, 5 Dec 2014 12:17:15 -0800 Subject: Drop new focus indicator into Camera2. * Create a new custom focus view that interacts with physical lens diopter changes. * Replace all occurances of the old focus indicator with the new one. Change-Id: Ia02646ce4d1eb059ecb8a1dfccc15dfc9c167e1b --- src/com/android/camera/ui/motion/DampedSpring.java | 145 +++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 src/com/android/camera/ui/motion/DampedSpring.java (limited to 'src/com/android/camera/ui/motion/DampedSpring.java') diff --git a/src/com/android/camera/ui/motion/DampedSpring.java b/src/com/android/camera/ui/motion/DampedSpring.java new file mode 100644 index 000000000..84cbfa6f8 --- /dev/null +++ b/src/com/android/camera/ui/motion/DampedSpring.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.camera.ui.motion; + +/** + * This models a value after the behavior of a spring. The value tracks the current value, a target + * value, and the current velocity and applies both a directional force and a damping force to the + * value on each update call. + */ +public class DampedSpring { + public static final float DEFAULT_TIME_TO_90_PERCENT_MILLIS = 200.0f; + public static final float DEFAULT_SPRING_STIFFNESS = 3.75f; + public static final float EPSILON = 0.01f; + + private final float mSpringStiffness; + private final float mTimeTo90PercentMs; + + private float mTarget = 0f; + private float mVelocity = 0f; + private float mValue = 0f; + + public DampedSpring() { + this(DEFAULT_TIME_TO_90_PERCENT_MILLIS, DEFAULT_SPRING_STIFFNESS); + } + + public DampedSpring(float timeTo90PercentMs) { + this(timeTo90PercentMs, DEFAULT_SPRING_STIFFNESS); + } + + public DampedSpring(float timeTo90PercentMs, float springStiffness) { + // TODO: Assert timeTo90PercentMs >= 1ms, it might behave badly at low values. + // TODO: Assert springStiffness > 2.0f + + mTimeTo90PercentMs = timeTo90PercentMs; + mSpringStiffness = springStiffness; + + if (springStiffness > timeTo90PercentMs) { + throw new IllegalArgumentException("Creating a spring value with " + + "excessive stiffness will oscillate endlessly."); + } + } + + /** + * @return the current value. + */ + public float getValue() { + return mValue; + } + + /** + * @param value the value to set this instance's current state too. + */ + public void setValue(float value) { + mValue = value; + } + + /** + * @return the current target value. + */ + public float getTarget() { + return mTarget; + } + + /** + * Set a target value. The current value will maintain any existing velocity values and will + * move towards the new target value. To forcibly stopAt the value use the stopAt() method. + * + * @param value the new value to move the current value towards. + */ + public void setTarget(float value) { + mTarget = value; + } + + /** + * Update the current value, moving it towards the actual value over the given + * time delta (in milliseconds) since the last update. This works off of the + * principle of a critically damped spring such that any given current value + * will move elastically towards the target value. The current value maintains + * and applies velocity, acceleration, and a damping force to give a continuous, + * smooth transition towards the target value. + * + * @param dtMs the time since the last update, or zero. + * @return the current value after the update occurs. + */ + public float update(float dtMs) { + float dt = dtMs / mTimeTo90PercentMs; + float dts = dt * mSpringStiffness; + + // If the dts > 1, and the velocity is zero, the force will exceed the + // distance to the target value and it will overshoot the value, causing + // weird behavior and unintended oscillation. since a critically damped + // spring should never overshoot the value, simply the current value to the + // target value. + if (dts > 1.0f || dts < 0.0f) { + stop(); + return mValue; + } + + float delta = (mTarget - mValue); + float force = delta - 2.0f * mVelocity; + + mVelocity += force * dts; + mValue += mVelocity * dts; + + // If we get close enough to the actual value, simply set the current value + // to the current target value and stop. + if (!isActive()) { + stop(); + } + + return mValue; + } + + /** + * @return true if this instance has velocity or it is not at the target value. + */ + public boolean isActive() { + boolean hasVelocity = Math.abs(mVelocity) >= EPSILON; + boolean atTarget = Math.abs(mTarget - mValue) < EPSILON; + return hasVelocity || !atTarget; + } + + /** + * Stop the spring motion wherever it is currently at. Sets target to the + * current value and sets the velocity to zero. + */ + public void stop() { + mTarget = mValue; + mVelocity = 0.0f; + } +} -- cgit v1.2.3