| /* | |
| * Copyright 2011 Google Inc. | |
| * | |
| * 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.google.gwt.touch.client; | |
| /** | |
| * Default implementation of momentum. | |
| */ | |
| public class DefaultMomentum implements Momentum { | |
| /** | |
| * The constant factor applied to velocity every millisecond to simulate | |
| * deceleration. | |
| */ | |
| private static final double DECELERATION_FACTOR = 0.9993; | |
| /** | |
| * The velocity threshold at which declereration will end. | |
| */ | |
| private static final double DECELERATION_STOP_VELOCITY = 0.02; | |
| /** | |
| * The minimum deceleration rate in pixels per millisecond^2. | |
| */ | |
| private static final double MIN_DECELERATION = 0.0005; | |
| public State createState(Point initialPosition, Point initialVelocity) { | |
| return new State(initialPosition, initialVelocity); | |
| } | |
| public boolean updateState(State state) { | |
| // Calculate the new velocity. | |
| int ellapsedMillis = state.getElapsedMillis(); | |
| int totalEllapsedMillis = state.getCumulativeElapsedMillis(); | |
| Point initialVelocity = state.getInitialVelocity(); | |
| Point oldVelocity = state.getVelocity(); | |
| double decelFactor = Math.pow(DECELERATION_FACTOR, totalEllapsedMillis); | |
| double minDecel = ellapsedMillis * MIN_DECELERATION; | |
| double newVelocityX = | |
| calcNewVelocity(initialVelocity.getX(), decelFactor, oldVelocity.getX(), minDecel); | |
| double newVelocityY = | |
| calcNewVelocity(initialVelocity.getY(), decelFactor, oldVelocity.getY(), minDecel); | |
| // Save the new velocity. | |
| Point newVelocity = new Point(newVelocityX, newVelocityY); | |
| state.setVelocity(newVelocity); | |
| // Calculate the distance traveled. | |
| int elapsedMillis = state.getElapsedMillis(); | |
| Point dist = newVelocity.mult(new Point(elapsedMillis, elapsedMillis)); | |
| // Update the state with the new point. | |
| Point position = state.getPosition(); | |
| state.setPosition(position.plus(dist)); | |
| // End momentum when we reach the threshold. | |
| if (Math.abs(newVelocity.getX()) < DECELERATION_STOP_VELOCITY | |
| && Math.abs(newVelocity.getY()) < DECELERATION_STOP_VELOCITY) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| /** | |
| * Calculate the new velocity. | |
| * | |
| * @param initialVelocity the initial velocity | |
| * @param decelFactor the deceleration factor based on the cumulative elapsed | |
| * time | |
| * @param oldVelocity the previous velocity | |
| * @param minDecel the absolute value of the minimum deceleration over the | |
| * elapsed time since the last update | |
| * @return the new velocity | |
| */ | |
| private double calcNewVelocity(double initialVelocity, double decelFactor, double oldVelocity, | |
| double minDecel) { | |
| // Calculate the new velocity based on the deceleration factor. | |
| double newVelocity = initialVelocity * decelFactor; | |
| // Ensure that we are decelerating faster than the minimum rate. | |
| if (oldVelocity >= 0) { | |
| double maxVelocityX = Math.max(0.0, oldVelocity - minDecel); | |
| newVelocity = Math.min(newVelocity, maxVelocityX); | |
| } else { | |
| double minVelocityX = Math.min(0.0, oldVelocity + minDecel); | |
| newVelocity = Math.max(newVelocity, minVelocityX); | |
| } | |
| return newVelocity; | |
| } | |
| } |