| /* |
| * 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; |
| } |
| } |