/*
Copyright (C) 2001, 2007 United States Government as represented by
the Administrator of the National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwind.view;
import gov.nasa.worldwind.View;
import gov.nasa.worldwind.ViewStateIterator;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.util.Logging;
/**
* @author dcollins
* @version $Id: AbstractViewStateIterator.java 4852 2008-03-28 19:14:52Z dcollins $
*/
public abstract class AbstractViewStateIterator implements ViewStateIterator
{
private long startTime = -1;
private long length;
private boolean smoothed = true;
private boolean hasNext = true;
public AbstractViewStateIterator(long lengthMillis)
{
this(-1, lengthMillis);
}
public AbstractViewStateIterator(long startTimeMillis, long lengthMillis)
{
if (lengthMillis < 0)
{
String message = Logging.getMessage("generic.ArgumentOutOfRange", lengthMillis);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.startTime = startTimeMillis;
this.length = lengthMillis;
}
public boolean isSmoothed()
{
return this.smoothed;
}
public void setSmoothed(boolean smoothed)
{
this.smoothed = smoothed;
}
public ViewStateIterator coalesceWith(View view, ViewStateIterator stateIterator)
{
return this;
}
public boolean hasNextState(View view)
{
return this.hasNext;
}
public void nextState(View view)
{
if (view == null)
{
String message = Logging.getMessage("nullValue.ViewIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
// Get the current system time in milliseconds.
long timeMillis = System.currentTimeMillis();
// If no start time is specified, begin counting time on the first run.
if (this.startTime < 0)
this.startTime = timeMillis;
// If the iterator has not started, exit for now.
if (!hasStarted(timeMillis))
return;
// Stop iteration when we've reached the end time.
if (!hasNextIteration(timeMillis))
stopNextIteration();
// Compute - and optionally smooth - the interpolant corresponding to the current time.
double interpolant = computeInterpolant(timeMillis);
if (this.smoothed)
interpolant = smoothValue(interpolant);
try
{
doNextState(interpolant, view);
view.firePropertyChange(AVKey.VIEW, null, view);
}
catch (Exception e)
{
Logging.logger().log(java.util.logging.Level.SEVERE, "generic.ExceptionWhileRunningViewStateIterator", e);
stopNextIteration();
}
}
protected abstract void doNextState(double interpolant, View view);
protected final void stopNextIteration()
{
this.hasNext = false;
}
private boolean hasStarted(long timeMillis)
{
return this.startTime < timeMillis;
}
private boolean hasNextIteration(long timeMillis)
{
// Iterator has more iterations when current-time < end-time.
return timeMillis < (this.startTime + this.length);
}
private double computeInterpolant(long timeMillis)
{
// When no start time is specified, begin counting time on the first run.
if (this.startTime < 0)
this.startTime = timeMillis;
// Exit when current time is before starting time.
if (timeMillis < this.startTime)
return 0;
long elapsedTime = timeMillis - this.startTime;
double unclampedInterpolant = ((double) elapsedTime) / ((double) this.length);
return clampValue(unclampedInterpolant, 0, 1);
}
private static double clampValue(double value, double min, double max)
{
return value < min ? min : (value > max ? max : value);
}
private static double smoothValue(double value)
{
// Apply "hermite" smoothing.
return value * value * (3.0 - 2.0 * value);
}
}