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

gov.nasa.worldwind.symbology.milstd2525.MilStd2525Util Maven / Gradle / Ivy

The 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;

import gov.nasa.worldwind.View;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.render.*;
import gov.nasa.worldwind.symbology.SymbologyConstants;
import gov.nasa.worldwind.util.Logging;

import java.awt.geom.*;
import java.util.*;

/**
 * @author dcollins
 * @version $Id: MilStd2525Util.java 1171 2013-02-11 21:45:02Z dcollins $
 */
public class MilStd2525Util
{
    protected static final Offset CLOVER_OFFSET = Offset.fromFraction(0.0625, 0.0625);
    protected static final Size CLOVER_SIZE = Size.fromFraction(0.890625, 0.890625);
    protected static final Offset CLOVER_C2_HQ_OFFSET = Offset.fromFraction(0.0, -0.0546875);

    protected static final Offset CLOVER_UP_OFFSET = Offset.fromFraction(0.03125, 0.1875);
    protected static final Size CLOVER_UP_SIZE = Size.fromFraction(0.9375, 0.8046875);

    protected static final Offset CLOVER_DOWN_OFFSET = Offset.fromFraction(0.03125, 0.0078125);
    protected static final Size CLOVER_DOWN_SIZE = Size.fromFraction(0.9375, 0.8046875);

    protected static final Offset ARCH_UP_OFFSET = Offset.fromFraction(0.15625, 0.1953125);
    protected static final Size ARCH_UP_SIZE = Size.fromFraction(0.6875, 0.734375);

    protected static final Offset ARCH_DOWN_OFFSET = Offset.fromFraction(0.15625, 0.0703125);
    protected static final Size ARCH_DOWN_SIZE = Size.fromFraction(0.6875, 0.734375);

    protected static final Offset CIRCLE_OFFSET = Offset.fromFraction(0.125, 0.125);
    protected static final Size CIRCLE_SIZE = Size.fromFraction(0.75, 0.75);

    protected static final Offset RECTANGLE_OFFSET = Offset.fromFraction(0.0390625, 0.1875);
    protected static final Size RECTANGLE_SIZE = Size.fromFraction(0.921875, 0.625);
    protected static final Offset RECTANGLE_C2_HQ_OFFSET = Offset.fromFraction(0.0, -0.3);

    protected static final Offset HAT_UP_OFFSET = Offset.fromFraction(0.15625, 0.1953125);
    protected static final Size HAT_UP_SIZE = Size.fromFraction(0.6875, 0.734375);

    protected static final Offset HAT_DOWN_OFFSET = Offset.fromFraction(0.15625, 0.0703125);
    protected static final Size HAT_DOWN_SIZE = Size.fromFraction(0.6875, 0.734375);

    protected static final Offset SQUARE_OFFSET = Offset.fromFraction(0.15625, 0.15625);
    protected static final Size SQUARE_SIZE = Size.fromFraction(0.6875, 0.6875);
    protected static final Offset SQUARE_C2_HQ_OFFSET = Offset.fromFraction(0.0, -0.22728);

    protected static final Offset TENT_UP_OFFSET = Offset.fromFraction(0.15625, 0.1875);
    protected static final Size TENT_UP_SIZE = Size.fromFraction(0.6875, 0.8046875);

    protected static final Offset TENT_DOWN_OFFSET = Offset.fromFraction(0.15625, 0.0);
    protected static final Size TENT_DOWN_SIZE = Size.fromFraction(0.6875, 0.8046875);

    protected static final Offset DIAMOND_OFFSET = Offset.fromFraction(0.046875, 0.046875);
    protected static final Size DIAMOND_SIZE = Size.fromFraction(0.90625, 0.90625);
    protected static final Offset DIAMOND_C2_HQ_OFFSET = Offset.fromFraction(0.0, -0.05172);

    public static class SymbolInfo
    {
        public Offset iconOffset;
        public Size iconSize;
        public Offset offset;
        public boolean isGroundSymbol;
    }

