001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030/**
031 *
032 */
033package org.openimaj.content.animation.animator;
034
035/**
036 * An animator that will animate a value over a given time period. The animator
037 * is constructed using a specific time period and on the first call of the
038 * makeNextValue() will start a timer.
039 * <p>
040 * Subclasses must implement a method that can return a value based on an
041 * absolute percentage value. This class will convert the time each nextValue()
042 * is called into a percentage value between the start and end times and use
043 * that to calculate the absolute value of the animator.
044 *
045 * @author David Dupplaw (dpd@ecs.soton.ac.uk)
046 * @version $Author$, $Revision$, $Date$
047 * @param <T>
048 *            The type of value produced
049 */
050public abstract class TimeBasedValueAnimator<T> implements ValueAnimator<T>
051{
052        /** The time the animation started */
053        private long startTime = 0;
054
055        /** The length of the animation */
056        private long animationLength = 0;
057
058        /** The start value of the animation */
059        protected T startValue = null;
060
061        /** The end/target value of the animation */
062        protected T endValue = null;
063
064        /** The current percentage */
065        private double currentPC = 0;
066
067        /**
068         * @param initial
069         *            The start value for the animator
070         * @param end
071         *            The end value for the animator
072         * @param millis
073         *            The length of time the animation should run
074         */
075        public TimeBasedValueAnimator(final T initial, final T end, final long millis)
076        {
077                this.startValue = initial;
078                this.endValue = end;
079                this.animationLength = millis;
080        }
081
082        /**
083         * Given a percentage value (0 &lt; pc &lt;=1), the method should return a value
084         * for the animation.
085         *
086         * @param pc
087         *            the percentage value
088         * @return The animator value
089         */
090        protected abstract T calculateValue(double pc);
091
092        /**
093         * {@inheritDoc}
094         * 
095         * @see org.openimaj.content.animation.animator.ValueAnimator#nextValue()
096         */
097        @Override
098        public T nextValue()
099        {
100                final long currentTime = System.currentTimeMillis();
101                if (this.startTime == 0)
102                        this.startTime = currentTime;
103
104                this.currentPC = (currentTime - this.startTime) / (double) this.animationLength;
105
106                if (this.isComplete())
107                        return this.endValue;
108
109                return this.calculateValue(this.currentPC);
110        }
111
112        /**
113         * {@inheritDoc}
114         * 
115         * @see org.openimaj.content.animation.animator.ValueAnimator#reset()
116         */
117        @Override
118        public void reset()
119        {
120                this.startTime = 0;
121                this.currentPC = 0;
122        }
123
124        /**
125         * Returns whether the animator has completed
126         *
127         * @return TRUE if the animator has completed.
128         */
129        public boolean isComplete()
130        {
131                return this.currentPC >= 1.0;
132        }
133
134        /**
135         * A implementation sugar for {@link #isComplete()}
136         *
137         * {@inheritDoc}
138         * 
139         * @see org.openimaj.content.animation.animator.ValueAnimator#hasFinished()
140         */
141        @Override
142        public boolean hasFinished()
143        {
144                return this.isComplete();
145        }
146}