Home | History | Annotate | Download | only in replicaisland
      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 
     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 
     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.
     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 
     88     public float getCurrent() {
     89         return mCurrent;
     90     }
     91 
     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
    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
    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