/*******************************************************************************
* Copyright 2014 Geoscience Australia
*
* 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 au.gov.ga.earthsci.worldwind.common.view.orbit;
import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.animation.AngleAnimator;
import gov.nasa.worldwind.animation.AnimationSupport;
import gov.nasa.worldwind.animation.CompoundAnimator;
import gov.nasa.worldwind.animation.DoubleAnimator;
import gov.nasa.worldwind.animation.Interpolator;
import gov.nasa.worldwind.animation.PositionAnimator;
import gov.nasa.worldwind.animation.ScheduledInterpolator;
import gov.nasa.worldwind.geom.Angle;
import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.util.PropertyAccessor;
import gov.nasa.worldwind.view.ViewElevationAnimator;
import gov.nasa.worldwind.view.ViewPropertyAccessor;
import gov.nasa.worldwind.view.orbit.BasicOrbitView;
import gov.nasa.worldwind.view.orbit.OrbitView;
import gov.nasa.worldwind.view.orbit.OrbitViewPropertyAccessor;
/**
* Same as {@link gov.nasa.worldwind.view.orbit.FlyToOrbitViewAnimator}, but
* replacing any references to {@link BasicOrbitView} with the {@link OrbitView}
* interface.
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public class FlyToOrbitViewAnimator extends CompoundAnimator
{
int altitudeMode;
PositionAnimator centerAnimator;
ViewElevationAnimator zoomAnimator;
AngleAnimator headingAnimator;
AngleAnimator pitchAnimator;
AngleAnimator rollAnimator;
OrbitView orbitView;
public FlyToOrbitViewAnimator(OrbitView orbitView, Interpolator interpolator, int altitudeMode,
PositionAnimator centerAnimator, DoubleAnimator zoomAnimator,
AngleAnimator headingAnimator, AngleAnimator pitchAnimator, AngleAnimator rollAnimator)
{
super(interpolator, centerAnimator, zoomAnimator, headingAnimator, pitchAnimator, rollAnimator);
this.orbitView = orbitView;
this.centerAnimator = centerAnimator;
this.zoomAnimator = (ViewElevationAnimator) zoomAnimator;
this.headingAnimator = headingAnimator;
this.pitchAnimator = pitchAnimator;
this.rollAnimator = rollAnimator;
if (interpolator == null)
{
this.interpolator = new ScheduledInterpolator(10000);
}
this.altitudeMode = altitudeMode;
}
public static FlyToOrbitViewAnimator createFlyToOrbitViewAnimator(
OrbitView orbitView,
Position beginCenterPos, Position endCenterPos,
Angle beginHeading, Angle endHeading,
Angle beginPitch, Angle endPitch,
double beginZoom, double endZoom, long timeToMove, int altitudeMode)
{
OnSurfacePositionAnimator centerAnimator = new OnSurfacePositionAnimator(orbitView.getGlobe(),
new ScheduledInterpolator(timeToMove),
beginCenterPos, endCenterPos,
OrbitViewPropertyAccessor.createCenterPositionAccessor(
orbitView), altitudeMode);
// Create an elevation animator with ABSOLUTE altitude mode because the OrbitView altitude mode applies to the
// center position, not the zoom.
ViewElevationAnimator zoomAnimator = new ViewElevationAnimator(orbitView.getGlobe(),
beginZoom, endZoom, beginCenterPos, endCenterPos, WorldWind.ABSOLUTE,
OrbitViewPropertyAccessor.createZoomAccessor(orbitView));
centerAnimator.useMidZoom = zoomAnimator.getUseMidZoom();
AngleAnimator headingAnimator = new AngleAnimator(
new ScheduledInterpolator(timeToMove),
beginHeading, endHeading,
ViewPropertyAccessor.createHeadingAccessor(orbitView));
AngleAnimator pitchAnimator = new AngleAnimator(
new ScheduledInterpolator(timeToMove),
beginPitch, endPitch,
ViewPropertyAccessor.createPitchAccessor(orbitView));
FlyToOrbitViewAnimator panAnimator = new FlyToOrbitViewAnimator(orbitView,
new ScheduledInterpolator(timeToMove), altitudeMode, centerAnimator,
zoomAnimator, headingAnimator, pitchAnimator, null);
return (panAnimator);
}
protected static class OnSurfacePositionAnimator extends PositionAnimator
{
Globe globe;
int altitudeMode;
boolean useMidZoom = true;
public OnSurfacePositionAnimator(Globe globe, Interpolator interpolator,
Position begin,
Position end,
PropertyAccessor.PositionAccessor propertyAccessor, int altitudeMode)
{
super(interpolator, begin, end, propertyAccessor);
this.globe = globe;
this.altitudeMode = altitudeMode;
}
@Override
protected Position nextPosition(double interpolant)
{
final int MAX_SMOOTHING = 1;
final double CENTER_START = this.useMidZoom ? 0.2 : 0.0;
final double CENTER_STOP = this.useMidZoom ? 0.8 : 0.8;
double latLonInterpolant = AnimationSupport.basicInterpolant(interpolant, CENTER_START, CENTER_STOP,
MAX_SMOOTHING);
// Invoke the standard next position functionality.
Position pos = super.nextPosition(latLonInterpolant);
// Check the altitude mode. If the altitude mode depends on the surface elevation we will reevaluate the
// end position altitude. When the animation starts we may not have accurate elevation data available for
// the end position, so recalculating the elevation as we go ensures that the animation will end at the
// correct altitude.
double endElevation = 0.0;
boolean overrideEndElevation = false;
if (this.altitudeMode == WorldWind.CLAMP_TO_GROUND)
{
overrideEndElevation = true;
endElevation = this.globe.getElevation(getEnd().getLatitude(), getEnd().getLongitude());
}
else if (this.altitudeMode == WorldWind.RELATIVE_TO_GROUND)
{
overrideEndElevation = true;
endElevation = this.globe.getElevation(getEnd().getLatitude(), getEnd().getLongitude())
+ getEnd().getAltitude();
}
if (overrideEndElevation)
{
LatLon ll = pos; // Use interpolated lat/lon.
double e1 = getBegin().getElevation();
pos = new Position(ll, (1 - latLonInterpolant) * e1 + latLonInterpolant * endElevation);
}
return pos;
}
}
}