    public static SymbolInfo computeTacticalSymbolInfo(String symbolId)
    {
        if (symbolId == null)
        {
            String msg = Logging.getMessage("nullValue.SymbolCodeIsNull");
            Logging.logger().severe(msg);
            throw new IllegalArgumentException(msg);
        }

        SymbolCode symbolCode = new SymbolCode(symbolId);
        SymbolInfo symbolInfo = new SymbolInfo();

        String scheme = symbolCode.getScheme();
        String si = symbolCode.getStandardIdentity();
        String bd = symbolCode.getBattleDimension();
        String fi = symbolCode.getFunctionId();

        // Clover, Clover Up, and Clover Down.
        if (si != null && (si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_PENDING)
            || si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_UNKNOWN)
            || si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_EXERCISE_PENDING)
            || si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_EXERCISE_UNKNOWN)))
        {
            // Clover icon.
            if (bd != null && (bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_UNKNOWN)
                || bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SEA_SURFACE)
                || bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SOF)))
            {
                symbolInfo.iconOffset = CLOVER_OFFSET;
                symbolInfo.iconSize = CLOVER_SIZE;
            }
            // Clover icon for Special C2 Headquarters symbols. Must appear before Clover icon for Ground symbols.
            else if (scheme != null && scheme.equalsIgnoreCase(SymbologyConstants.SCHEME_WARFIGHTING)
                && si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_UNKNOWN)
                && bd != null && bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_GROUND)
                && fi != null && fi.toUpperCase().equalsIgnoreCase("UH----"))
            {
                symbolInfo.iconOffset = CLOVER_OFFSET;
                symbolInfo.iconSize = CLOVER_SIZE;
                symbolInfo.offset = CLOVER_C2_HQ_OFFSET;
                symbolInfo.isGroundSymbol = true;
            }
            // Clover icon for Ground symbols.
            else if ((bd != null && bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_GROUND))
                || (scheme != null && (scheme.equalsIgnoreCase(SymbologyConstants.SCHEME_STABILITY_OPERATIONS)
                || scheme.equalsIgnoreCase(SymbologyConstants.SCHEME_EMERGENCY_MANAGEMENT))))
            {
                symbolInfo.iconOffset = CLOVER_OFFSET;
                symbolInfo.iconSize = CLOVER_SIZE;
                symbolInfo.isGroundSymbol = true;
            }
            // Clover Up icon (Clover without a bottom leaf).
            else if (bd != null && (bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SPACE)
                || bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_AIR)))
            {
                symbolInfo.iconOffset = CLOVER_UP_OFFSET;
                symbolInfo.iconSize = CLOVER_UP_SIZE;
            }
            // Clover Down icon (Clover without a top leaf).
            else if (bd != null && bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SEA_SUBSURFACE))
            {
                symbolInfo.iconOffset = CLOVER_DOWN_OFFSET;
                symbolInfo.iconSize = CLOVER_DOWN_SIZE;
            }
        }
        // Arch Up, Arch Down, Circle, and Rectangle.
        else if (si != null && (si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_FRIEND)
            || si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_ASSUMED_FRIEND)
            || si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_EXERCISE_FRIEND)
            || si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_EXERCISE_ASSUMED_FRIEND)
            || si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_JOKER)
            || si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_FAKER)))
        {
            // Arch Up icon.
            if (bd != null && (bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SPACE)
                || bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_AIR)))
            {
                symbolInfo.iconOffset = ARCH_UP_OFFSET;
                symbolInfo.iconSize = ARCH_UP_SIZE;
            }
            // Arch Down icon.
            else if (bd != null && (bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SEA_SUBSURFACE)))
            {
                symbolInfo.iconOffset = ARCH_DOWN_OFFSET;
                symbolInfo.iconSize = ARCH_DOWN_SIZE;
            }
            // Circle icon.
            else if (bd != null && (bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_UNKNOWN)
                || bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SEA_SURFACE)))
            {
                symbolInfo.iconOffset = CIRCLE_OFFSET;
                symbolInfo.iconSize = CIRCLE_SIZE;
            }
            // Circle icon for Ground Symbols.
            else if ((scheme != null && scheme.equalsIgnoreCase(SymbologyConstants.SCHEME_WARFIGHTING)
                && bd != null && bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_GROUND)
                && fi != null && fi.matches("E....."))
                || (scheme != null && scheme.equalsIgnoreCase(SymbologyConstants.SCHEME_INTELLIGENCE)
                && bd != null && bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_GROUND)))
            {
                symbolInfo.iconOffset = CIRCLE_OFFSET;
                symbolInfo.iconSize = CIRCLE_SIZE;
                symbolInfo.isGroundSymbol = true;
            }
            // Rectangle icon.
            else if (bd != null && bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SOF))
            {
                symbolInfo.iconOffset = RECTANGLE_OFFSET;
                symbolInfo.iconSize = RECTANGLE_SIZE;
            }
            // Rectangle icon for Special C2 Headquarters symbols. Must appear before Rectangle icon for Ground symbols.
            else if (scheme != null && scheme.equalsIgnoreCase(SymbologyConstants.SCHEME_WARFIGHTING)
                && si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_FRIEND)
                && bd != null && bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_GROUND)
                && fi != null && fi.equalsIgnoreCase("UH----"))
            {
                symbolInfo.iconOffset = RECTANGLE_OFFSET;
                symbolInfo.iconSize = RECTANGLE_SIZE;
                symbolInfo.offset = RECTANGLE_C2_HQ_OFFSET;
                symbolInfo.isGroundSymbol = true;
            }
            // Rectangle icon for Ground symbols.
            else if ((scheme != null && scheme.equalsIgnoreCase(SymbologyConstants.SCHEME_WARFIGHTING)
                && bd != null && bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_GROUND)
                && (fi == null || (fi.equalsIgnoreCase("-----") || fi.toUpperCase().matches("U.....")
                || fi.toUpperCase().matches("I....."))))
                || (scheme != null && (scheme.equalsIgnoreCase(SymbologyConstants.SCHEME_STABILITY_OPERATIONS)
                || scheme.equalsIgnoreCase(SymbologyConstants.SCHEME_EMERGENCY_MANAGEMENT))))
            {
                symbolInfo.iconOffset = RECTANGLE_OFFSET;
                symbolInfo.iconSize = RECTANGLE_SIZE;
                symbolInfo.isGroundSymbol = true;
            }
        }
        // Hat Up, Hat Down, and Square.
        else if (si != null && (si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_NEUTRAL)
            || si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_EXERCISE_NEUTRAL)))
        {
            // Hat Up icon (tall rectangle without a bottom edge).
            if (bd != null && (bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SPACE)
                || bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_AIR)))
            {
                symbolInfo.iconOffset = HAT_UP_OFFSET;
                symbolInfo.iconSize = HAT_UP_SIZE;
            }
            // Hat Down icon (tall rectangle without a top edge).
            else if (bd != null && bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SEA_SUBSURFACE))
            {
                symbolInfo.iconOffset = HAT_DOWN_OFFSET;
                symbolInfo.iconSize = HAT_DOWN_SIZE;
            }
            // Square icon.
            else if (bd != null && (bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_UNKNOWN)
                || bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SEA_SURFACE)
                || bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SOF)))
            {
                symbolInfo.iconOffset = SQUARE_OFFSET;
                symbolInfo.iconSize = SQUARE_SIZE;
            }
            // Square icon for Special C2 Headquarters symbols. Must appear before Square icon for Ground symbols.
            else if (scheme != null && scheme.equalsIgnoreCase(SymbologyConstants.SCHEME_WARFIGHTING)
                && si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_NEUTRAL)
                && bd != null && bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_GROUND)
                && fi != null && fi.equalsIgnoreCase("UH----"))
            {
                symbolInfo.iconOffset = SQUARE_OFFSET;
                symbolInfo.iconSize = SQUARE_SIZE;
                symbolInfo.offset = SQUARE_C2_HQ_OFFSET;
                symbolInfo.isGroundSymbol = true;
            }
            // Square icon for Ground symbols.
            else if ((bd != null && bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_GROUND))
                || (scheme != null && (scheme.equalsIgnoreCase(SymbologyConstants.SCHEME_STABILITY_OPERATIONS)
                || scheme.equalsIgnoreCase(SymbologyConstants.SCHEME_EMERGENCY_MANAGEMENT))))
            {
                symbolInfo.iconOffset = SQUARE_OFFSET;
                symbolInfo.iconSize = SQUARE_SIZE;
                symbolInfo.isGroundSymbol = true;
            }
        }
        // Tent Up, Tent Down, Diamond.
        else if (si != null && (si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_HOSTILE)
            || si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_SUSPECT)))
        {
            // Tent Up icon.
            if (bd != null && (bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SPACE)
                || bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_AIR)))
            {
                symbolInfo.iconOffset = TENT_UP_OFFSET;
                symbolInfo.iconSize = TENT_UP_SIZE;
            }
            // Tent Down icon.
            else if (bd != null && bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SEA_SUBSURFACE))
            {
                symbolInfo.iconOffset = TENT_DOWN_OFFSET;
                symbolInfo.iconSize = TENT_DOWN_SIZE;
            }
            // Diamond icon.
            else if (bd != null && (bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_UNKNOWN)
                || bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SEA_SURFACE)
                || bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_SOF)))
            {
                symbolInfo.iconOffset = DIAMOND_OFFSET;
                symbolInfo.iconSize = DIAMOND_SIZE;
            }
            // Diamond icon for Special C2 Headquarters symbols. Must appear before Diamond icon for Ground symbols.
            else if (scheme != null && scheme.equalsIgnoreCase(SymbologyConstants.SCHEME_WARFIGHTING)
                && si.equalsIgnoreCase(SymbologyConstants.STANDARD_IDENTITY_HOSTILE)
                && bd != null && bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_GROUND)
                && fi != null && fi.equalsIgnoreCase("UH----"))
            {
                symbolInfo.iconOffset = DIAMOND_OFFSET;
                symbolInfo.iconSize = DIAMOND_SIZE;
                symbolInfo.offset = DIAMOND_C2_HQ_OFFSET;
                symbolInfo.isGroundSymbol = true;
            }
            // Diamond icon for Ground symbols.
            else if ((bd != null && bd.equalsIgnoreCase(SymbologyConstants.BATTLE_DIMENSION_GROUND))
                || (scheme != null && (scheme.equalsIgnoreCase(SymbologyConstants.SCHEME_STABILITY_OPERATIONS)
                || scheme.equalsIgnoreCase(SymbologyConstants.SCHEME_EMERGENCY_MANAGEMENT))))
            {
                symbolInfo.iconOffset = DIAMOND_OFFSET;
                symbolInfo.iconSize = DIAMOND_SIZE;
                symbolInfo.isGroundSymbol = true;
            }
        }

        return symbolInfo;
    }

    /**
     * Compute screen points required to draw a leader line on a tactical symbol. This method returns two points that
     * will draw a line out from the center of the symbol.
     *
     * @param dc          Current draw context.
     * @param symbolPoint Symbol position in model coordinates.
     * @param heading     Direction of movement, as a bearing clockwise from North.
     * @param length      Length of the indicator line, in pixels.
     *
     * @return List of screen points that describe the speed leader line.
     */
    public static List computeCenterHeadingIndicatorPoints(DrawContext dc, Vec4 symbolPoint,
        Angle heading, double length)
    {
        if (dc == null)
        {
            String msg = Logging.getMessage("nullValue.DrawContextIsNull");
            Logging.logger().severe(msg);
            throw new IllegalArgumentException(msg);
        }

        if (heading == null)
        {
            String msg = Logging.getMessage("nullValue.HeadingIsNull");
            Logging.logger().severe(msg);
            throw new IllegalArgumentException(msg);
        }

        View view = dc.getView();
        Vec4 dir = computeDirectionOfMovement(dc, symbolPoint, heading, length);

        // Project geographic points into screen space.
        Vec4 pt1 = view.project(symbolPoint);
        Vec4 pt2 = view.project(symbolPoint.add3(dir));

        return Arrays.asList(
            new Point2D.Double(0, 0),
            new Point2D.Double(pt2.x - pt1.x, pt2.y - pt1.y));
    }

    /**
     * Compute screen points required to draw a leader line on a tactical ground symbol. This method returns three
     * points that will draw a line down from the base of the symbol and then out in the direction of movement.
     *
     * @param dc          Current draw context.
     * @param symbolPoint Symbol position in model coordinates.
     * @param heading     Direction of movement, as a bearing clockwise from North.
     * @param length      Length of the indicator line, in pixels.
     * @param frameHeight Height of the symbol's bounding rectangle, in pixels.
     *
     * @return List of screen points that describe the speed leader line.
     */
    public static List computeGroundHeadingIndicatorPoints(DrawContext dc, Vec4 symbolPoint,
        Angle heading, double length, double frameHeight)
    {
        if (dc == null)
        {
            String msg = Logging.getMessage("nullValue.DrawContextIsNull");
            Logging.logger().severe(msg);
            throw new IllegalArgumentException(msg);
        }

        if (heading == null)
        {
            String msg = Logging.getMessage("nullValue.HeadingIsNull");
            Logging.logger().severe(msg);
            throw new IllegalArgumentException(msg);
        }

        View view = dc.getView();
        Vec4 dir = computeDirectionOfMovement(dc, symbolPoint, heading, length);

        // Project geographic points into screen space.
        Vec4 pt1 = view.project(symbolPoint);
        Vec4 pt2 = view.project(symbolPoint.add3(dir));

        return Arrays.asList(
            new Point2D.Double(0, 0),
            new Point2D.Double(0, -frameHeight / 2d),
            new Point2D.Double(pt2.x - pt1.x, -frameHeight / 2d + (pt2.y - pt1.y)));
    }

    /**
     * Compute a vector in the direction that a symbol is moving.
     *
     * @param dc          Current draw context.
     * @param symbolPoint Symbol position in model coordinates.
     * @param heading     Heading as a bearing clockwise from North.
     * @param length      Length of the leader line, in pixels. The computed vector will have magnitude equal to this
     *                    distance in pixels multiplied by the size of a pixel (in meters) at the position of the symbol
     *                    relative to the current view.
     *
     * @return A vector that points in the direction of a symbol's movement.
     */
    protected static Vec4 computeDirectionOfMovement(DrawContext dc, Vec4 symbolPoint, Angle heading, double length)
    {
        View view = dc.getView();
        Globe globe = dc.getGlobe();

        double pixelSize = view.computePixelSizeAtDistance(view.getEyePoint().distanceTo3(symbolPoint));

        // Compute a vector in the direction of the heading.
        Position position = globe.computePositionFromPoint(symbolPoint);
        Matrix surfaceOrientation = globe.computeSurfaceOrientationAtPosition(position);
        Vec4 dir = new Vec4(heading.sin(), heading.cos());

        return dir.transformBy3(surfaceOrientation).normalize3().multiply3(length * pixelSize);
    }

    /**
     * Determines a default color to apply to a symbol. MIL-STD-2525C section 5.5.1.1 (pg. 37) states that obstacles
     * should be displayed in green, friendly entities in black or blue, and hostile entities in red. This method return
     * green for obstacles and neutral entities, black for friendly entities, red for hostile entities, and yellow for
     * unknown and pending entities.
     *
     * @param symbolCode Symbol for which to determine color.
     *
     * @return Default material for the specified symbol.
     */
    public static Material getDefaultGraphicMaterial(SymbolCode symbolCode)
    {
        if (symbolCode == null)
        {
            String msg = Logging.getMessage("nullValue.SymbolCodeIsNull");
            Logging.logger().severe(msg);
            throw new IllegalArgumentException(msg);
        }

        if (isObstacle(symbolCode))
            return MilStd2525Constants.MATERIAL_OBSTACLE;

        String id = symbolCode.getStandardIdentity();
        if (SymbologyConstants.STANDARD_IDENTITY_FRIEND.equalsIgnoreCase(id)
            || SymbologyConstants.STANDARD_IDENTITY_ASSUMED_FRIEND.equalsIgnoreCase(id)
            || SymbologyConstants.STANDARD_IDENTITY_EXERCISE_ASSUMED_FRIEND.equalsIgnoreCase(id))
        {
            return MilStd2525Constants.MATERIAL_FRIEND;
        }
        else if (SymbologyConstants.STANDARD_IDENTITY_HOSTILE.equalsIgnoreCase(id)
            || SymbologyConstants.STANDARD_IDENTITY_SUSPECT.equalsIgnoreCase(id)
            || SymbologyConstants.STANDARD_IDENTITY_JOKER.equalsIgnoreCase(id)
            || SymbologyConstants.STANDARD_IDENTITY_FAKER.equalsIgnoreCase(id))
        {
            return MilStd2525Constants.MATERIAL_HOSTILE;
        }
        else if (SymbologyConstants.STANDARD_IDENTITY_NEUTRAL.equalsIgnoreCase(id)
            || SymbologyConstants.STANDARD_IDENTITY_EXERCISE_NEUTRAL.equalsIgnoreCase(id))
        {
            return MilStd2525Constants.MATERIAL_NEUTRAL;
        }

        // Default to Unknown
        return MilStd2525Constants.MATERIAL_UNKNOWN;
    }

    /**
     * Indicates whether or not a symbol code identifiers an Obstacle. Obstacles defined in the Mobility and
     * Survivability category of MIL-STD-2525C Appendix B.
     *
     * @param symbolCode Symbol code to test.
     *
     * @return True if the symbol code represents an obstacle, otherwise false.
     */
    protected static boolean isObstacle(SymbolCode symbolCode)
    {
        if (symbolCode == null)
            return false;

        String scheme = symbolCode.getScheme();
        String category = symbolCode.getCategory();
        String functionId = symbolCode.getFunctionId();

        // Obstacle function IDs start with "O".
        return SymbologyConstants.SCHEME_TACTICAL_GRAPHICS.equalsIgnoreCase(scheme)
            && SymbologyConstants.CATEGORY_MOBILITY_SURVIVABILITY.equalsIgnoreCase(category)
            && (functionId.charAt(0) == 'o' || functionId.charAt(0) == 'O');
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy