/* Copyright (C) 2001, 2006 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.geom.*; import gov.nasa.worldwind.util.Logging; /** * @author dcollins * @version $Id: ScheduledOrbitViewStateIterator.java 4100 2008-01-08 02:49:54Z dcollins $ */ public class ScheduledOrbitViewStateIterator extends BasicOrbitViewStateIterator { private final int maxSmoothing; protected ScheduledOrbitViewStateIterator(long lengthMillis, OrbitViewAnimator animator, boolean doSmoothing) { this(new ScheduledOrbitViewInterpolator(lengthMillis), animator, doSmoothing); } protected ScheduledOrbitViewStateIterator(ScheduledOrbitViewInterpolator interpolator, OrbitViewAnimator animator, boolean doSmoothing) { super(false, interpolator, animator); if (interpolator == null) { String message = Logging.getMessage("nullValue.OrbitViewInterpolatorIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (animator == null) { String message = Logging.getMessage("nullValue.OrbitViewAnimatorIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.maxSmoothing = maxSmoothingFromFlag(doSmoothing); } public final boolean isSmoothing() { return this.maxSmoothing != 0; } public void doNextState(double interpolant, OrbitView orbitView) { if (orbitView == null) { String message = Logging.getMessage("nullValue.OrbitViewIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } double smoothedInterpolant = interpolantSmoothed(interpolant, this.maxSmoothing); super.doNextState(smoothedInterpolant, orbitView); } private static double interpolantSmoothed(double interpolant, int smoothingIterations) { // Apply iterative hermite smoothing. double smoothed = interpolant; for (int i = 0; i < smoothingIterations; i++) { smoothed = smoothed * smoothed * (3.0 - 2.0 * smoothed); } return smoothed; } private static int maxSmoothingFromFlag(boolean doSmoothing) { if (doSmoothing) return 1; else return 0; } // ============== Factory Functions ======================= // // ============== Factory Functions ======================= // // ============== Factory Functions ======================= // public static ScheduledOrbitViewStateIterator createCenterIterator( Position begin, Position end) { if (begin == null || end == null) { String message = Logging.getMessage("nullValue.PositionIsNull"); Logging.logger().fine(message); throw new IllegalArgumentException(message); } // TODO: length-scaling factory function final long DEFAULT_LENGTH_MILLIS = 4000; boolean smoothed = true; return createCenterIterator( begin, end, DEFAULT_LENGTH_MILLIS, smoothed); } public static ScheduledOrbitViewStateIterator createCenterIterator( Position begin, Position end, long lengthMillis, boolean smoothed) { if (begin == null || end == null) { String message = Logging.getMessage("nullValue.PositionIsNull"); Logging.logger().fine(message); throw new IllegalArgumentException(message); } if (lengthMillis < 0) { String message = Logging.getMessage("generic.ArgumentOutOfRange"); Logging.logger().fine(message); throw new IllegalArgumentException(message); } OrbitViewPropertyAccessor.PositionAccessor propertyAccessor = OrbitViewPropertyAccessor.createCenterPositionAccessor(); OrbitViewAnimator animator = new BasicOrbitViewAnimator.PositionAnimator(begin, end, propertyAccessor); return new ScheduledOrbitViewStateIterator(lengthMillis, animator, smoothed); } public static ScheduledOrbitViewStateIterator createHeadingIterator( Angle begin, Angle end) { if (begin == null || end == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } final long MIN_LENGTH_MILLIS = 500; final long MAX_LENGTH_MILLIS = 3000; long lengthMillis = getScaledLengthMillis( begin, end, Angle.POS180, MIN_LENGTH_MILLIS, MAX_LENGTH_MILLIS); boolean smoothed = true; return createHeadingIterator( begin, end, lengthMillis, smoothed); } public static ScheduledOrbitViewStateIterator createHeadingIterator( Angle begin, Angle end, long lengthMillis, boolean smoothed) { if (begin == null || end == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (lengthMillis < 0) { String message = Logging.getMessage("generic.ArgumentOutOfRange", lengthMillis); Logging.logger().severe(message); throw new IllegalArgumentException(message); } OrbitViewPropertyAccessor.AngleAccessor propertyAccessor = OrbitViewPropertyAccessor.createHeadingAccessor(); OrbitViewAnimator animator = new BasicOrbitViewAnimator.AngleAnimator(begin, end, propertyAccessor); return new ScheduledOrbitViewStateIterator(lengthMillis, animator, smoothed); } public static ScheduledOrbitViewStateIterator createPitchIterator( Angle begin, Angle end) { if (begin == null || end == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } final long MIN_LENGTH_MILLIS = 500; final long MAX_LENGTH_MILLIS = 1500; long lengthMillis = getScaledLengthMillis( begin, end, Angle.POS90, MIN_LENGTH_MILLIS, MAX_LENGTH_MILLIS); boolean smoothed = true; return createPitchIterator( begin, end, lengthMillis, smoothed); } public static ScheduledOrbitViewStateIterator createPitchIterator( Angle begin, Angle end, long lengthMillis, boolean smoothed) { if (begin == null || end == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (lengthMillis < 0) { String message = Logging.getMessage("generic.ArgumentOutOfRange", lengthMillis); Logging.logger().severe(message); throw new IllegalArgumentException(message); } OrbitViewPropertyAccessor.AngleAccessor propertyAccessor = OrbitViewPropertyAccessor.createPitchAccessor(); OrbitViewAnimator animator = new BasicOrbitViewAnimator.AngleAnimator(begin, end, propertyAccessor); return new ScheduledOrbitViewStateIterator(lengthMillis, animator, smoothed); } public static ScheduledOrbitViewStateIterator createZoomIterator( double begin, double end) { // TODO: length-scaling factory function final long DEFAULT_LENGTH_MILLIS = 4000; boolean smoothed = true; return createZoomIterator( begin, end, DEFAULT_LENGTH_MILLIS, smoothed); } public static ScheduledOrbitViewStateIterator createZoomIterator( double begin, double end, long lengthMillis, boolean smoothed) { if (lengthMillis < 0) { String message = Logging.getMessage("generic.ArgumentOutOfRange", lengthMillis); Logging.logger().severe(message); throw new IllegalArgumentException(message); } OrbitViewPropertyAccessor.DoubleAccessor propertyAccessor = OrbitViewPropertyAccessor.createZoomAccessor(); OrbitViewAnimator animator = new BasicOrbitViewAnimator.DoubleAnimator(begin, end, propertyAccessor); return new ScheduledOrbitViewStateIterator(lengthMillis, animator, smoothed); } public static ScheduledOrbitViewStateIterator createCenterHeadingPitchIterator( Position beginCenter, Position endCenter, Angle beginHeading, Angle endHeading, Angle beginPitch, Angle endPitch, long lengthMillis, boolean smoothed) { if (beginCenter == null || endCenter == null) { String message = Logging.getMessage("nullValue.PositionIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (beginHeading == null || endHeading == null || beginPitch == null || endPitch == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (lengthMillis < 0) { String message = Logging.getMessage("generic.ArgumentOutOfRange", lengthMillis); Logging.logger().severe(message); throw new IllegalArgumentException(message); } OrbitViewPropertyAccessor.PositionAccessor cPropAccessor = OrbitViewPropertyAccessor.createCenterPositionAccessor(); OrbitViewPropertyAccessor.AngleAccessor hPropAccessor = OrbitViewPropertyAccessor.createHeadingAccessor(); OrbitViewPropertyAccessor.AngleAccessor pPropAccessor = OrbitViewPropertyAccessor.createPitchAccessor(); OrbitViewAnimator cAnimator = new BasicOrbitViewAnimator.PositionAnimator(beginCenter, endCenter, cPropAccessor); OrbitViewAnimator hAnimator = new BasicOrbitViewAnimator.AngleAnimator(beginHeading, endHeading, hPropAccessor); OrbitViewAnimator pAnimator = new BasicOrbitViewAnimator.AngleAnimator(beginPitch, endPitch, pPropAccessor); OrbitViewAnimator animator = new BasicOrbitViewAnimator.CompoundAnimator(cAnimator, hAnimator, pAnimator); return new ScheduledOrbitViewStateIterator(lengthMillis, animator, smoothed); } public static ScheduledOrbitViewStateIterator createCenterZoomIterator( Position beginCenter, Position endCenter, double beginZoom, double endZoom, long lengthMillis, boolean smoothed) { if (beginCenter == null || endCenter == null) { String message = Logging.getMessage("nullValue.PositionIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (lengthMillis < 0) { String message = Logging.getMessage("generic.ArgumentOutOfRange", lengthMillis); Logging.logger().severe(message); throw new IllegalArgumentException(message); } OrbitViewPropertyAccessor.PositionAccessor cPropAccessor = OrbitViewPropertyAccessor.createCenterPositionAccessor(); OrbitViewPropertyAccessor.DoubleAccessor zPropAccessor = OrbitViewPropertyAccessor.createZoomAccessor(); OrbitViewAnimator cAnimator = new BasicOrbitViewAnimator.PositionAnimator(beginCenter, endCenter, cPropAccessor); OrbitViewAnimator zAnimator = new BasicOrbitViewAnimator.DoubleAnimator(beginZoom, endZoom, zPropAccessor); OrbitViewAnimator animator = new BasicOrbitViewAnimator.CompoundAnimator(cAnimator, zAnimator); return new ScheduledOrbitViewStateIterator(lengthMillis, animator, smoothed); } public static ScheduledOrbitViewStateIterator createCenterHeadingPitchZoomIterator( Position beginCenter, Position endCenter, Angle beginHeading, Angle endHeading, Angle beginPitch, Angle endPitch, double beginZoom, double endZoom, long lengthMillis, boolean smoothed) { if (beginCenter == null || endCenter == null) { String message = Logging.getMessage("nullValue.PositionIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (beginHeading == null || endHeading == null || beginPitch == null || endPitch == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (lengthMillis < 0) { String message = Logging.getMessage("generic.ArgumentOutOfRange", lengthMillis); Logging.logger().severe(message); throw new IllegalArgumentException(message); } OrbitViewPropertyAccessor.PositionAccessor cPropAccessor = OrbitViewPropertyAccessor.createCenterPositionAccessor(); OrbitViewPropertyAccessor.AngleAccessor hPropAccessor = OrbitViewPropertyAccessor.createHeadingAccessor(); OrbitViewPropertyAccessor.AngleAccessor pPropAccessor = OrbitViewPropertyAccessor.createPitchAccessor(); OrbitViewPropertyAccessor.DoubleAccessor zPropAccessor = OrbitViewPropertyAccessor.createZoomAccessor(); OrbitViewAnimator cAnimator = new BasicOrbitViewAnimator.PositionAnimator(beginCenter, endCenter, cPropAccessor); OrbitViewAnimator hAnimator = new BasicOrbitViewAnimator.AngleAnimator(beginHeading, endHeading, hPropAccessor); OrbitViewAnimator pAnimator = new BasicOrbitViewAnimator.AngleAnimator(beginPitch, endPitch, pPropAccessor); OrbitViewAnimator zAnimator = new BasicOrbitViewAnimator.DoubleAnimator(beginZoom, endZoom, zPropAccessor); OrbitViewAnimator animator = new BasicOrbitViewAnimator.CompoundAnimator( cAnimator, hAnimator, pAnimator, zAnimator); return new ScheduledOrbitViewStateIterator(lengthMillis, animator, smoothed); } public static ScheduledOrbitViewStateIterator createHeadingPitchIterator( Angle beginHeading, Angle endHeading, Angle beginPitch, Angle endPitch) { if (beginHeading == null || endHeading == null || beginPitch == null || endPitch == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } final long MIN_LENGTH_MILLIS = 500; final long MAX_LENGTH_MILLIS = 3000; long headingLengthMillis = getScaledLengthMillis( beginHeading, endHeading, Angle.POS180, MIN_LENGTH_MILLIS, MAX_LENGTH_MILLIS); long pitchLengthMillis = getScaledLengthMillis( beginPitch, endPitch, Angle.POS90, MIN_LENGTH_MILLIS, MAX_LENGTH_MILLIS / 2L); long lengthMillis = headingLengthMillis + pitchLengthMillis; boolean smoothed = true; return createHeadingPitchIterator( beginHeading, endHeading, beginPitch, endPitch, lengthMillis, smoothed); } public static ScheduledOrbitViewStateIterator createHeadingPitchIterator( Angle beginHeading, Angle endHeading, Angle beginPitch, Angle endPitch, long lengthMillis, boolean smoothed) { if (beginHeading == null || endHeading == null || beginPitch == null || endPitch == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (lengthMillis < 0) { String message = Logging.getMessage("generic.ArgumentOutOfRange", lengthMillis); Logging.logger().severe(message); throw new IllegalArgumentException(message); } OrbitViewPropertyAccessor.AngleAccessor hPropAccessor = OrbitViewPropertyAccessor.createHeadingAccessor(); OrbitViewPropertyAccessor.AngleAccessor pPropAccessor = OrbitViewPropertyAccessor.createPitchAccessor(); OrbitViewAnimator hAnimator = new BasicOrbitViewAnimator.AngleAnimator(beginHeading, endHeading, hPropAccessor); OrbitViewAnimator pAnimator = new BasicOrbitViewAnimator.AngleAnimator(beginPitch, endPitch, pPropAccessor); OrbitViewAnimator animator = new BasicOrbitViewAnimator.CompoundAnimator(hAnimator, pAnimator); return new ScheduledOrbitViewStateIterator(lengthMillis, animator, smoothed); } public static ScheduledOrbitViewStateIterator createHeadingPitchZoomIterator( Angle beginHeading, Angle endHeading, Angle beginPitch, Angle endPitch, double beginZoom, double endZoom, long lengthMillis, boolean smoothed) { if (beginHeading == null || endHeading == null || beginPitch == null || endPitch == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (lengthMillis < 0) { String message = Logging.getMessage("generic.ArgumentOutOfRange", lengthMillis); Logging.logger().severe(message); throw new IllegalArgumentException(message); } OrbitViewPropertyAccessor.AngleAccessor hPropAccessor = OrbitViewPropertyAccessor.createHeadingAccessor(); OrbitViewPropertyAccessor.AngleAccessor pPropAccessor = OrbitViewPropertyAccessor.createPitchAccessor(); OrbitViewPropertyAccessor.DoubleAccessor zPropAccessor = OrbitViewPropertyAccessor.createZoomAccessor(); OrbitViewAnimator hAnimator = new BasicOrbitViewAnimator.AngleAnimator(beginHeading, endHeading, hPropAccessor); OrbitViewAnimator pAnimator = new BasicOrbitViewAnimator.AngleAnimator(beginPitch, endPitch, pPropAccessor); OrbitViewAnimator zAnimator = new BasicOrbitViewAnimator.DoubleAnimator(beginZoom, endZoom, zPropAccessor); OrbitViewAnimator animator = new BasicOrbitViewAnimator.CompoundAnimator(hAnimator, pAnimator, zAnimator); return new ScheduledOrbitViewStateIterator(lengthMillis, animator, smoothed); } private static long getScaledLengthMillis( Angle begin, Angle end, Angle max, long minLengthMillis, long maxLengthMillis) { Angle angularDistance = begin.angularDistanceTo(end); double scaleFactor = angularRatio(angularDistance, max); return (long) mixDouble(scaleFactor, minLengthMillis, maxLengthMillis); } private static double angularRatio(Angle x, Angle y) { if (x == null || y == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } double unclampedRatio = x.divide(y); return clampDouble(unclampedRatio, 0, 1); } private static double clampDouble(double value, double min, double max) { return value < min ? min : (value > max ? max : value); } private static double mixDouble(double amount, double value1, double value2) { if (amount < 0) return value1; else if (amount > 1) return value2; return value1 * (1.0 - amount) + value2 * amount; } }