/** * Subdivide a list of positions so that no segment is longer then the provided maxLength. Only * the positions between start and start + count - 1 will be processed. * * <p>If needed, new intermediate positions will be created along lines that follow the given * pathType - one of Polyline.LINEAR, Polyline.RHUMB_LINE or Polyline.GREAT_CIRCLE. All position * elevations will be either at the terrain surface if followTerrain is true, or interpolated * according to the original elevations. * * @param globe the globe to draw elevations and points from. * @param positions the original position list * @param maxLength the maximum length for one segment. * @param followTerrain true if the positions should be on the terrain surface. * @param pathType the type of path to use in between two positions. * @param start the first position indice in the original list. * @param count how many positions from the original list have to be processed and returned. * @return a list of positions with no segment longer then maxLength and elevations following * terrain or not. */ protected static ArrayList<? extends Position> subdividePositions( Globe globe, ArrayList<? extends Position> positions, double maxLength, boolean followTerrain, String pathType, int start, int count) { if (positions == null || positions.size() < start + count) return positions; ArrayList<Position> newPositions = new ArrayList<Position>(); // Add first position Position pos1 = positions.get(start); if (followTerrain) newPositions.add( new Position(pos1, globe.getElevation(pos1.getLatitude(), pos1.getLongitude()))); else newPositions.add(pos1); for (int i = 1; i < count; i++) { Position pos2 = positions.get(start + i); double arcLengthRadians = LatLon.greatCircleDistance(pos1, pos2).radians; double arcLength = arcLengthRadians * globe.getRadiusAt(LatLon.interpolate(.5, pos1, pos2)); if (arcLength > maxLength) { // if necessary subdivide segment at regular intervals smaller then maxLength Angle segmentAzimuth = null; Angle segmentDistance = null; int steps = (int) Math.ceil(arcLength / maxLength); // number of intervals - at least two for (int j = 1; j < steps; j++) { float s = (float) j / steps; LatLon destLatLon; if (pathType.equals(AVKey.LINEAR)) { destLatLon = LatLon.interpolate(s, pos1, pos2); } else if (pathType.equals(AVKey.RHUMB_LINE)) { if (segmentAzimuth == null) { segmentAzimuth = LatLon.rhumbAzimuth(pos1, pos2); segmentDistance = LatLon.rhumbDistance(pos1, pos2); } destLatLon = LatLon.rhumbEndPosition(pos1, segmentAzimuth.radians, s * segmentDistance.radians); } else // GREAT_CIRCLE { if (segmentAzimuth == null) { segmentAzimuth = LatLon.greatCircleAzimuth(pos1, pos2); segmentDistance = LatLon.greatCircleDistance(pos1, pos2); } destLatLon = LatLon.greatCircleEndPosition( pos1, segmentAzimuth.radians, s * segmentDistance.radians); } // Set elevation double elevation; if (followTerrain) elevation = globe.getElevation(destLatLon.getLatitude(), destLatLon.getLongitude()); else elevation = pos1.elevation * (1 - s) + pos2.elevation * s; // Add new position newPositions.add(new Position(destLatLon, elevation)); } } // Finally add the segment end position if (followTerrain) newPositions.add( new Position(pos2, globe.getElevation(pos2.getLatitude(), pos2.getLongitude()))); else newPositions.add(pos2); // Prepare for next segment pos1 = pos2; } return newPositions; }