Skip to content

zepinto/mil-sym-java

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mil-sym-java

A comprehensive Java library for rendering military symbols according to MIL-STD-2525 standards. This library has been used in US Army Mission Command software for years and supports 2525D, 2525E, and potentially future versions.

Table of Contents

About

mil-sym-java is a well-worn set of Java libraries that have been used in US Army Mission Command software for years. In November 2013, Mission Command was given approval to release and maintain these libraries as public open source. Eventually work on the 2525C SEC Renderer ended and the project was retired.

This is a continuation of that effort and this library aims to support 2525D, 2525E and potentially more future versions.

Project Structure

Renderer: This is the component that can be used in Java applications to generate the entire MIL-STD-2525 symbol for both icon-based symbols and geometric symbols such as tactical graphics. The Renderer relies on the jar files generated by Core.

External Libraries in use

Understanding MIL-STD-2525

What is MIL-STD-2525?

MIL-STD-2525 is a United States Department of Defense (DoD) interface standard that defines a comprehensive system for visualizing military symbology. It provides a standardized way to represent military units, equipment, installations, activities, and tactical graphics on maps and displays across all military services and NATO forces.

Key Features of MIL-STD-2525

  1. Universal Recognition: Ensures that military symbols are universally recognizable across all branches of service, allied nations, and military systems.

  2. Information Encoding: Symbols encode critical information including:

    • Unit/equipment type (aircraft, ground unit, ship, etc.)
    • Affiliation (friendly, hostile, neutral, unknown)
    • Status (present, planned, destroyed, etc.)
    • Command level/echelon (team, platoon, company, battalion, etc.)
    • Mobility (wheeled, tracked, towed, etc.)
  3. Visual Hierarchy: Uses colors, shapes, and modifiers to quickly convey complex military information:

    • Colors: Blue/Cyan for friendly, Red for hostile, Yellow for unknown, Green for neutral
    • Shapes: Different frame shapes for different affiliations and contexts
    • Modifiers: Text and graphic modifiers for additional details (e.g., unit names, quantities, directions)

MIL-STD-2525 Versions

This library supports:

  • 2525D Change 1: Major update from 2525C, introducing significant structural changes to symbol codes
  • 2525E Change 1: Latest version with additional symbols and refinements
  • APP6 (Allied Procedural Publication 6): NATO equivalent with some variations

Symbol Categories

MIL-STD-2525 defines two primary categories of symbols:

1. Single-Point Symbols (Icons)

These represent objects at a specific point on the map:

  • Units: Infantry, armor, artillery, aviation units, etc.
  • Equipment: Vehicles, weapons systems, sensors
  • Installations: Bases, depots, headquarters
  • Activities: Events, incidents, points of interest

2. Multi-Point Symbols (Tactical Graphics)

These represent areas, lines, or complex shapes:

  • Control Measures: Boundaries, phase lines, objectives
  • Fire Support: Target areas, no-fire areas, fire support coordination measures
  • Mobility/Survivability: Obstacles, minefields, routes
  • Combat Service Support: Supply routes, medical evacuation routes

Symbol ID Structure

A MIL-STD-2525D/E Symbol Identification Code (SIDC) is a string that uniquely identifies a military symbol. The minimum length is 20 digits, but it can extend to 30 digits to include additional modifiers. Understanding this structure is crucial for creating symbols.

Symbol ID Format (20-30 digits)

Position:  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Format:   [V][V][C][A][SS ][S][H][EE ][EEEEEE      ][MMMMMM      ][optional 10 digits      ]

