1d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu/* 2d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Copyright (C) 2017 The Android Open Source Project 3d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 4d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Licensed under the Apache License, Version 2.0 (the "License"); 5d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * you may not use this file except in compliance with the License. 6d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * You may obtain a copy of the License at 7d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 8d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * http://www.apache.org/licenses/LICENSE-2.0 9d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 10d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Unless required by applicable law or agreed to in writing, software 11d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * distributed under the License is distributed on an "AS IS" BASIS, 12d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * See the License for the specific language governing permissions and 14d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * limitations under the License. 15d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 16d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 17d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liupackage android.support.animation; 18d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 19d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liuimport android.support.annotation.FloatRange; 20d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 21d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu/** 22d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Spring Force defines the characteristics of the spring being used in the animation. 23d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * <p> 24d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * By configuring the stiffness and damping ratio, callers can create a spring with the look and 25d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * feel suits their use case. Stiffness corresponds to the spring constant. The stiffer the spring 26d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * is, the harder it is to stretch it, the faster it undergoes dampening. 27d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * <p> 28d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Spring damping ratio describes how oscillations in a system decay after a disturbance. 29d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * When damping ratio > 1* (i.e. over-damped), the object will quickly return to the rest position 30d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * without overshooting. If damping ratio equals to 1 (i.e. critically damped), the object will 31d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * return to equilibrium within the shortest amount of time. When damping ratio is less than 1 32d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * (i.e. under-damped), the mass tends to overshoot, and return, and overshoot again. Without any 33d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * damping (i.e. damping ratio = 0), the mass will oscillate forever. 34d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 35d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liupublic final class SpringForce implements Force { 36d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 37d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Stiffness constant for extremely stiff spring. 38d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 39d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public static final float STIFFNESS_HIGH = 10_000f; 40d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 41d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Stiffness constant for medium stiff spring. This is the default stiffness for spring force. 42d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 43d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public static final float STIFFNESS_MEDIUM = 1500f; 44d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 45d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Stiffness constant for a spring with low stiffness. 46d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 47d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public static final float STIFFNESS_LOW = 200f; 48d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 49d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Stiffness constant for a spring with very low stiffness. 50d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 51d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public static final float STIFFNESS_VERY_LOW = 50f; 52d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 53d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 54d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Damping ratio for a very bouncy spring. Note for under-damped springs 55d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * (i.e. damping ratio < 1), the lower the damping ratio, the more bouncy the spring. 56d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 57d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public static final float DAMPING_RATIO_HIGH_BOUNCY = 0.2f; 58d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 59d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Damping ratio for a medium bouncy spring. This is also the default damping ratio for spring 60d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * force. Note for under-damped springs (i.e. damping ratio < 1), the lower the damping ratio, 61d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * the more bouncy the spring. 62d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 63d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public static final float DAMPING_RATIO_MEDIUM_BOUNCY = 0.5f; 64d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 65d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Damping ratio for a spring with low bounciness. Note for under-damped springs 66d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * (i.e. damping ratio < 1), the lower the damping ratio, the higher the bounciness. 67d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 68d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public static final float DAMPING_RATIO_LOW_BOUNCY = 0.75f; 69d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 70d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Damping ratio for a spring with no bounciness. This damping ratio will create a critically 71d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * damped spring that returns to equilibrium within the shortest amount of time without 72d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * oscillating. 73d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 74d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public static final float DAMPING_RATIO_NO_BOUNCY = 1f; 75d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 76d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // This multiplier is used to calculate the velocity threshold given a certain value threshold. 77d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // The idea is that if it takes >= 1 frame to move the value threshold amount, then the velocity 78d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // is a reasonable threshold. 79d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private static final double VELOCITY_THRESHOLD_MULTIPLIER = 1000.0 / 16.0; 80d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 81d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // Natural frequency 82d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu double mNaturalFreq = Math.sqrt(STIFFNESS_MEDIUM); 83d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // Damping ratio. 84d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu double mDampingRatio = DAMPING_RATIO_MEDIUM_BOUNCY; 85d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 86d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // Value to indicate an unset state. 87d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private static final double UNSET = Double.MAX_VALUE; 88d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 89d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // Indicates whether the spring has been initialized 90d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private boolean mInitialized = false; 91d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 92d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // Threshold for velocity and value to determine when it's reasonable to assume that the spring 93d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // is approximately at rest. 945df257d2a2f330f8e4d37321a40431973fa9b0d1Doris Liu private double mValueThreshold; 955df257d2a2f330f8e4d37321a40431973fa9b0d1Doris Liu private double mVelocityThreshold; 96d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 97d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // Intermediate values to simplify the spring function calculation per frame. 98d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private double mGammaPlus; 99d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private double mGammaMinus; 100d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private double mDampedFreq; 101d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 102d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // Final position of the spring. This must be set before the start of the animation. 103d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private double mFinalPosition = UNSET; 104d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 105d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // Internal state to hold a value/velocity pair. 106bfd3aa4c1b99267c42066918cfe8347b132f4dc1Doris Liu private final DynamicAnimation.MassState mMassState = new DynamicAnimation.MassState(); 107d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 108d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 109d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Creates a spring force. Note that final position of the spring must be set through 110d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * {@link #setFinalPosition(float)} before the spring animation starts. 111d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 112d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public SpringForce() { 113d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // No op. 114d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 115d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 116d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 117d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Creates a spring with a given final rest position. 118d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 119d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @param finalPosition final position of the spring when it reaches equilibrium 120d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 121d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public SpringForce(float finalPosition) { 122d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mFinalPosition = finalPosition; 123d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 124d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 125d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 126d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Sets the stiffness of a spring. The more stiff a spring is, the more force it applies to 127d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * the object attached when the spring is not at the final position. Default stiffness is 128d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * {@link #STIFFNESS_MEDIUM}. 129d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 130d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @param stiffness non-negative stiffness constant of a spring 131d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @return the spring force that the given stiffness is set on 132bfd3aa4c1b99267c42066918cfe8347b132f4dc1Doris Liu * @throws IllegalArgumentException if the given spring stiffness is not positive 133d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 134bfd3aa4c1b99267c42066918cfe8347b132f4dc1Doris Liu public SpringForce setStiffness( 135bfd3aa4c1b99267c42066918cfe8347b132f4dc1Doris Liu @FloatRange(from = 0.0, fromInclusive = false) float stiffness) { 136bfd3aa4c1b99267c42066918cfe8347b132f4dc1Doris Liu if (stiffness <= 0) { 137bfd3aa4c1b99267c42066918cfe8347b132f4dc1Doris Liu throw new IllegalArgumentException("Spring stiffness constant must be positive."); 138d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 139d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mNaturalFreq = Math.sqrt(stiffness); 140d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // All the intermediate values need to be recalculated. 141d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mInitialized = false; 142d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return this; 143d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 144d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 145d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 146d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Gets the stiffness of the spring. 147d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 148d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @return the stiffness of the spring 149d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 150d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public float getStiffness() { 151d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return (float) (mNaturalFreq * mNaturalFreq); 152d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 153d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 154d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 155d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Spring damping ratio describes how oscillations in a system decay after a disturbance. 156d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * <p> 157d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * When damping ratio > 1 (over-damped), the object will quickly return to the rest position 158d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * without overshooting. If damping ratio equals to 1 (i.e. critically damped), the object will 159d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * return to equilibrium within the shortest amount of time. When damping ratio is less than 1 160d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * (i.e. under-damped), the mass tends to overshoot, and return, and overshoot again. Without 161d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * any damping (i.e. damping ratio = 0), the mass will oscillate forever. 162d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * <p> 163d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Default damping ratio is {@link #DAMPING_RATIO_MEDIUM_BOUNCY}. 164d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 165d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @param dampingRatio damping ratio of the spring, it should be non-negative 166d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @return the spring force that the given damping ratio is set on 167d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @throws IllegalArgumentException if the {@param dampingRatio} is negative. 168d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 169d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public SpringForce setDampingRatio(@FloatRange(from = 0.0) float dampingRatio) { 170d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (dampingRatio < 0) { 171d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu throw new IllegalArgumentException("Damping ratio must be non-negative"); 172d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 173d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mDampingRatio = dampingRatio; 174d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // All the intermediate values need to be recalculated. 175d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mInitialized = false; 176d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return this; 177d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 178d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 179d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 180d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Returns the damping ratio of the spring. 181d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 182d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @return damping ratio of the spring 183d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 184d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public float getDampingRatio() { 185d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return (float) mDampingRatio; 186d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 187d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 188d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 189d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Sets the rest position of the spring. 190d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 191d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @param finalPosition rest position of the spring 192d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @return the spring force that the given final position is set on 193d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 194d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public SpringForce setFinalPosition(float finalPosition) { 195d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mFinalPosition = finalPosition; 196d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return this; 197d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 198d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 199d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 200d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Returns the rest position of the spring. 201d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 202d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @return rest position of the spring 203d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 204d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public float getFinalPosition() { 205d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return (float) mFinalPosition; 206d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 207d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 208d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /*********************** Below are private APIs *********************/ 209d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 210d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 211d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @hide 212d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 213d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu @Override 214d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public float getAcceleration(float lastDisplacement, float lastVelocity) { 215d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 216d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu lastDisplacement -= getFinalPosition(); 217d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 218d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu double k = mNaturalFreq * mNaturalFreq; 219d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu double c = 2 * mNaturalFreq * mDampingRatio; 220d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 221d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return (float) (-k * lastDisplacement - c * lastVelocity); 222d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 223d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 224d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 225d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @hide 226d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 227d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu @Override 228d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public boolean isAtEquilibrium(float value, float velocity) { 229d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (Math.abs(velocity) < mVelocityThreshold 230d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu && Math.abs(value - getFinalPosition()) < mValueThreshold) { 231d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return true; 232d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 233d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return false; 234d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 235d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 236d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 237d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Initialize the string by doing the necessary pre-calculation as well as some sanity check 238d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * on the setup. 239d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 240d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @throws IllegalStateException if the final position is not yet set by the time the spring 241d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * animation has started 242d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 243d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private void init() { 244d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (mInitialized) { 245d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return; 246d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 247d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 248d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (mFinalPosition == UNSET) { 249d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu throw new IllegalStateException("Error: Final position of the spring must be" 250d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu + " set before the animation starts"); 251d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 252d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 253d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (mDampingRatio > 1) { 254d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // Over damping 255d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mGammaPlus = -mDampingRatio * mNaturalFreq 256d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu + mNaturalFreq * Math.sqrt(mDampingRatio * mDampingRatio - 1); 257d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mGammaMinus = -mDampingRatio * mNaturalFreq 258d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu - mNaturalFreq * Math.sqrt(mDampingRatio * mDampingRatio - 1); 259d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } else if (mDampingRatio >= 0 && mDampingRatio < 1) { 260d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // Under damping 261d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mDampedFreq = mNaturalFreq * Math.sqrt(1 - mDampingRatio * mDampingRatio); 262d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 263d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 264d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mInitialized = true; 265d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 266d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 267d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 268d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Internal only call for Spring to calculate the spring position/velocity using 269d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * an analytical approach. 270d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 271bfd3aa4c1b99267c42066918cfe8347b132f4dc1Doris Liu DynamicAnimation.MassState updateValues(double lastDisplacement, double lastVelocity, 272bfd3aa4c1b99267c42066918cfe8347b132f4dc1Doris Liu long timeElapsed) { 273d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu init(); 274d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 275d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu double deltaT = timeElapsed / 1000d; // unit: seconds 276d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu lastDisplacement -= mFinalPosition; 277d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu double displacement; 278d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu double currentVelocity; 279d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (mDampingRatio > 1) { 280d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // Overdamped 281d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu double coeffA = lastDisplacement - (mGammaMinus * lastDisplacement - lastVelocity) 282d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu / (mGammaMinus - mGammaPlus); 283d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu double coeffB = (mGammaMinus * lastDisplacement - lastVelocity) 284d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu / (mGammaMinus - mGammaPlus); 285d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu displacement = coeffA * Math.pow(Math.E, mGammaMinus * deltaT) 286d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu + coeffB * Math.pow(Math.E, mGammaPlus * deltaT); 287d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu currentVelocity = coeffA * mGammaMinus * Math.pow(Math.E, mGammaMinus * deltaT) 288d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu + coeffB * mGammaPlus * Math.pow(Math.E, mGammaPlus * deltaT); 289d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } else if (mDampingRatio == 1) { 290d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // Critically damped 291d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu double coeffA = lastDisplacement; 292d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu double coeffB = lastVelocity + mNaturalFreq * lastDisplacement; 293d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu displacement = (coeffA + coeffB * deltaT) * Math.pow(Math.E, -mNaturalFreq * deltaT); 294d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu currentVelocity = (coeffA + coeffB * deltaT) * Math.pow(Math.E, -mNaturalFreq * deltaT) 295d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * (-mNaturalFreq) + coeffB * Math.pow(Math.E, -mNaturalFreq * deltaT); 296d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } else { 297d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu // Underdamped 298d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu double cosCoeff = lastDisplacement; 299d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu double sinCoeff = (1 / mDampedFreq) * (mDampingRatio * mNaturalFreq 300d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * lastDisplacement + lastVelocity); 301d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu displacement = Math.pow(Math.E, -mDampingRatio * mNaturalFreq * deltaT) 302d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * (cosCoeff * Math.cos(mDampedFreq * deltaT) 303d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu + sinCoeff * Math.sin(mDampedFreq * deltaT)); 304d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu currentVelocity = displacement * (-mNaturalFreq) * mDampingRatio 305d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu + Math.pow(Math.E, -mDampingRatio * mNaturalFreq * deltaT) 306d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * (-mDampedFreq * cosCoeff * Math.sin(mDampedFreq * deltaT) 307d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu + mDampedFreq * sinCoeff * Math.cos(mDampedFreq * deltaT)); 308d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 309d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 310d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mMassState.mValue = (float) (displacement + mFinalPosition); 311d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mMassState.mVelocity = (float) currentVelocity; 312d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return mMassState; 313d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 314d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 315d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 316d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * This threshold defines how close the animation value needs to be before the animation can 317d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * finish. This default value is based on the property being animated, e.g. animations on alpha, 318d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * scale, translation or rotation would have different thresholds. This value should be small 319d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * enough to avoid visual glitch of "jumping to the end". But it shouldn't be so small that 320d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * animations take seconds to finish. 321d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 322d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @param threshold the difference between the animation value and final spring position that 323d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * is allowed to end the animation when velocity is very low 324d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 3255df257d2a2f330f8e4d37321a40431973fa9b0d1Doris Liu void setValueThreshold(double threshold) { 326d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mValueThreshold = Math.abs(threshold); 327d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mVelocityThreshold = mValueThreshold * VELOCITY_THRESHOLD_MULTIPLIER; 328d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 329d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu} 330