org.oscim.utils.animation.DragForce Maven / Gradle / Ivy
/*
* Copyright (C) 2017 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 org.oscim.utils.animation;
/**
* See https://developer.android.com/reference/android/support/animation/FlingAnimation.html
* Class androidx.dynamicanimation.animation.FlingAnimation
*/
public final class DragForce {
private static final float DEFAULT_FRICTION = -4.2f;
private static final float DEFAULT_MIN_VISIBLE_CHANGE_PIXELS = 0.5f;
// This multiplier is used to calculate the velocity threshold given a certain value
// threshold. The idea is that if it takes >= 1 frame to move the value threshold amount,
// then the velocity is a reasonable threshold.
private static final float VELOCITY_THRESHOLD_MULTIPLIER = 1000f / 16f; // 1 frame ≙ 16 ms (62.5 fps)
private float mFriction = DEFAULT_FRICTION;
private float mVelocityThreshold = DEFAULT_MIN_VISIBLE_CHANGE_PIXELS * VELOCITY_THRESHOLD_MULTIPLIER;
// Internal state to hold a value/velocity pair.
private float mValue;
private float mVelocity;
public void setFrictionScalar(float frictionScalar) {
mFriction = frictionScalar * DEFAULT_FRICTION;
}
public float getFrictionScalar() {
return mFriction / DEFAULT_FRICTION;
}
/**
* Updates the animation state (i.e. value and velocity).
*
* @param deltaT time elapsed in millisecond since last frame
* @return the value delta since last frame
*/
public float updateValueAndVelocity(long deltaT) {
float velocity = mVelocity;
mVelocity = (float) (velocity * Math.exp((deltaT / 1000f) * mFriction));
float valueDelta = (mVelocity - velocity);
mValue += valueDelta;
if (isAtEquilibrium(mValue, mVelocity)) {
mVelocity = 0f;
}
return valueDelta;
}
public void setValueAndVelocity(float value, float velocity) {
mValue = value;
mVelocity = velocity;
}
public float getValue() {
return mValue;
}
public float getVelocity() {
return mVelocity;
}
public float getAcceleration(float position, float velocity) {
return velocity * mFriction;
}
public boolean isAtEquilibrium(float value, float velocity) {
return Math.abs(velocity) < mVelocityThreshold;
}
public void setValueThreshold(float threshold) {
mVelocityThreshold = threshold * VELOCITY_THRESHOLD_MULTIPLIER;
}
}