1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.replica.replicaisland; 18 19 /** 20 * Helper class for interpolating velocity over time given a target velocity and acceleration. 21 * The current velocity will be accelerated towards the target until the target is reached. 22 * Note that acceleration is effectively an absolute value--it always points in the direction of 23 * the target velocity. 24 */ 25 public class Interpolator extends AllocationGuard { 26 27 private float mCurrent; 28 private float mTarget; 29 private float mAcceleration; 30 Interpolator()31 public Interpolator() { 32 super(); 33 } 34 35 // Rather than simply interpolating acceleration and velocity for each time step 36 // (as in, position += (velocity * time); velocity += (acceleration * time);), 37 // we actually perform the work needed to calculate the integral of velocity with respect to 38 // time. 39 // 40 // The integral of velocity is: 41 // 42 // integral[(v + aT)dT] 43 // 44 // Simplified to: 45 // 46 // vT + 1/2 * aT^2 47 // 48 // Thus: 49 // change in position = velocity * time + (0.5 * acceleration * (time^2)) 50 // change in velocity = acceleration * time 51 set(float current, float target, float acceleration)52 public void set(float current, float target, float acceleration) { 53 mCurrent = current; 54 mTarget = target; 55 mAcceleration = acceleration; 56 } 57 58 // While this function writes directly to velocity, it doesn't affect 59 // position. Instead, the position offset is returned so that it can be blended. interpolate(float secondsDelta)60 public float interpolate(float secondsDelta) { 61 float oldVelocity = mCurrent; 62 63 // point the acceleration at the target, or zero it if we are already 64 // there 65 float directionalAcceleration = calculateAcceleration(oldVelocity, mAcceleration, mTarget); 66 67 // calculate scaled acceleration (0.5 * acceleration * (time^2)) 68 float scaledAcceleration; 69 scaledAcceleration = scaleAcceleration(directionalAcceleration, secondsDelta); 70 71 // calculate the change in position 72 float positionOffset = (oldVelocity * secondsDelta) + scaledAcceleration; 73 74 // change in velocity = v + aT 75 float newVelocity = oldVelocity + (directionalAcceleration * secondsDelta); 76 77 // check to see if we've passed our target velocity since the last time 78 // step. If so, clamp to the target 79 if (passedTarget(oldVelocity, newVelocity, mTarget)) { 80 newVelocity = mTarget; 81 } 82 83 mCurrent = newVelocity; 84 85 return positionOffset; 86 } 87 getCurrent()88 public float getCurrent() { 89 return mCurrent; 90 } 91 passedTarget(float oldVelocity, float newVelocity, float targetVelocity)92 private boolean passedTarget(float oldVelocity, float newVelocity, float targetVelocity) { 93 boolean result = false; 94 95 if (oldVelocity < targetVelocity && newVelocity > targetVelocity) { 96 result = true; 97 } else if (oldVelocity > targetVelocity && newVelocity < targetVelocity) { 98 result = true; 99 } 100 101 return result; 102 } 103 104 // find the magnitude and direction of acceleration. 105 // in this system, acceleration always points toward target velocity calculateAcceleration(float velocity, float acceleration, float target)106 private float calculateAcceleration(float velocity, float acceleration, float target) { 107 if (Math.abs(velocity - target) < 0.0001f) { 108 // no accel needed 109 acceleration = 0.0f; 110 } else if (velocity > target) { 111 // accel must be negative 112 acceleration *= -1.0f; 113 } 114 115 return acceleration; 116 } 117 118 // calculates 1/2 aT^2 scaleAcceleration(float acceleration, float secondsDelta)119 private float scaleAcceleration(float acceleration, float secondsDelta) { 120 float timeSquared = (secondsDelta * secondsDelta); 121 float scaledAccel = acceleration * timeSquared; 122 scaledAccel *= 0.5f; 123 124 return scaledAccel; 125 } 126 } 127