All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.gov.nasa.worldwind.symbology.milstd2525.graphics.lines.DirectionOfAttack Maven / Gradle / Ivy

Go to download

World Wind is a collection of components that interactively display 3D geographic information within Java applications or applets.

There is a newer version: 2.0.0-986
Show newest version
/*
 * Copyright (C) 2012 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */

package gov.nasa.worldwind.symbology.milstd2525.graphics.lines;

import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.render.*;
import gov.nasa.worldwind.symbology.TacticalGraphicUtil;
import gov.nasa.worldwind.symbology.milstd2525.AbstractMilStd2525TacticalGraphic;
import gov.nasa.worldwind.symbology.milstd2525.graphics.TacGrpSidc;
import gov.nasa.worldwind.util.Logging;

import java.util.*;

/**
 * Direction of Attack graphics. This class implements the following graphics:
 * 

*

  • Direction of Main Attack graphic (2.X.2.5.2.2.2.1)
  • Direction of Supporting Attack graphic * (2.X.2.5.2.2.2.2)
* * @author pabercrombie * @version $Id: DirectionOfAttack.java 1171 2013-02-11 21:45:02Z dcollins $ */ public class DirectionOfAttack extends AbstractMilStd2525TacticalGraphic { /** Default length of the arrowhead, as a fraction of the total line length. */ public final static double DEFAULT_ARROWHEAD_LENGTH = 0.1; /** Default angle of the arrowhead. */ public final static Angle DEFAULT_ARROWHEAD_ANGLE = Angle.fromDegrees(60.0); /** Default width of the arrowhead outline. */ public final static double DEFAULT_ARROWHEAD_OUTLINE_WIDTH = 0.3; /** Length of the arrowhead from base to tip, as a fraction of the total line length. */ protected Angle arrowAngle = DEFAULT_ARROWHEAD_ANGLE; /** Angle of the arrowhead. */ protected double arrowLength = DEFAULT_ARROWHEAD_LENGTH; /** Width of the arrowhead outline, as a fraction of the arrowhead length. */ protected double outlineWidth = DEFAULT_ARROWHEAD_OUTLINE_WIDTH; /** First control point. */ protected Position startPosition; /** Second control point. */ protected Position endPosition; /** Path used to render the line. */ protected Path[] paths; /** * Indicates the graphics supported by this class. * * @return List of masked SIDC strings that identify graphics that this class supports. */ public static List getSupportedGraphics() { return Arrays.asList( TacGrpSidc.C2GM_OFF_LNE_DIRATK_GRD_MANATK, TacGrpSidc.C2GM_OFF_LNE_DIRATK_GRD_SUPATK ); } /** * Create a new arrow graphic. * * @param sidc Symbol code the identifies the graphic. */ public DirectionOfAttack(String sidc) { super(sidc); } /** * Indicates the angle of the arrowhead. * * @return Angle of the arrowhead in the graphic. */ public Angle getArrowAngle() { return this.arrowAngle; } /** * Specifies the angle of the arrowhead in the graphic. * * @param arrowAngle The angle of the arrowhead. Must be greater than zero degrees and less than 90 degrees. */ public void setArrowAngle(Angle arrowAngle) { if (arrowAngle == null) { String msg = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } if (arrowAngle.degrees <= 0) { String msg = Logging.getMessage("generic.AngleOutOfRange"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } this.arrowAngle = arrowAngle; } /** * Indicates the length of the arrowhead. * * @return The length of the arrowhead as a fraction of the total line length. */ public double getArrowLength() { return this.arrowLength; } /** * Specifies the length of the arrowhead. * * @param arrowLength Length of the arrowhead as a fraction of the total line length. If the arrowhead length is * 0.25, then the arrowhead length will be one quarter of the total line length. */ public void setArrowLength(double arrowLength) { if (arrowLength < 0) { String msg = Logging.getMessage("generic.ArgumentOutOfRange"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } this.arrowLength = arrowLength; } /** * Indicates the width of the arrowhead when it is drawn outlined. Note that the arrowhead is only drawn outlined * when the graphic represents a Main Direction of Attack. * * @return Width of the outline as a fraction of the arrowhead length. */ public double getOutlineWidth() { return this.outlineWidth; } /** * Specifies the width of the the arrowhead when it is drawn outlined. Note that the arrowhead is only drawn * outlined when the graphic represents a Main Direction of Attack. * * @param outlineWidth Width of the outline as a fraction of the length of the arrowhead. */ public void setOutlineWidth(double outlineWidth) { if (outlineWidth < 0) { String msg = Logging.getMessage("generic.ArgumentOutOfRange"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } this.outlineWidth = outlineWidth; } /** * {@inheritDoc} * * @param positions Control points that orient the graphic. Must provide at least three points. */ public void setPositions(Iterable positions) { if (positions == null) { String message = Logging.getMessage("nullValue.PositionsListIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } try { Iterator iterator = positions.iterator(); this.endPosition = iterator.next(); this.startPosition = iterator.next(); } catch (NoSuchElementException e) { String message = Logging.getMessage("generic.InsufficientPositions"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.paths = null; // Need to recompute path for the new control points } /** {@inheritDoc} */ public Iterable getPositions() { return Arrays.asList(this.endPosition, this.startPosition); } /** {@inheritDoc} */ public Position getReferencePosition() { return this.startPosition; } /** {@inheritDoc} */ protected void doRenderGraphic(DrawContext dc) { for (Path path : this.paths) { path.render(dc); } } @Override protected void computeGeometry(DrawContext dc) { if (this.paths == null) { this.createShapes(dc); } super.computeGeometry(dc); } /** {@inheritDoc} */ protected void applyDelegateOwner(Object owner) { if (this.paths == null) return; for (Path path : this.paths) { path.setDelegateOwner(owner); } } /** * Indicates whether or not to draw the arrow head outlined. * * @return {@code true} if the arrow head should be drawn outlined. */ protected boolean isDrawOutlined() { // Draw the arrow head outlined if this is a Main Attack graphic. return TacGrpSidc.C2GM_OFF_LNE_DIRATK_GRD_MANATK.equalsIgnoreCase(this.maskedSymbolCode); } /** * Create the list of positions that describe the arrow. * * @param dc Current draw context. */ protected void createShapes(DrawContext dc) { this.paths = new Path[2]; // Create a path for the line part of the arrow this.paths[0] = this.createPath(Arrays.asList(this.startPosition, this.endPosition)); // Create the arrowhead Globe globe = dc.getGlobe(); Vec4 p1 = globe.computePointFromPosition(this.startPosition); Vec4 p2 = globe.computePointFromPosition(this.endPosition); // Find vector in the direction of the arrow Vec4 v21 = p1.subtract3(p2); double arrowheadLength = v21.getLength3() * this.getArrowLength(); List positions = this.computeArrowheadPositions(dc, p2, v21, arrowheadLength); this.paths[1] = createPath(positions); } /** * Determine the positions that make up the arrowhead. * * @param dc Current draw context. * @param tip Point at the tip of the arrow head. * @param dir Vector in the direction of the arrow head. * @param length Length of the arrowhead from base to tip. * * @return Positions that define the arrowhead. */ protected List computeArrowheadPositions(DrawContext dc, Vec4 tip, Vec4 dir, double length) { Globe globe = dc.getGlobe(); // The arrowhead is drawn outlined for the Main Attack graphic, and as a single line for the Supporting Attack // graphic. When outlined, we need points A, B, C, D, E, and F. When not outlined the arrowhead is just points // A, B, and C. // // F _ // |\ | // A\ \ | 1/2 width // ________B\ \ E _| // Pt. 1 / / // C/ / // |/ // D // | | // Length @SuppressWarnings({"UnnecessaryLocalVariable"}) Vec4 ptB = tip; // Compute the length of the arrowhead double arrowHalfWidth = length * this.getArrowAngle().tanHalfAngle(); dir = dir.normalize3(); // Find the point at the base of the arrowhead Vec4 arrowBase = ptB.add3(dir.multiply3(length)); Vec4 normal = globe.computeSurfaceNormalAtPoint(arrowBase); // Compute a vector perpendicular to the segment and the normal vector Vec4 perpendicular = dir.cross3(normal); perpendicular = perpendicular.normalize3().multiply3(arrowHalfWidth); // Find points A and C Vec4 ptA = arrowBase.add3(perpendicular); Vec4 ptC = arrowBase.subtract3(perpendicular); List positions; if (this.isDrawOutlined()) { double outlineWidth = this.getOutlineWidth(); // Find points D and F perpendicular = perpendicular.multiply3(1 + outlineWidth); Vec4 ptF = arrowBase.add3(perpendicular); Vec4 ptD = arrowBase.subtract3(perpendicular); Vec4 ptE = ptB.subtract3(dir.multiply3(length * outlineWidth)); positions = TacticalGraphicUtil.asPositionList(globe, ptA, ptB, ptC, ptD, ptE, ptF, ptA); } else { positions = TacticalGraphicUtil.asPositionList(globe, ptA, ptB, ptC); } return positions; } /** * Create and configure the Path used to render this graphic. * * @param positions Positions that define the path. * * @return New path configured with defaults appropriate for this type of graphic. */ protected Path createPath(List positions) { Path path = new Path(positions); path.setFollowTerrain(true); path.setPathType(AVKey.GREAT_CIRCLE); path.setAltitudeMode(WorldWind.CLAMP_TO_GROUND); path.setDelegateOwner(this.getActiveDelegateOwner()); path.setAttributes(this.getActiveShapeAttributes()); return path; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy