protected List<Position> computePathPositions( Position startPosition, Position endPosition, Angle delta) { Angle dist = LatLon.greatCircleDistance(startPosition, endPosition); dist = dist.multiply(0.6); Angle azimuth = LatLon.greatCircleAzimuth(startPosition, endPosition); LatLon locA = LatLon.greatCircleEndPosition(startPosition, azimuth.add(delta), dist); dist = dist.multiply(0.9); LatLon locB = LatLon.greatCircleEndPosition(startPosition, azimuth.subtract(delta), dist); return Arrays.asList(startPosition, new Position(locA, 0), new Position(locB, 0), endPosition); }
@Test public void testAntipodalPointsB() { LatLon begin = LatLon.fromDegrees(-12.0, 87.0); double azimuthRadians = Math.toRadians(-90.0); double distanceRadians = Math.toRadians(180.0); LatLon end = LatLon.greatCircleEndPosition(begin, azimuthRadians, distanceRadians); assertEquals("Antipodal points B (lat)", 12.0, end.getLatitude().degrees, THRESHOLD); assertEquals("Antipodal points B (lon)", -93.0, end.getLongitude().degrees, THRESHOLD); }
@Test public void testAntipodalPointsA() { LatLon begin = LatLon.fromDegrees(53.0902505, 112.8935442); double azimuthRadians = Math.toRadians(-90.0); double distanceRadians = Math.toRadians(180.0); LatLon end = LatLon.greatCircleEndPosition(begin, azimuthRadians, distanceRadians); assertEquals("Antipodal points A (lat)", -53.0902505, end.getLatitude().degrees, THRESHOLD); assertEquals("Antipodal points A (lon)", -67.1064558, end.getLongitude().degrees, THRESHOLD); }
@Test public void testTrivialAzimuthB() { LatLon begin = LatLon.fromDegrees(0.0, 0.0); double azimuthRadians = Math.toRadians(90.0); double distanceRadians = Math.toRadians(360.0); LatLon end = LatLon.greatCircleEndPosition(begin, azimuthRadians, distanceRadians); assertEquals("Trivial Azimuth B (lat)", 0.0, end.getLatitude().degrees, THRESHOLD); assertEquals("Trivial Azimuth B (lon)", 0.0, end.getLongitude().degrees, THRESHOLD); }
@Test public void testKnownPointsB() { LatLon begin = LatLon.fromDegrees(53.0902505, 112.8935442); double azimuthRadians = Math.toRadians(-68.4055227); double distanceRadians = Math.toRadians(10.53630354); LatLon end = LatLon.greatCircleEndPosition(begin, azimuthRadians, distanceRadians); assertEquals("Known points B (lat)", 55.7426290038835, end.getLatitude().degrees, THRESHOLD); assertEquals( "Known points B (lon)", 95.313127193979270, end.getLongitude().degrees, THRESHOLD); }
protected void doMoveTo(Position oldReferencePosition, Position newReferencePosition) { java.util.ArrayList<LatLon> newLocations = new java.util.ArrayList<LatLon>(); for (LatLon ll : this.locations) { Angle heading = LatLon.greatCircleAzimuth(oldReferencePosition, ll); Angle pathLength = LatLon.greatCircleDistance(oldReferencePosition, ll); newLocations.add(LatLon.greatCircleEndPosition(newReferencePosition, heading, pathLength)); } this.setLocations(newLocations); }
@Test public void testKnownPointsA() { LatLon begin = LatLon.fromDegrees(-53.0902505, -67.1064558); double azimuthRadians = Math.toRadians(15.2204311); double distanceRadians = Math.toRadians(-88.7560694); LatLon end = LatLon.greatCircleEndPosition(begin, azimuthRadians, distanceRadians); assertEquals( "Known points A (lat)", -36.63477988750917, end.getLatitude().degrees, THRESHOLD); assertEquals( "Known points A (lon)", 131.98550742812412, end.getLongitude().degrees, THRESHOLD); }
/** * Compute the view range footprint on the globe. * * @param dc the current <code>DrawContext</code> * @param steps the number of steps. * @return an array list of <code>LatLon</code> forming a closed shape. */ protected ArrayList<LatLon> computeViewFootPrint(DrawContext dc, int steps) { ArrayList<LatLon> positions = new ArrayList<LatLon>(); Position eyePos = dc.getView().getEyePosition(); Angle distance = Angle.fromRadians( Math.asin( dc.getView().getFarClipDistance() / (dc.getGlobe().getRadius() + eyePos.getElevation()))); if (distance.degrees > 10) { double headStep = 360d / steps; Angle heading = Angle.ZERO; for (int i = 0; i <= steps; i++) { LatLon p = LatLon.greatCircleEndPosition(eyePos, heading, distance); positions.add(p); heading = heading.addDegrees(headStep); } return positions; } else return null; }
@Override protected void doMoveTo(Position oldReferencePosition, Position newReferencePosition) { if (this.boundaries.getContourCount() == 0) return; for (int i = 0; i < this.boundaries.getContourCount(); i++) { ArrayList<LatLon> newLocations = new ArrayList<LatLon>(); for (LatLon ll : this.boundaries.getContour(i)) { Angle heading = LatLon.greatCircleAzimuth(oldReferencePosition, ll); Angle pathLength = LatLon.greatCircleDistance(oldReferencePosition, ll); newLocations.add(LatLon.greatCircleEndPosition(newReferencePosition, heading, pathLength)); } this.boundaries.setContour(i, newLocations); } // We've changed the multi-polygon's list of boundaries; flag the shape as changed. this.onShapeChanged(); }
/** {@inheritDoc} */ @Override protected void determineLabelPositions(DrawContext dc) { Position center = this.getReferencePosition(); if (center == null) return; // Position the labels along a line radiating out from the center of the circle. The angle (60 // degrees) is // chosen to match the graphic template defined by MIL-STD-2525C, pg. 613. double globeRadius = dc.getGlobe().getRadius(); Angle labelAngle = this.getLabelAngle(); int i = 0; for (SurfaceCircle ring : this.rings) { double radius = ring.getRadius(); LatLon ll = LatLon.greatCircleEndPosition(center, labelAngle.radians, radius / globeRadius); this.labels.get(i).setPosition(new Position(ll, 0)); i += 1; } }
protected void doMoveTo(Position oldRef, Position newRef) { if (oldRef == null) { String message = "nullValue.OldRefIsNull"; Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (newRef == null) { String message = "nullValue.NewRefIsNull"; Logging.logger().severe(message); throw new IllegalArgumentException(message); } super.doMoveTo(oldRef, newRef); int count = this.locations.size(); LatLon[] newLocations = new LatLon[count]; for (int i = 0; i < count; i++) { LatLon ll = this.locations.get(i); double distance = LatLon.greatCircleDistance(oldRef, ll).radians; double azimuth = LatLon.greatCircleAzimuth(oldRef, ll).radians; newLocations[i] = LatLon.greatCircleEndPosition(newRef, azimuth, distance); } this.setLocations(Arrays.asList(newLocations)); }
/** * 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; }