/** * Compute the positions of the arrow head of the graphic's legs. * * @param dc Current draw context * @param base Position of the arrow's starting point. * @param tip Position of the arrow head tip. * @param arrowLength Length of the arrowhead as a fraction of the total line length. * @param arrowAngle Angle of the arrow head. * @return Positions required to draw the arrow head. */ protected List<Position> computeArrowheadPositions( DrawContext dc, Position base, Position tip, double arrowLength, Angle arrowAngle) { // Build a triangle to represent the arrowhead. The triangle is built from two vectors, one // parallel to the // segment, and one perpendicular to it. Globe globe = dc.getGlobe(); Vec4 ptA = globe.computePointFromPosition(base); Vec4 ptB = globe.computePointFromPosition(tip); // Compute parallel component Vec4 parallel = ptA.subtract3(ptB); Vec4 surfaceNormal = globe.computeSurfaceNormalAtPoint(ptB); // Compute perpendicular component Vec4 perpendicular = surfaceNormal.cross3(parallel); double finalArrowLength = arrowLength * parallel.getLength3(); double arrowHalfWidth = finalArrowLength * arrowAngle.tanHalfAngle(); perpendicular = perpendicular.normalize3().multiply3(arrowHalfWidth); parallel = parallel.normalize3().multiply3(finalArrowLength); // Compute geometry of direction arrow Vec4 vertex1 = ptB.add3(parallel).add3(perpendicular); Vec4 vertex2 = ptB.add3(parallel).subtract3(perpendicular); return TacticalGraphicUtil.asPositionList(globe, vertex1, vertex2, ptB); }
/** * Determine the positions that make up the arrowhead. * * @param dc Current draw context. * @param startPosition Position of the arrow's base. * @param endPosition Position of the arrow head tip. * @return Positions that define the arrowhead. */ protected List<Position> computeArrowheadPositions( DrawContext dc, Position startPosition, Position endPosition) { Globe globe = dc.getGlobe(); // Arrowhead looks like this: // _ // A\ | 1/2 width // ________B\ _| // Pt. 1 / // C/ // | | // Length Vec4 p1 = globe.computePointFromPosition(startPosition); Vec4 pB = globe.computePointFromPosition(endPosition); // Find vector in the direction of the arrow Vec4 vB1 = p1.subtract3(pB); double arrowLengthFraction = this.getArrowLength(); // Find the point at the base of the arrowhead Vec4 arrowBase = pB.add3(vB1.multiply3(arrowLengthFraction)); Vec4 normal = globe.computeSurfaceNormalAtPoint(arrowBase); // Compute the length of the arrowhead double arrowLength = vB1.getLength3() * arrowLengthFraction; double arrowHalfWidth = arrowLength * this.getArrowAngle().tanHalfAngle(); // Compute a vector perpendicular to the segment and the normal vector Vec4 perpendicular = vB1.cross3(normal); perpendicular = perpendicular.normalize3().multiply3(arrowHalfWidth); // Find points A and C Vec4 pA = arrowBase.add3(perpendicular); Vec4 pC = arrowBase.subtract3(perpendicular); return TacticalGraphicUtil.asPositionList(globe, pA, pB, pC); }
/** * Determines whether this sector intersects the specified geographic line segment. The line * segment is specified by a begin location and an end location. The locations are are assumed to * be connected by a linear path in geographic space. This returns true if any location along that * linear path intersects this sector, including the begin and end locations. * * @param begin the line segment begin location. * @param end the line segment end location. * @return true <code>true</code> if this sector intersects the line segment, otherwise <code> * false</code>. * @throws IllegalArgumentException if either the begin location or the end location is null. */ public boolean intersectsSegment(LatLon begin, LatLon end) { if (begin == null) { throw new IllegalArgumentException("Begin Is Null"); } if (end == null) { throw new IllegalArgumentException("End Is Null"); } Vec4 segmentBegin = new Vec4(begin.getLongitude().degrees, begin.getLatitude().degrees, 0); Vec4 segmentEnd = new Vec4(end.getLongitude().degrees, end.getLatitude().degrees, 0); Vec4 tmp = segmentEnd.subtract3(segmentBegin); Vec4 segmentCenter = segmentBegin.add3(segmentEnd).divide3(2); Vec4 segmentDirection = tmp.normalize3(); double segmentExtent = tmp.getLength3() / 2.0; LatLon centroid = this.getCentroid(); Vec4 boxCenter = new Vec4(centroid.getLongitude().degrees, centroid.getLatitude().degrees, 0); double boxExtentX = this.getDeltaLonDegrees() / 2.0; double boxExtentY = this.getDeltaLatDegrees() / 2.0; Vec4 diff = segmentCenter.subtract3(boxCenter); if (Math.abs(diff.x) > (boxExtentX + segmentExtent * Math.abs(segmentDirection.x))) { return false; } if (Math.abs(diff.y) > (boxExtentY + segmentExtent * Math.abs(segmentDirection.y))) { return false; } //noinspection SuspiciousNameCombination Vec4 segmentPerp = new Vec4(segmentDirection.y, -segmentDirection.x, 0); return Math.abs(segmentPerp.dot3(diff)) <= (boxExtentX * Math.abs(segmentPerp.x) + boxExtentY * Math.abs(segmentPerp.y)); }