@Test public void testTrivialEquivalentPointsC() { LatLon begin = LatLon.fromDegrees(90.0, 0.0); LatLon end = LatLon.fromDegrees(90.0, 0.0); double azimuth = LatLon.greatCircleAzimuth(begin, end).degrees; assertEquals("Trivial equivalent points C", 0.0, azimuth, THRESHOLD); }
@Test public void testKnownAzimuthE() { LatLon begin = LatLon.fromDegrees(-12.0, 87.0); LatLon end = LatLon.fromDegrees(53.0902505, -67.1064558); double azimuth = LatLon.greatCircleAzimuth(begin, end).degrees; assertEquals("Known Azimuth E", -21.38356223882703, azimuth, THRESHOLD); }
@Test public void testKnownAzimuthC() { LatLon begin = LatLon.fromDegrees(-12.0, 87.0); LatLon end = LatLon.fromDegrees(-12.0000001, 86.9999999); double azimuth = LatLon.greatCircleAzimuth(begin, end).degrees; assertEquals("Known Azimuth C", -135.6329170237546, azimuth, THRESHOLD); }
@Test public void testKnownAzimuthD() { LatLon begin = LatLon.fromDegrees(-12.0, 87.0); LatLon end = LatLon.fromDegrees(11.9999999, -93.0000001); double azimuth = LatLon.greatCircleAzimuth(begin, end).degrees; assertEquals("Known Azimuth D", 135.6329170162944, azimuth, THRESHOLD); }
@Test public void testKnownAzimuthB() { LatLon begin = LatLon.fromDegrees(53.0902505, 112.8935442); LatLon end = LatLon.fromDegrees(-53.0902505, -67.1064558); double azimuth = LatLon.greatCircleAzimuth(begin, end).degrees; assertEquals("Known Azimuth B", -90.0, azimuth, THRESHOLD); }
@Test public void testKnownAzimuthA() { LatLon begin = LatLon.fromDegrees(-90.0, -180.0); LatLon end = LatLon.fromDegrees(90.0, 180.0); double azimuth = LatLon.greatCircleAzimuth(begin, end).degrees; assertEquals("Known Azimuth A", 0.0, azimuth, THRESHOLD); }
@Test public void testEquivalentPoints() { LatLon begin = LatLon.fromDegrees(53.0902505, 112.8935442); LatLon end = LatLon.fromDegrees(53.0902505, 112.8935442); double azimuth = LatLon.greatCircleAzimuth(begin, end).degrees; assertEquals("Equivalent points", 0.0, azimuth, THRESHOLD); }
/** * {@inheritDoc} * * @param positions Control points. This graphic uses only two control point, which determine the * midpoints of two opposite sides of the quad. See Fire Support Area (2.X.4.3.2.1.2) on pg. * 652 of MIL-STD-2525C for an example of how these points are interpreted. */ public void setPositions(Iterable<? extends Position> positions) { if (positions == null) { String message = Logging.getMessage("nullValue.PositionsListIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } Iterator<? extends Position> iterator = positions.iterator(); try { Position pos1 = iterator.next(); Position pos2 = iterator.next(); LatLon center = LatLon.interpolateGreatCircle(0.5, pos1, pos2); this.quad.setCenter(center); Angle heading = LatLon.greatCircleAzimuth(pos2, pos1); this.quad.setHeading(heading.subtract(Angle.POS90)); this.positions = positions; this.shapeInvalid = true; // Need to recompute quad size } catch (NoSuchElementException e) { String message = Logging.getMessage("generic.InsufficientPositions"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } }
@Test public void testTrivialWest() { LatLon begin = LatLon.fromDegrees(0.0, 0.0); LatLon end = LatLon.fromDegrees(0.0, -90.0); double azimuth = LatLon.greatCircleAzimuth(begin, end).degrees; assertEquals("Trivial West greatCircleAzimuth", -90.0, azimuth, 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 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); }
/** * Create the list of positions that describe the arrow. * * @param dc Current draw context. */ protected void createShapes(DrawContext dc) { this.paths = new Path[2]; int i = 0; Angle azimuth1 = LatLon.greatCircleAzimuth(this.position1, this.position2); Angle azimuth2 = LatLon.greatCircleAzimuth(this.position1, this.position3); Angle delta = azimuth2.subtract(azimuth1); int sign = delta.degrees > 0 ? 1 : -1; delta = Angle.fromDegrees(sign * 5.0); // Create a path for the line part of the arrow List<Position> positions = this.computePathPositions(this.position1, this.position2, delta); this.paths[i++] = this.createPath(positions); // Create a polygon to draw the arrow head. double arrowLength = this.getArrowLength(); Angle arrowAngle = this.getArrowAngle(); positions = this.computeArrowheadPositions( dc, positions.get(2), positions.get(3), arrowLength, arrowAngle); this.arrowHead1 = this.createPolygon(positions); this.arrowHead1.setLocations(positions); delta = delta.multiply(-1.0); positions = this.computePathPositions(this.position1, this.position3, delta); this.paths[i] = this.createPath(positions); positions = this.computeArrowheadPositions( dc, positions.get(2), positions.get(3), arrowLength, arrowAngle); this.arrowHead2 = this.createPolygon(positions); this.arrowHead2.setLocations(positions); }
@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(); }
protected void setCursor(MeasureTool.ControlPoint controlPoint) { // TODO: handle 'rotating' mode cursor is this.isRotating() - when using Alt key on regular // shapes if (controlPoint == null) { setComponentCursor(null); } else { if (this.measureTool.isRegularShape()) { if (this.measureTool.isCornerControl(controlPoint)) { Angle azimuth = LatLon.greatCircleAzimuth( controlPoint.getPosition(), this.measureTool.getCenterPosition()); // Account for view heading in cursor selection azimuth = azimuth.subtract(this.measureTool.getWwd().getView().getHeading()); setComponentCursor(selectResizeCursor(azimuth)); } else if (this.measureTool.isCenterControl(controlPoint)) { setComponentCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); } } else { // Line, path and polygon setComponentCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); } } }
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); }
protected Angle computeHeading(Position pa, Position pb) { return LatLon.greatCircleAzimuth(pa, pb); }
/** * 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; }