diff --git a/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/MilStd2525GraphicFactory.java b/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/MilStd2525GraphicFactory.java index bab05832e..72c2c9b0c 100644 --- a/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/MilStd2525GraphicFactory.java +++ b/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/MilStd2525GraphicFactory.java @@ -106,8 +106,18 @@ protected void populateClassMap() DirectionOfAttack.FUNCTION_ID_SUPPORTING); this.mapClass(RectangularFireSupportArea.class, + RectangularFireSupportArea.FUNCTION_ID_FSA, RectangularFireSupportArea.FUNCTION_ID_FFA, - RectangularFireSupportArea.FUNCTION_ID_RFA); + RectangularFireSupportArea.FUNCTION_ID_RFA, + RectangularFireSupportArea.FUNCTION_ID_SENSOR_ZONE, + RectangularFireSupportArea.FUNCTION_ID_DEAD_SPACE_AREA, + RectangularFireSupportArea.FUNCTION_ID_ZONE_OF_RESPONSIBILITY, + RectangularFireSupportArea.FUNCTION_ID_TARGET_BUILDUP, + RectangularFireSupportArea.FUNCTION_ID_TARGET_VALUE, + RectangularFireSupportArea.FUNCTION_ID_ATI, + RectangularFireSupportArea.FUNCTION_ID_CFF, + RectangularFireSupportArea.FUNCTION_ID_CENSOR_ZONE, + RectangularFireSupportArea.FUNCTION_ID_CF); this.mapClass(CircularFireSupportArea.class, CircularFireSupportArea.FUNCTION_ID_TARGET, diff --git a/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/CircularFireSupportArea.java b/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/CircularFireSupportArea.java index 93d9615f9..b4342f09c 100644 --- a/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/CircularFireSupportArea.java +++ b/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/CircularFireSupportArea.java @@ -17,19 +17,12 @@ /** * Implementation of circular Fire Support graphics. This class implements the following graphics: - * - * + *

+ *

* * @author pabercrombie * @version $Id$ @@ -63,11 +56,31 @@ public class CircularFireSupportArea extends MilStd2525TacticalGraphic implement protected SurfaceCircle circle; protected Object delegateOwner; + /** Create a new circular area. */ public CircularFireSupportArea() { this.circle = this.createShape(); } + /** + * Indicates the function IDs of circular Fire Support area graphics that display a date/time range as a separate + * label at the left side of the circle. Whether or not a graphic supports this is determined by the graphic's + * template in MIL-STD-2525C. + * + * @return A Set containing the function IDs of graphics that support a date/time label separate from the graphic's + * main label. + */ + public static Set getGraphicsWithTimeLabel() + { + return new HashSet(Arrays.asList( + FUNCTION_ID_FSA, + FUNCTION_ID_SENSOR_ZONE, + FUNCTION_ID_DEAD_SPACE_AREA, + FUNCTION_ID_ZONE_OF_RESPONSIBILITY, + FUNCTION_ID_TARGET_BUILDUP, + FUNCTION_ID_TARGET_VALUE)); + } + /** {@inheritDoc} */ public String getCategory() { diff --git a/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/FireSupportTextBuilder.java b/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/FireSupportTextBuilder.java index eb0328389..4d7e50d51 100644 --- a/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/FireSupportTextBuilder.java +++ b/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/FireSupportTextBuilder.java @@ -40,17 +40,17 @@ public String[] createText(MilStd2525TacticalGraphic graphic) if (CircularFireSupportArea.FUNCTION_ID_TARGET.equals(functionId)) { // Circular Target just uses the Unique Designation as a label. - result = new String[] { graphic.getText() }; + result = new String[] {graphic.getText()}; } else if (IrregularFireSupportArea.FUNCTION_ID_BOMB.equals(functionId)) { // Bomb graphic just says "BOMB" - result = new String[] { "BOMB" }; + result = new String[] {"BOMB"}; } else if (IrregularFireSupportArea.FUNCTION_ID_TERMINALLY_GUIDED_MUNITIONS_FOOTPRINT.equals(functionId)) { // Terminally guided munitions footprint says "TGMF", and does not support modifiers. - result = new String[] { "TGMF" }; + result = new String[] {"TGMF"}; } else { @@ -70,11 +70,11 @@ else if (IrregularFireSupportArea.FUNCTION_ID_TERMINALLY_GUIDED_MUNITIONS_FOOTPR if (useSeparateTimeLabel) { String timeText = this.createTimeRangeText(graphic); - result = new String[] { mainText, timeText }; + result = new String[] {mainText, timeText}; } else { - result = new String[] { mainText }; + result = new String[] {mainText}; } } return result; @@ -82,12 +82,8 @@ else if (IrregularFireSupportArea.FUNCTION_ID_TERMINALLY_GUIDED_MUNITIONS_FOOTPR protected boolean isShowSeparateTimeLabel(String functionId) { - return CircularFireSupportArea.FUNCTION_ID_FSA.equals(functionId) - || CircularFireSupportArea.FUNCTION_ID_SENSOR_ZONE.equals(functionId) - || CircularFireSupportArea.FUNCTION_ID_DEAD_SPACE_AREA.equals(functionId) - || CircularFireSupportArea.FUNCTION_ID_ZONE_OF_RESPONSIBILITY.equals(functionId) - || CircularFireSupportArea.FUNCTION_ID_TARGET_BUILDUP.equals(functionId) - || CircularFireSupportArea.FUNCTION_ID_TARGET_VALUE.equals(functionId); + return CircularFireSupportArea.getGraphicsWithTimeLabel().contains(functionId) + || RectangularFireSupportArea.getGraphicsWithTimeLabel().contains(functionId); } protected boolean isAirspaceCoordinationArea(String functionId) @@ -159,30 +155,57 @@ else if (RectangularFireSupportArea.FUNCTION_ID_RFA.equals(functionId) { return "RFA"; } - else if (CircularFireSupportArea.FUNCTION_ID_FSA.equals(functionId)) + else if (RectangularFireSupportArea.FUNCTION_ID_FSA.equals(functionId) + || CircularFireSupportArea.FUNCTION_ID_FSA.equals(functionId)) { return "FSA"; } - else if (CircularFireSupportArea.FUNCTION_ID_SENSOR_ZONE.equals(functionId)) + else if (RectangularFireSupportArea.FUNCTION_ID_SENSOR_ZONE.equals(functionId) + || CircularFireSupportArea.FUNCTION_ID_SENSOR_ZONE.equals(functionId) + || IrregularFireSupportArea.FUNCTION_ID_SENSOR_ZONE.equals(functionId)) { return "SENSOR\nZONE"; } - else if (CircularFireSupportArea.FUNCTION_ID_DEAD_SPACE_AREA.equals(functionId)) + else if (RectangularFireSupportArea.FUNCTION_ID_DEAD_SPACE_AREA.equals(functionId) + || CircularFireSupportArea.FUNCTION_ID_DEAD_SPACE_AREA.equals(functionId) + || IrregularFireSupportArea.FUNCTION_ID_DEAD_SPACE_AREA.equals(functionId)) { return "DA"; } - else if (CircularFireSupportArea.FUNCTION_ID_ZONE_OF_RESPONSIBILITY.equals(functionId)) + else if (RectangularFireSupportArea.FUNCTION_ID_ZONE_OF_RESPONSIBILITY.equals(functionId) + || CircularFireSupportArea.FUNCTION_ID_ZONE_OF_RESPONSIBILITY.equals(functionId) + || IrregularFireSupportArea.FUNCTION_ID_ZONE_OF_RESPONSIBILITY.equals(functionId)) { return "ZOR"; } - else if (CircularFireSupportArea.FUNCTION_ID_TARGET_BUILDUP.equals(functionId)) + else if (RectangularFireSupportArea.FUNCTION_ID_TARGET_BUILDUP.equals(functionId) + || CircularFireSupportArea.FUNCTION_ID_TARGET_BUILDUP.equals(functionId) + || IrregularFireSupportArea.FUNCTION_ID_TARGET_BUILDUP.equals(functionId)) { return "TBA"; } - else if (CircularFireSupportArea.FUNCTION_ID_TARGET_VALUE.equals(functionId)) + else if (RectangularFireSupportArea.FUNCTION_ID_TARGET_VALUE.equals(functionId) + || CircularFireSupportArea.FUNCTION_ID_TARGET_VALUE.equals(functionId) + || IrregularFireSupportArea.FUNCTION_ID_TARGET_VALUE.equals(functionId)) { return "TVAR"; } + else if (RectangularFireSupportArea.FUNCTION_ID_ATI.equals(functionId)) + { + return "ATI ZONE"; + } + else if (RectangularFireSupportArea.FUNCTION_ID_CFF.equals(functionId)) + { + return "CFF ZONE"; + } + else if (RectangularFireSupportArea.FUNCTION_ID_CENSOR_ZONE.equals(functionId)) + { + return "CENSOR ZONE"; + } + else if (RectangularFireSupportArea.FUNCTION_ID_CF.equals(functionId)) + { + return "CF ZONE"; + } return ""; } @@ -238,5 +261,4 @@ protected String createAirspaceCoordinationText(MilStd2525TacticalGraphic graphi return sb.toString(); } - } diff --git a/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/IrregularFireSupportArea.java b/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/IrregularFireSupportArea.java index 5c9314862..aaed0a0a7 100644 --- a/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/IrregularFireSupportArea.java +++ b/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/IrregularFireSupportArea.java @@ -40,6 +40,16 @@ public class IrregularFireSupportArea extends BasicArea public final static String FUNCTION_ID_ACA = "ACAI--"; /** Function ID of the Terminally Guided Munitions Footprint graphic. */ public final static String FUNCTION_ID_TERMINALLY_GUIDED_MUNITIONS_FOOTPRINT = "ACT---"; + /** Function ID for the Sensor Zone graphic. */ + public final static String FUNCTION_ID_SENSOR_ZONE = "ACEI--"; + /** Function ID for the Dead Space Area graphic. */ + public final static String FUNCTION_ID_DEAD_SPACE_AREA = "ACDI--"; + /** Function ID for the Zone of Responsibility graphic. */ + public final static String FUNCTION_ID_ZONE_OF_RESPONSIBILITY = "ACZI--"; + /** Function ID for the Target Build-up Area graphic. */ + public final static String FUNCTION_ID_TARGET_BUILDUP = "ACBI--"; + /** Function ID for the Target Value Area graphic. */ + public final static String FUNCTION_ID_TARGET_VALUE = "ACVI--"; /** Center text block on label position when the text is left aligned. */ protected final static Offset LEFT_ALIGN_OFFSET = new Offset(-0.5d, -0.5d, AVKey.FRACTION, AVKey.FRACTION); diff --git a/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/RectangularFireSupportArea.java b/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/RectangularFireSupportArea.java index dc99ac606..285c6b128 100644 --- a/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/RectangularFireSupportArea.java +++ b/WorldWind/src/gov/nasa/worldwind/symbology/milstd2525/graphics/firesupport/areas/RectangularFireSupportArea.java @@ -17,24 +17,45 @@ /** * Implementation of rectangular Fire Support graphics. This class implements the following graphics: - * - * + *

+ *

* * @author pabercrombie * @version $Id$ */ public class RectangularFireSupportArea extends MilStd2525TacticalGraphic implements TacticalQuad, PreRenderable { + /** Function ID for the Fire Support Area graphic (2.X.4.3.2.1.2). */ + public final static String FUNCTION_ID_FSA = "ACSR--"; /** Function ID for the Free Fire Area graphic (2.X.4.3.2.3.2). */ public final static String FUNCTION_ID_FFA = "ACFR--"; /** Function ID for the Restrictive Fire Area graphic (2.X.4.3.2.5.2). */ public final static String FUNCTION_ID_RFA = "ACRR--"; /** Function ID for the Airspace Coordination Area graphic (2.X.4.3.2.2.2). */ public final static String FUNCTION_ID_ACA = "ACAR--"; + /** Function ID for the Sensor Zone graphic. */ + public final static String FUNCTION_ID_SENSOR_ZONE = "ACER--"; + /** Function ID for the Dead Space Area graphic. */ + public final static String FUNCTION_ID_DEAD_SPACE_AREA = "ACDR--"; + /** Function ID for the Zone of Responsibility graphic. */ + public final static String FUNCTION_ID_ZONE_OF_RESPONSIBILITY = "ACZR--"; + /** Function ID for the Target Build-up Area graphic. */ + public final static String FUNCTION_ID_TARGET_BUILDUP = "ACBR--"; + /** Function ID for the Target Value Area graphic. */ + public final static String FUNCTION_ID_TARGET_VALUE = "ACVR--"; + /** Function ID for the Artillery Target Intelligence Zone graphic (2.X.4.3.3.1.2). */ + public final static String FUNCTION_ID_ATI = "AZIR--"; + /** Function ID for the Call For Fire Zone graphic (2.X.4.3.3.2.2). */ + public final static String FUNCTION_ID_CFF = "AZXR--"; + /** Function ID for the Censor Zone graphic (2.X.4.3.3.4.2). */ + public final static String FUNCTION_ID_CENSOR_ZONE = "AZCR--"; + /** Function ID for the Critical Friendly Zone graphic (2.X.4.3.3.6.2). */ + public final static String FUNCTION_ID_CF = "AZFR--"; /** Center text block on label position when the text is left aligned. */ protected final static Offset LEFT_ALIGN_OFFSET = new Offset(-0.5d, -0.5d, AVKey.FRACTION, AVKey.FRACTION); @@ -50,6 +71,29 @@ public RectangularFireSupportArea() this.quad = this.createShape(); } + /** + * Indicates the function IDs of rectangular Fire Support area graphics that display a date/time range as a separate + * label at the left side of the rectangle. Whether or not a graphic supports this is determined by the graphic's + * template in MIL-STD-2525C. + * + * @return A Set containing the function IDs of graphics that support a date/time label separate from the graphic's + * main label. + */ + public static Set getGraphicsWithTimeLabel() + { + return new HashSet(Arrays.asList( + FUNCTION_ID_FSA, + FUNCTION_ID_SENSOR_ZONE, + FUNCTION_ID_DEAD_SPACE_AREA, + FUNCTION_ID_ZONE_OF_RESPONSIBILITY, + FUNCTION_ID_TARGET_BUILDUP, + FUNCTION_ID_TARGET_VALUE, + FUNCTION_ID_ATI, + FUNCTION_ID_CFF, + FUNCTION_ID_CENSOR_ZONE, + FUNCTION_ID_CF)); + } + /** {@inheritDoc} */ public String getCategory() { @@ -225,18 +269,48 @@ public void doRenderGraphic(DrawContext dc) protected void createLabels() { FireSupportTextBuilder textBuilder = new FireSupportTextBuilder(); - String text = textBuilder.createText(this)[0]; + String[] allText = textBuilder.createText(this); + + String text = allText[0]; if (!WWUtil.isEmpty(text)) { Label mainLabel = this.addLabel(text); mainLabel.setTextAlign(this.getMainLabelTextAlign()); } + + if (allText.length > 1) + { + Label timeLabel = this.addLabel(allText[1]); + timeLabel.setTextAlign(AVKey.RIGHT); + + // Align the upper right corner of the time label with the upper right corner of the quad. + timeLabel.setOffset(new Offset(0d, 0d, AVKey.FRACTION, AVKey.FRACTION)); + } } @Override protected void determineLabelPositions(DrawContext dc) { - this.labels.get(0).setPosition(new Position(this.quad.getCenter(), 0)); + Position center = new Position(this.quad.getCenter(), 0); + this.labels.get(0).setPosition(center); + + if (this.labels.size() > 1) + { + double hw = this.quad.getWidth() / 2.0; + double hh = this.quad.getHeight() / 2.0; + double globeRadius = dc.getGlobe().getRadiusAt(center.getLatitude(), center.getLongitude()); + double distance = Math.sqrt(hw * hw + hh * hh); + double pathLength = distance / globeRadius; + + // Find the upper left corner (looking the quad such that Point 1 is on the left and Point 2 is on the right, + // and the line between the two is horizontal, as the quad is pictured in the MIL-STD-2525C spec, pg. 652). + double cornerAngle = Math.atan2(-hh, hw); + double azimuth = (Math.PI / 2.0) - (cornerAngle - this.quad.getHeading().radians); + + LatLon corner = LatLon.greatCircleEndPosition(center, azimuth, pathLength); + + this.labels.get(1).setPosition(new Position(corner, 0)); + } } /** diff --git a/WorldWind/src/gov/nasa/worldwindx/examples/symbology/TacticalGraphics.java b/WorldWind/src/gov/nasa/worldwindx/examples/symbology/TacticalGraphics.java index 08aa265d1..61e52d92a 100644 --- a/WorldWind/src/gov/nasa/worldwindx/examples/symbology/TacticalGraphics.java +++ b/WorldWind/src/gov/nasa/worldwindx/examples/symbology/TacticalGraphics.java @@ -358,6 +358,20 @@ protected void createAreaGraphics(RenderableLayer layer) graphic.setText("GREEN"); graphic.setModifier(SymbologyConstants.DATE_TIME_GROUP, Arrays.asList("051030", "051600Z")); layer.addRenderable(graphic); + + //////////////////////////////////////////////////////////// + // Sensor Zone, Rectangular + //////////////////////////////////////////////////////////// + + positions = Arrays.asList( + Position.fromDegrees(35.0592, -117.2903, 0), + Position.fromDegrees(35.0620, -117.1606, 0)); + graphic = factory.createGraphic("GFFPACER------X", positions, null); + graphic.setModifier(SymbologyConstants.DISTANCE, 5000.0); + graphic.setValue(AVKey.DISPLAY_NAME, "Sensor Zone"); + graphic.setText("Q37"); + graphic.setModifier(SymbologyConstants.DATE_TIME_GROUP, Arrays.asList("051030", "051600Z")); + layer.addRenderable(graphic); } }