@Override public boolean handleMessage(Message msg) { if (this.animationAmount < 1) { // Increment the animation amount. this.animationAmount += this.animationIncrement; for (int idx = 0, len = this.flightPathLayer.count(); idx < len; idx++) { // Identify the departure airport and destination airport associated with each flight path. Path path = (Path) this.flightPathLayer.getRenderable(idx); Airport dept = (Airport) path.getUserProperty("dept"); Airport dest = (Airport) path.getUserProperty("dest"); // Compute the location on the great circle path between the departure and the destination that // corresponds to the animation amount. Position nextPos = dept.pos.interpolateAlongPath(dest.pos, WorldWind.GREAT_CIRCLE, this.animationAmount, new Position()); // Compute the altitude on the flight path that corresponds to the animation amount. We mock altitude // using an inverse parabolic function scaled to reach a max altitude of 10% of the flight distance. double dist = dept.pos.greatCircleDistance(dest.pos) * this.getWorldWindow().getGlobe().getEquatorialRadius(); double altCurve = (1 - this.animationAmount) * this.animationAmount * 4; nextPos.altitude = altCurve * dist * 0.1; // Append the location and altitude to the flight path's list of positions. List<Position> positions = path.getPositions(); positions.add(nextPos); path.setPositions(positions); } // Redraw the WorldWindow to display the changes. this.getWorldWindow().requestRedraw(); // Continue the animation after a delay. this.handler.sendEmptyMessageDelayed(0 /*what*/, 1000); } return false; }