Breakdown:

  • Positions 1-2: Version (e.g., "10" = 2525D, "15" = 2525E Change 1)
  • Position 3: Context (0=Reality, 1=Exercise, 2=Simulation)
  • Position 4: Standard Identity/Affiliation (0=Pending, 1=Unknown, 2=Assumed Friend, 3=Friend, 4=Neutral, 5=Suspect, 6=Hostile)
  • Positions 5-6: Symbol Set (01=Air, 10=Land Unit, 15=Land Equipment, 20=Installation, 25=Control Measure, 30=Sea Surface, etc.)
  • Position 7: Status (0=Present, 1=Planned, 2=Fully Capable, 3=Damaged, 4=Destroyed, 5=Full to Capacity)
  • Position 8: HQ/Task Force/Dummy (0=None, 1=Feint/Dummy, 2=Headquarters, 4=Task Force, 6=TF+HQ)
  • Positions 9-10: Echelon/Mobility (11=Team/Crew, 12=Squad, 15=Company, 16=Battalion, 21=Division, etc.)
  • Positions 11-16: Entity Code (specific unit/equipment type within the symbol set)
  • Positions 17-20: Modifier 1 (0000 for none)
  • Positions 21-30: Additional modifiers (optional, typically zeros for basic symbols)

Symbol Set Values

Common Symbol Set values:

  • 01 - Air
  • 05 - Space
  • 10 - Land Unit
  • 11 - Land Civilian Unit/Organization
  • 15 - Land Equipment
  • 20 - Land Installation
  • 25 - Control Measure (Tactical Graphics)
  • 27 - Dismounted Individuals
  • 30 - Sea Surface
  • 35 - Sea Subsurface
  • 40 - Activities
  • 45 - Atmospheric
  • 60 - Cyberspace

Quick Start

Maven Dependency

<dependency>
    <groupId>io.github.missioncommand</groupId>
    <artifactId>mil-sym-java</artifactId>
    <version>2.5.1</version>
</dependency>

Basic Usage

import armyc2.c5isr.renderer.MilStdIconRenderer;
import armyc2.c5isr.renderer.utilities.*;
import java.util.HashMap;
import java.util.Map;

// Get the renderer instance
MilStdIconRenderer renderer = MilStdIconRenderer.getInstance();

// Create a friendly infantry unit symbol
String symbolCode = "10031000001211000000000000000000";
Map<String, String> modifiers = new HashMap<>();
Map<String, String> attributes = new HashMap<>();

// Render the icon
ImageInfo imageInfo = renderer.RenderIcon(symbolCode, modifiers, attributes);

// Get the image
java.awt.image.BufferedImage image = imageInfo.getImage();

Creating Single-Point Symbols (Icons)

Example 1: Basic Friendly Infantry Unit

import armyc2.c5isr.renderer.MilStdIconRenderer;
import armyc2.c5isr.renderer.utilities.*;
import java.util.HashMap;
import java.util.Map;

