/** * Set the value of the field being animated based on the given interpolant. * @param interpolant A value between 0 and 1. */ public void set(double interpolant) { const int MAX_SMOOTHING = 1; const double ZOOM_START = 0.0; const double ZOOM_STOP = 1.0; if (interpolant >= 1.0) { this.stop(); } double zoomInterpolant; if (this.UseMidZoom) { double value; zoomInterpolant = this.zoomInterpolant(interpolant, ZOOM_START, ZOOM_STOP, MAX_SMOOTHING); if (interpolant <= .5) { value = nextDouble(zoomInterpolant, this.Begin, this.End); } else { value = nextDouble(zoomInterpolant, this.End, this.trueEndZoom); } this.propertyAccessor.setDouble(value); } else { zoomInterpolant = AnimationSupport.basicInterpolant(interpolant, ZOOM_START, ZOOM_STOP, MAX_SMOOTHING); base.set(zoomInterpolant); } }
/** * Computes the value for the given interpolant. * * @param interpolant the interpolant to use for interpolating * @param start the lower end of the interpolated range. * @param end the upper end of the interpolated range. * @return the interpolated value. */ protected double nextDouble(double interpolant, double start, double end) { double elevation = AnimationSupport.mixDouble( interpolant, start, end); // 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; bool overrideEndElevation = false; if (this.globe != null && this.altitudeMode == WorldWind.CLAMP_TO_GROUND) { overrideEndElevation = true; endElevation = this.globe.getElevation(endLatLon.getLatitude(), endLatLon.getLongitude()); } else if (this.globe != null && this.altitudeMode == WorldWind.RELATIVE_TO_GROUND) { overrideEndElevation = true; endElevation = this.globe.getElevation(endLatLon.getLatitude(), endLatLon.getLongitude()) + end; } if (overrideEndElevation) { elevation = (1 - interpolant) * start + interpolant * endElevation; } return(elevation); }
/** * Create an animator to animate heading, pitch, and roll. * * @param view View to animate * @param beginHeading staring heading * @param endHeading final heading * @param beginPitch starting pitch * @param endPitch final pitch * @param beginRoll starting roll * @param endRoll final roll * * @return A CompoundAnimator to animate heading, pitch, and roll. */ public static CompoundAnimator createHeadingPitchRollAnimator(View view, Angle beginHeading, Angle endHeading, Angle beginPitch, Angle endPitch, Angle beginRoll, Angle endRoll) { if (beginHeading == null || endHeading == null || beginPitch == null || endPitch == null || beginRoll == null || endRoll == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new ArgumentException(message); } const long MIN_LENGTH_MILLIS = 500; const long MAX_LENGTH_MILLIS = 3000; long headingLengthMillis = AnimationSupport.getScaledTimeMillisecs( beginHeading, endHeading, Angle.POS180, MIN_LENGTH_MILLIS, MAX_LENGTH_MILLIS); long pitchLengthMillis = AnimationSupport.getScaledTimeMillisecs( beginPitch, endPitch, Angle.POS90, MIN_LENGTH_MILLIS, MAX_LENGTH_MILLIS / 2L); long rollLengthMillis = AnimationSupport.getScaledTimeMillisecs( beginRoll, endRoll, Angle.POS90, MIN_LENGTH_MILLIS, MAX_LENGTH_MILLIS / 2L); long lengthMillis = headingLengthMillis + pitchLengthMillis + rollLengthMillis; AngleAnimator headingAnimator = createHeadingAnimator(view, beginHeading, endHeading); AngleAnimator pitchAnimator = createPitchAnimator(view, beginPitch, endPitch); AngleAnimator rollAnimator = createRollAnimator(view, beginRoll, endRoll); CompoundAnimator headingPitchAnimator = new CompoundAnimator(new ScheduledInterpolator(lengthMillis), headingAnimator, pitchAnimator, rollAnimator); return(headingPitchAnimator); }
protected static double basicInterpolant(double interpolant, double startInterpolant, double stopInterpolant, int maxSmoothing) { var normalizedInterpolant = AnimationSupport.interpolantNormalized(interpolant, startInterpolant, stopInterpolant); return(AnimationSupport.interpolantSmoothed(normalizedInterpolant, maxSmoothing)); }
protected static double computeMidZoom( Globe globe, LatLon beginLatLon, LatLon endLatLon, double beginZoom, double endZoom) { // Scale factor is angular distance over 180 degrees. Angle sphericalDistance = LatLon.greatCircleDistance(beginLatLon, endLatLon); double scaleFactor = AnimationSupport.angularRatio(sphericalDistance, Angle.POS180); // Mid-point zoom is interpolated value between minimum and maximum zoom. double MIN_ZOOM = Math.Min(beginZoom, endZoom); double MAX_ZOOM = 3.0 * globe.getRadius(); return(AnimationSupport.mixDouble(scaleFactor, MIN_ZOOM, MAX_ZOOM)); }
/** * Create an animator to animate heading. * * @param view View to animate * @param begin starting heading * @param end final heading * * @return An Animator to animate heading. */ public static AngleAnimator createHeadingAnimator(View view, Angle begin, Angle end) { if (begin == null || end == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new ArgumentException(message); } const long MIN_LENGTH_MILLIS = 500; const long MAX_LENGTH_MILLIS = 3000; long lengthMillis = AnimationSupport.getScaledTimeMillisecs( begin, end, Angle.POS180, MIN_LENGTH_MILLIS, MAX_LENGTH_MILLIS); return(new AngleAnimator(new ScheduledInterpolator(lengthMillis), begin, end, new ViewPropertyAccessor.HeadingAccessor(view))); }
private double zoomInterpolant(double interpolant, double startInterpolant, double stopInterpolant, int maxSmoothing) { // Map interpolant in to range [start, stop]. double normalizedInterpolant = AnimationSupport.interpolantNormalized( interpolant, startInterpolant, stopInterpolant); // During first half of iteration, zoom increases from begin to mid, // and decreases from mid to end during second half. if (normalizedInterpolant <= 0.5) { normalizedInterpolant = (normalizedInterpolant * 2.0); } else { normalizedInterpolant = ((normalizedInterpolant - .5) * 2.0); } return(AnimationSupport.interpolantSmoothed(normalizedInterpolant, maxSmoothing)); }
protected Position nextPosition(double interpolant) { const int MAX_SMOOTHING = 1; double CENTER_START = this.useMidZoom ? 0.2 : 0.0; 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 = base.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; bool 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); }