@Test public void testAntipodalPointsA() { LatLon begin = LatLon.fromDegrees(53.0902505, 112.8935442); LatLon end = LatLon.fromDegrees(-53.0902505, -67.1064558); double distance = LatLon.greatCircleDistance(begin, end).degrees; assertEquals("Antipodal points A", 180.0, distance, THRESHOLD); }
@Test public void testAntipodalPointsB() { LatLon begin = LatLon.fromDegrees(-12.0, 87.0); LatLon end = LatLon.fromDegrees(12.0, -93.0); double distance = LatLon.greatCircleDistance(begin, end).degrees; assertEquals("Antipodal points B", 180.0, distance, THRESHOLD); }
@Test public void testEquivalentPoints() { LatLon begin = LatLon.fromDegrees(53.0902505, 112.8935442); LatLon end = LatLon.fromDegrees(53.0902505, 112.8935442); double distance = LatLon.greatCircleDistance(begin, end).degrees; assertEquals("Equivalent points", 0.0, distance, THRESHOLD); }
@Test public void testTrivialAntipodalPointsC() { LatLon begin = LatLon.fromDegrees(-90.0, -180.0); LatLon end = LatLon.fromDegrees(90.0, 180.0); double distance = LatLon.greatCircleDistance(begin, end).degrees; assertEquals("Trivial antipodal points C", 180.0, distance, THRESHOLD); }
@Test public void testTrivialEquivalentPointsC() { LatLon begin = LatLon.fromDegrees(0.0, 0.0); LatLon end = LatLon.fromDegrees(0.0, 360.0); double distance = LatLon.greatCircleDistance(begin, end).degrees; assertEquals("Trivial equivalent points C", 0.0, distance, THRESHOLD); }
@Test public void testProblemPointsA() { LatLon begin = LatLon.fromDegrees(36.0, -118.0); LatLon end = LatLon.fromDegrees(36.0, -117.0); double distance = LatLon.greatCircleDistance(begin, end).degrees; assertEquals("Problem points A", 0.8090134466773318, distance, THRESHOLD); }
@Test public void testKnownDistanceCloseTo180() { LatLon begin = LatLon.fromDegrees(-12.0, 87.0); LatLon end = LatLon.fromDegrees(11.9999999, -93.0000001); double distance = LatLon.greatCircleDistance(begin, end).degrees; assertEquals("Known spherical distance (close to 180)", 180.0, distance, THRESHOLD); }
@Test public void testKnownDistance() { LatLon begin = LatLon.fromDegrees(90.0, 45.0); LatLon end = LatLon.fromDegrees(36.0, 180.0); double distance = LatLon.greatCircleDistance(begin, end).degrees; assertEquals("Known spherical distance", 54.0, distance, THRESHOLD); }
@Test public void testKnownDistanceCloseToZero() { LatLon begin = LatLon.fromDegrees(-12.0, 87.0); LatLon end = LatLon.fromDegrees(-12.0000001, 86.9999999); double distance = LatLon.greatCircleDistance(begin, end).degrees; assertEquals( "Known spherical distance (close to zero)", 1.3988468832247915e-7, distance, 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); }
protected void computeQuadSize(DrawContext dc) { if (this.positions == null) return; Iterator<? extends Position> iterator = this.positions.iterator(); Position pos1 = iterator.next(); Position pos2 = iterator.next(); Angle angularDistance = LatLon.greatCircleDistance(pos1, pos2); double length = angularDistance.radians * dc.getGlobe().getRadius(); this.quad.setWidth(length); }
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); }
@SuppressWarnings({"UnusedDeclaration"}) protected void doMoved(PositionEvent event) { if (this.active && rubberBandTarget != null && this.measureTool.getWwd().getObjectsAtCurrentPosition() != null && this.measureTool.getWwd().getObjectsAtCurrentPosition().getTerrainObject() != null) { if (!isFreeHand() || (!measureTool.getMeasureShapeType().equals(MeasureTool.SHAPE_PATH) && !measureTool.getMeasureShapeType().equals(MeasureTool.SHAPE_POLYGON))) { // Rubber band - Move control point and update shape Position lastPosition = rubberBandTarget.getPosition(); PickedObjectList pol = measureTool.getWwd().getObjectsAtCurrentPosition(); PickedObject to = pol.getTerrainObject(); rubberBandTarget.setPosition(new Position(to.getPosition(), 0)); measureTool.moveControlPoint(rubberBandTarget); measureTool.firePropertyChange( MeasureTool.EVENT_POSITION_REPLACE, lastPosition, rubberBandTarget.getPosition()); measureTool.getWwd().redraw(); } else { // Free hand - Compute distance from current control point (rubber band target) Position lastPosition = rubberBandTarget.getPosition(); Position newPosition = measureTool.getWwd().getCurrentPosition(); double distance = LatLon.greatCircleDistance(lastPosition, newPosition).radians * measureTool.getWwd().getModel().getGlobe().getRadius(); if (distance >= freeHandMinSpacing) { // Add new control point measureTool.addControlPoint(); rubberBandTarget = (MeasureTool.ControlPoint) getMeasureTool() .getControlPoints() .get(getMeasureTool().getControlPoints().size() - 1); measureTool.getWwd().redraw(); } } } else if (this.moving && movingTarget != null && measureTool.getWwd().getCurrentPosition() != null) { // Moving the whole shape Position lastPosition = movingTarget.getPosition(); Position newPosition = measureTool.getWwd().getCurrentPosition(); this.moveToPosition(lastPosition, newPosition); // Update the tool tip to follow the shape as it moves. if (measureTool.isShowAnnotation()) measureTool.updateAnnotation(movingTarget.getPosition()); measureTool.getWwd().redraw(); } }
@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(); }
/** * Create the circles used to draw this graphic. * * @param dc Current draw context. */ protected void createShapes(DrawContext dc) { if (this.positions == null) return; this.rings = new ArrayList<SurfaceCircle>(); Iterator<? extends Position> iterator = this.positions.iterator(); Position center = iterator.next(); double globeRadius = dc.getGlobe().getRadius(); while (iterator.hasNext()) { SurfaceCircle ring = this.createCircle(); ring.setCenter(center); Position pos = iterator.next(); Angle radius = LatLon.greatCircleDistance(center, pos); double radiusMeters = radius.radians * globeRadius; ring.setRadius(radiusMeters); this.rings.add(ring); } }
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)); }
/** * Move the shape to the specified new position * * @param oldPosition Previous position of shape * @param newPosition New position for shape */ protected void moveToPosition(Position oldPosition, Position newPosition) { Angle distanceAngle = LatLon.greatCircleDistance(oldPosition, newPosition); Angle azimuthAngle = LatLon.greatCircleAzimuth(oldPosition, newPosition); measureTool.moveMeasureShape(azimuthAngle, distanceAngle); measureTool.firePropertyChange(MeasureTool.EVENT_POSITION_REPLACE, oldPosition, newPosition); }
/** * 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; }