public class BasicInfantryExample {
    public static void main(String[] args) {
        // Get renderer instance
        MilStdIconRenderer renderer = MilStdIconRenderer.getInstance();
        
        // Build a 2525D friendly infantry unit at company level
        // Symbol ID breakdown:
        // 10 - Version 2525D
        // 0  - Context: Reality
        // 3  - Affiliation: Friend
        // 10 - Symbol Set: Land Unit
        // 0  - Status: Present
        // 0  - HQ/TF: None
        // 15 - Echelon: Company
        // 120000 - Entity: Infantry
        String symbolCode = "10031000001512000000000000000000";
        
        Map<String, String> modifiers = new HashMap<>();
        Map<String, String> attributes = new HashMap<>();
        
        // Add unit designation
        modifiers.put(Modifiers.T_UNIQUE_DESIGNATION_1, "A/1-325");
        
        // Add higher formation
        modifiers.put(Modifiers.M_HIGHER_FORMATION, "1-325 IN");
        
        // Render the icon
        ImageInfo imageInfo = renderer.RenderIcon(symbolCode, modifiers, attributes);
        
        if (imageInfo != null && imageInfo.getImage() != null) {
            // Save to file
            try {
                javax.imageio.ImageIO.write(
                    imageInfo.getImage(), 
                    "PNG", 
                    new java.io.File("infantry_company.png")
                );
                System.out.println("Symbol created successfully!");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

Example 2: Hostile Tank Unit

public class HostileTankExample {
    public static void main(String[] args) {
        MilStdIconRenderer renderer = MilStdIconRenderer.getInstance();
        
        // Build a 2525E hostile tank unit at battalion level
        // 15 - Version 2525E Change 1
        // 0  - Context: Reality
        // 6  - Affiliation: Hostile
        // 10 - Symbol Set: Land Unit
        // 0  - Status: Present
        // 0  - HQ/TF: None
        // 16 - Echelon: Battalion
        // 010000 - Entity: Armor/Armored, Tracked
        String symbolCode = "15061000001601000000000000000000";
        
        Map<String, String> modifiers = new HashMap<>();
        modifiers.put(Modifiers.T_UNIQUE_DESIGNATION_1, "3rd Tank Bn");
        modifiers.put(Modifiers.C_QUANTITY, "30");
        
        Map<String, String> attributes = new HashMap<>();
        ImageInfo imageInfo = renderer.RenderIcon(symbolCode, modifiers, attributes);
        
        // Use the image...
    }
}

Example 3: Aircraft Symbol

public class AircraftExample {
    public static void main(String[] args) {
        MilStdIconRenderer renderer = MilStdIconRenderer.getInstance();
        
        // Friendly fighter aircraft
        // 10 - Version 2525D
        // 0  - Context: Reality
        // 3  - Affiliation: Friend
        // 01 - Symbol Set: Air
        // 0  - Status: Present
        // 0  - HQ/TF: None
        // 11 - Echelon: Team/Crew
        // 120000 - Entity: Military Fixed Wing, Fighter
        String symbolCode = "10030100001112000000000000000000";
        
        Map<String, String> modifiers = new HashMap<>();
        modifiers.put(Modifiers.T_UNIQUE_DESIGNATION_1, "F-16C");
        modifiers.put(Modifiers.C_QUANTITY, "4");
        modifiers.put(Modifiers.V_EQUIPMENT_TYPE, "Block 52");
        
        Map<String, String> attributes = new HashMap<>();
        ImageInfo imageInfo = renderer.RenderIcon(symbolCode, modifiers, attributes);
        
        // Use the image...
    }
}

Example 4: Equipment Symbol with Multiple Modifiers

public class EquipmentExample {
    public static void main(String[] args) {
        MilStdIconRenderer renderer = MilStdIconRenderer.getInstance();
        
        // Friendly wheeled vehicle (truck)
        // 10 - Version 2525D
        // 0  - Context: Reality
        // 3  - Affiliation: Friend
        // 15 - Symbol Set: Land Equipment
        // 0  - Status: Present
        // 0  - HQ/TF: None
        // 31 - Mobility: Wheeled Limited Cross Country
        // 120000 - Entity: Truck
        String symbolCode = "10031500003112000000000000000000";
        
        Map<String, String> modifiers = new HashMap<>();
        
        // Add unique designation
        modifiers.put(Modifiers.T_UNIQUE_DESIGNATION_1, "HMMWV");
        
        // Add quantity
        modifiers.put(Modifiers.C_QUANTITY, "12 Vehicles");
        
        // Add additional information
        modifiers.put(Modifiers.H_ADDITIONAL_INFO_1, "Motor Pool A");
        
        // Add staff comments
        modifiers.put(Modifiers.G_STAFF_COMMENTS, "Ready");
        
        // Add speed
        modifiers.put(Modifiers.Z_SPEED, "55 KPH");
        
        Map<String, String> attributes = new HashMap<>();
        attributes.put(MilStdAttributes.PixelSize, "100");
        
        ImageInfo imageInfo = renderer.RenderIcon(symbolCode, modifiers, attributes);
        
        // Use the image...
    }
}

Example 5: Installation/Facility

public class InstallationExample {
    public static void main(String[] args) {
        MilStdIconRenderer renderer = MilStdIconRenderer.getInstance();
        
        // Friendly hospital
        // 10 - Version 2525D
        // 0  - Context: Reality
        // 3  - Affiliation: Friend
        // 20 - Symbol Set: Land Installation
        // 0  - Status: Present
        // 0  - HQ/TF: None
        // 00 - Echelon: Not applicable
        // 410000 - Entity: Medical Treatment Facility
        String symbolCode = "10032000000041000000000000000000";
        
        Map<String, String> modifiers = new HashMap<>();
        modifiers.put(Modifiers.T_UNIQUE_DESIGNATION_1, "Field Hospital");
        modifiers.put(Modifiers.C_QUANTITY, "200 Beds");
        modifiers.put(Modifiers.H_ADDITIONAL_INFO_1, "Level III");
        
        Map<String, String> attributes = new HashMap<>();
        ImageInfo imageInfo = renderer.RenderIcon(symbolCode, modifiers, attributes);
        
        // Use the image...
    }
}

Creating Multi-Point Symbols (Tactical Graphics)

Multi-point symbols represent tactical graphics such as boundaries, routes, and areas. These require multiple coordinate points.

Example 6: Boundary Line

import armyc2.c5isr.web.render.WebRenderer;
import armyc2.c5isr.renderer.utilities.*;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class BoundaryExample {
    public static void main(String[] args) {
        // Boundary line
        // 10 - Version 2525D
        // 0  - Context: Reality
        // 3  - Affiliation: Friend
        // 25 - Symbol Set: Control Measure
        // 0  - Status: Present
        // 0  - HQ/TF: None
        // 00 - Echelon: Not applicable
        // 020100 - Entity: Boundary
        String symbolCode = "10032500000002010000000000000000";
        
        // Define control points (longitude, latitude)
        String controlPoints = "50.0,20.0 50.0,21.0 51.0,21.0";
        
        Map<String, String> modifiers = new HashMap<>();
        modifiers.put(Modifiers.T_UNIQUE_DESIGNATION_1, "PHASE LINE GREEN");
        
        Map<String, String> attributes = new HashMap<>();
        
        // Render as GeoJSON
        String geoJson = WebRenderer.RenderSymbol(
            "boundary_001",                // id
            "Unit Boundary",               // name
            "Division Boundary",           // description
            symbolCode,                    // symbol code
            controlPoints,                 // control points
            "clampToGround",              // altitude mode
            50000.0,                       // scale (1:50K)
            "49.5,19.5,51.5,21.5",        // bbox
            modifiers,                     // modifiers
            attributes,                    // attributes
            WebRenderer.OUTPUT_FORMAT_GEOJSON  // output format
        );
        
        System.out.println(geoJson);
    }
}

Example 7: Assembly Area

public class AssemblyAreaExample {
    public static void main(String[] args) {
        // Assembly Area
        // 10 - Version 2525D
        // 0  - Context: Reality
        // 3  - Affiliation: Friend
        // 25 - Symbol Set: Control Measure
        // 0  - Status: Present
        // 0  - HQ/TF: None
        // 00 - Echelon: Not applicable
        // 050600 - Entity: Assembly Area
        String symbolCode = "10032500000005060000000000000000";
        
        // Define area points (closed polygon)
        String controlPoints = "50.0,20.0 50.5,20.0 50.5,20.5 50.0,20.5 50.0,20.0";
        
        Map<String, String> modifiers = new HashMap<>();
        modifiers.put(Modifiers.T_UNIQUE_DESIGNATION_1, "AA WOLF");
        modifiers.put(Modifiers.H_ADDITIONAL_INFO_1, "2-325 IN");
        modifiers.put(Modifiers.W_DTG_1, "241200ZNOV24"); // Date-Time Group
        
        Map<String, String> attributes = new HashMap<>();
        
        // Render as KML
        String kml = WebRenderer.RenderSymbol(
            "aa_wolf",
            "Assembly Area Wolf",
            "2-325 IN Assembly Area",
            symbolCode,
            controlPoints,
            "clampToGround",
            50000.0,
            "49.5,19.5,51.0,21.0",
            modifiers,
            attributes,
            WebRenderer.OUTPUT_FORMAT_KML
        );
        
        System.out.println(kml);
    }
}

Example 8: Route

public class RouteExample {
    public static void main(String[] args) {
        // Main Supply Route
        // 10 - Version 2525D
        // 0  - Context: Reality
        // 3  - Affiliation: Friend
        // 25 - Symbol Set: Control Measure
        // 0  - Status: Present
        // 0  - HQ/TF: None
        // 00 - Echelon: Not applicable
        // 030200 - Entity: Main Supply Route
        String symbolCode = "10032500000003020000000000000000";
        
        // Define route waypoints
        String controlPoints = "50.0,20.0 50.2,20.3 50.5,20.5 50.8,20.7 51.0,21.0";
        
        Map<String, String> modifiers = new HashMap<>();
        modifiers.put(Modifiers.T_UNIQUE_DESIGNATION_1, "MSR TAMPA");
        modifiers.put(Modifiers.H_ADDITIONAL_INFO_1, "Primary");
        
        Map<String, String> attributes = new HashMap<>();
        
        // Render as SVG
        String svg = WebRenderer.RenderSymbol(
            "msr_tampa",
            "Main Supply Route Tampa",
            "Primary MSR for brigade",
            symbolCode,
            controlPoints,
            "clampToGround",
            50000.0,
            "49.5,19.5,51.5,21.5",
            modifiers,
            attributes,
            WebRenderer.OUTPUT_FORMAT_GEOSVG
        );
        
        System.out.println(svg);
    }
}

Using Modifiers

Modifiers add additional information to symbols. Here are the most commonly used modifiers:

Text Modifiers

Map<String, String> modifiers = new HashMap<>();

// Unique Designation (main identifier)
modifiers.put(Modifiers.T_UNIQUE_DESIGNATION_1, "A/1-325");

// Higher Formation
modifiers.put(Modifiers.M_HIGHER_FORMATION, "1st BCT");

// Additional Information
modifiers.put(Modifiers.H_ADDITIONAL_INFO_1, "Mission: Attack");
modifiers.put(Modifiers.H1_ADDITIONAL_INFO_2, "Additional notes");

// Staff Comments
modifiers.put(Modifiers.G_STAFF_COMMENTS, "Combat Ready");

// Quantity
modifiers.put(Modifiers.C_QUANTITY, "12 Tanks");

// Combat Effectiveness
modifiers.put(Modifiers.K_COMBAT_EFFECTIVENESS, "75%");

// Signature Equipment
modifiers.put(Modifiers.V_EQUIPMENT_TYPE, "M1A2");

// Date-Time Group
modifiers.put(Modifiers.W_DTG_1, "241200ZNOV24");
modifiers.put(Modifiers.W1_DTG_2, "251200ZNOV24");

// Altitude/Depth
modifiers.put(Modifiers.X_ALTITUDE_DEPTH, "1000 AGL");

// Location
modifiers.put(Modifiers.Y_LOCATION, "Grid: NV123456");

// Speed
modifiers.put(Modifiers.Z_SPEED, "45 KPH");

// Direction of Movement
modifiers.put(Modifiers.Q_DIRECTION_OF_MOVEMENT, "090"); // degrees

// Evaluation Rating
modifiers.put(Modifiers.J_EVALUATION_RATING, "A3");

// Reinforced or Reduced
modifiers.put(Modifiers.F_REINFORCED_REDUCED, "+"); // + for reinforced, - for reduced

// Special C2 Headquarters
modifiers.put(Modifiers.AA_SPECIAL_C2_HQ, "C2");

Distance and Azimuth Modifiers (for Tactical Graphics)

// Distance (for graphics that need distance, comma-separated for multiple)
modifiers.put(Modifiers.AM_DISTANCE, "1000,2000,3000");

// Azimuth (for graphics that need azimuth/direction)
modifiers.put(Modifiers.AN_AZIMUTH, "45,90,135");

// Width (for linear graphics)
modifiers.put(Modifiers.AM_DISTANCE, "200"); // meters

Attributes

Attributes control rendering behavior:

Map<String, String> attributes = new HashMap<>();

// Set icon pixel size (default is typically 35)
attributes.put(MilStdAttributes.PixelSize, "100");

// Set line width for multi-point graphics
attributes.put(MilStdAttributes.LineWidth, "3");

// Set line color (hex format)
attributes.put(MilStdAttributes.LineColor, "FFFF0000"); // ARGB format

// Set fill color
attributes.put(MilStdAttributes.FillColor, "80FF0000"); // Semi-transparent red

// Keep unit ratio (for scaling)
attributes.put(MilStdAttributes.KeepUnitRatio, "true");

// Center point (for positioning)
attributes.put(MilStdAttributes.CenterPoint, "100,100");

Symbol Examples

Common Military Symbols Quick Reference

Symbol Type Symbol Code Example Description
Friendly Infantry 10031000001512000000000000000000 Company-level infantry unit
Hostile Armor 10061000001601000000000000000000 Battalion-level tank unit
Unknown Aircraft 10010100001112000000000000000000 Fighter aircraft
Friendly Ship 10033000000000000000000000000000 Surface vessel
Hostile Submarine 10063500000000000000000000000000 Submarine
Friendly Helicopter 10030100001511000000000000000000 Attack helicopter
Field Artillery 10031000001510000000000000000000 Company-level artillery
Air Defense 10031000001510500000000000000000 Air defense unit
Engineers 10031000001513000000000000000000 Engineer unit
Supply Point 10032000000012000000000000000000 Supply installation
Command Post 10032000000000100000000000000000 Command facility
Objective 10032500000006010000000000000000 Attack objective
Phase Line 10032500000002010000000000000000 Control line
Route 10032500000003020000000000000000 Movement route

Building Symbol IDs with Helper Methods

The SymbolID class provides helper methods for building symbol IDs:

import armyc2.c5isr.renderer.utilities.SymbolID;

// Start with a base symbol ID
String baseID = "10031000001512000000000000000000";

// Change the affiliation to hostile (position 4)
String hostileID = SymbolID.setAffiliation(baseID, 
    SymbolID.StandardIdentity_Affiliation_Hostile_Faker);

// Change the echelon/amplifier descriptor to battalion (positions 9-10)
String battalionID = SymbolID.setAmplifierDescriptor(baseID, 16);

// Change the status to planned (position 7)
String plannedID = SymbolID.setStatus(baseID, 1);

// Change the version
String newVersionID = SymbolID.setVersion(baseID, SymbolID.Version_2525Ech1);

// Get parts of a symbol ID
int version = SymbolID.getVersion(baseID);
int symbolSet = SymbolID.getSymbolSet(baseID);
String entityCode = SymbolID.getEntityCode(baseID);

Build Instructions

Build the project using Gradle:

./gradlew build

Run tests:

./gradlew test

Generate JavaDoc:

./gradlew javadoc

Documentation

Ports

This library has been ported to multiple platforms:

Additional Resources

Official MIL-STD-2525 Documentation

For the complete specification, refer to the official DoD documentation:

  • MIL-STD-2525D Change 1 (20 November 2014)
  • MIL-STD-2525E Change 1 (Latest version)

These documents provide:

  • Complete symbol set definitions
  • Entity code tables
  • Modifier specifications
  • Color specifications
  • Symbol construction rules

Understanding Symbol Colors

The standard defines specific colors for affiliations:

  • Friendly: Blue (RGB: 0, 255, 255 or Cyan)
  • Hostile: Red (RGB: 255, 0, 0)
  • Neutral: Green (RGB: 0, 255, 0)
  • Unknown: Yellow (RGB: 255, 255, 0)

Frame Shapes

Frame shapes vary based on:

  • Dimension: Air, land, sea, space, etc.
  • Affiliation: Friend, hostile, neutral, unknown
  • Context: Reality, exercise, simulation

Common shapes include:

  • Circle: Unknown entities
  • Rectangle: Friendly entities
  • Diamond: Hostile entities
  • Square: Neutral entities
  • Cloverleaf: Friendly installations

License

GNU General Public License v3.0

Contributing

Contributions are welcome! Please follow the existing code style and include tests for new functionality.

Support

For issues, questions, or contributions, please visit the GitHub repository.

About

MIL-STD-2525 D+ Renderer for Java

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Java 100.0%