Introduction
To create, visualize and edit military symbols that comply with military symbology standards, LuciadRIA offers the Defense Symbology component.
The Defense Symbology functionality comes in a @luciad/ria-milsym
NPM package.
The LuciadRIA Defense Symbology component provides support for several military symbology standards, including MIL-STD 2525b, MIL-STD 2525c, MIL-STD 2525d, APP-6A, APP-6B, APP-6C and APP-6D. These standards define a symbol set that is used to plan and execute military operations in support of Command, Control, Communications, Computers, and Intelligence (C4I) functions.
The MIL-STD 2525 standards were developed by the United States Department of Defense (DOD), while the APP-6 standards were developed by the North Atlantic Treaty Organization (NATO). As the APP-6 standards are partially derived from MIL-STD 2525a, they share many symbols.
The Defense Symbology component allows a LuciadRIA user to create MIL-STD 2525b, MIL-STD 2525c, MIL-STD 2525d, APP-6A, APP-6B, APP-6C and APP-6D symbols, and visualize them on a map.
Using the Symbology API
A Symbology is a set of named symbols and tactical graphics that are visualized on a map by means of icons and shapes, like polygons and polylines. In LuciadRIA, a Symbology corresponds to one of the symbology standards APP6 and MS2525. This page explains how to use the LuciadRIA Symbology API to:
-
Import a symbology for use. Before any symbol can be created, visualized or manipulated, you must import a Symbology into your application. Symbologies provide the metadata to work with individual symbols or groups of symbols. See Importing a symbology for more information.
-
Visualize a domain object with a military symbol, using a
symbology.military.MilitarySymbologyPainter
. See Visualizing a symbol for more information. -
Create new symbols, as discussed in Creating a new Symbol.
-
Manipulate properties of a symbol, as discussed in Manipulating symbol properties.
Importing a symbology
To import a symbology, just import the symbology/military/<symbologyname>
module.
This returns a singleton instance of the symbology with <symbologyname>
.
import {MilitarySymbologyPainter} from "@luciad/ria-milsym/symbology/military/MilitarySymbologyPainter.js";
import {MIL_STD_2525b} from "@luciad/ria-milsym/symbology/military/MIL_STD_2525b.js";
The available symbologies correspond to the following standards.
-
MIL_STD_2525b
-
MIL_STD_2525c
-
MIL_STD_2525d
-
APP_6A
-
APP_6B
-
APP_6C
-
APP_6D
All symbology sets are represented as a hierarchical tree structure consisting of symbology nodes.
Note that it’s also possible to load a symbology using the symbology/SymbologyProvider
module.
This module can act as an AMD plugin that takes the name of the required Symbology as a parameter.
The result is a symbology instance that’s passed into the module factory function.
An alternative is to use the SymbologyProvider.getSymbology()
method. This method returns a promise for
the symbology. Both methods are deprecated since LuciadRIA 2018.1, however, and should no longer be used.
Using a hierarchical symbology
The symbology instance is an instance of type symbology.HierarchicalSymbology
.
This is because all military symbology standards have a hierarchical tree structure, in which related symbols with
similar properties are grouped under the same parent.
Each symbol or group of symbols in the hierarchy are instances of type symbology.SymbologyNode
.
The main purpose of the HierarchicalSymbology
instance is that it provides access to all the symbols defined in
the standard.
With it, you can:
-
Enumerate over all symbols, starting from the root of the symbology.
-
Use a symbol’s identifier,which is the code of the symbol, to retrieve a particular symbol.
Importing a symbology is a prerequisite for visualizing domain objects with military symbols. See Visualizing a symbol for more information.
Using a symbology node
Each individual symbol is an instance of symbology.SymbologyNode
.
Such a SymbologyNode
object has two main purposes:
-
Provide metadata, such as the symbol’s name and unique identifier
-
Create a shape with a geometry that corresponds to the symbol’s requirements. For example, a
Point
would be the corresponding shape for a tactical icon, a helipad for example, while aPolyLine
would be the corresponding shape for a symbol indicating a barrier, a fence for example.
Creating a new Symbol contains more details about how this functionality can be used to create new features.
Visualizing a symbol
To visualize a military symbol, create a MilitarySymbologyPainter
.
To visualize a symbol, the API does not place any requirements on the structure of the domain objects
in the model. When constructing a |
To construct a symbol painter, you need to supply two mandatory parameters.
-
A symbology. This is a reference to a symbology standard. How to import one is explained in Importing a symbology.
-
A code function. This function must map a feature, the domain object, to the SIDC military symbol code. As a shorthand, you can also use a string which refers to the property of the feature that contains the code.
Other parameters are optional and revert to default behavior if they haven’t been defined. See the API documentation for a list of optional modifiers, and their possible values.
Program: Minimum code needed to create a MilitarySymbologyPainter
. provides the minimum code required to create a MilitarySymbologyPainter
:
MilitarySymbologyPainter
.
const symbologyPainter = new MilitarySymbologyPainter(MIL_STD_2525b, {
//this is shorthand for a function that returns feature.properties.code
codeFunction: "code"
})
Customizing the styling of the symbol
In practice, you may need to modify the styling of the symbol according to some properties of the military symbology specification, your own preferences, or a combination of both.
For example, Program: Setting up a symbology painter to paint bodies and labels of military icons and tactical graphics. illustrates how to paint military icon symbols and
tactical graphics and apply custom symbol styling, using the MilitarySymbologyPainter
and its constructor parameters.
samples/symbology/symbology/main.tsx
)
//The military standard this painter should paint.
return new MilitarySymbologyPainter(symbology, {
codeFunction: function(feature: Feature): string {
//We return the SIDC of the military symbol
return feature.properties.code;
},
modifiers: function(feature: Feature): any {
//We return the modifiers in the properties of our feature.
//These include both text modifiers and graphical modifiers, as defined
//in the MS2525 and APP6 specifications.
return feature.properties.modifiers;
},
style: function(feature: Feature, paintState: PaintState): MilSymStyle {
//We return our style. Note that it is also possible to have feature-specific
//styling if you choose to use the feature parameter.
return {
selectionColor: "#FF9900",
// The body will not be drawn if there is a feature property "body" that is set to false.
// If so, a skeleton (tactical graphic without details and decorations) will be drawn.
body: feature.properties.body ?? true,
// The skeleton will be drawn if there is no body, or, as a selection style on top of the body
// on WebGL maps (this allows immediate response upon selection).
skeleton: !(feature.properties.body ?? true) || (paintState.selected),
// A selection rectangle will be drawn for icons when selected.
rectangle: paintState.selected,
affiliationColor: {
Friend: feature.properties.friend || FRIEND_COLOR,
Hostile: HOSTILE_COLOR
},
lineWidth: feature.properties.lineWidth,
iconSize: feature.properties.iconSize,
cornerSmoothness: feature.properties.cornerSmoothness,
haloColor: (paintState.hovered && !paintState.selected) ? "rgba(255,255,255,0.7)"
: feature.properties.haloColor,
haloWidth: (paintState.hovered && !paintState.selected) ? 2 : feature.properties.haloWidth,
};
},
width: function(feature: Feature): number {
//We return the width we use for arrow-type tactical graphics.
return feature.properties.width;
}
});
For simple properties, it’s possible to use strings as a parameter instead of functions. This is a shorthand notation for properties that exist within the feature properties. The example below uses short-hand strings instead of functions wherever possible to achieve the same result as Program: Setting up a symbology painter to paint bodies and labels of military icons and tactical graphics..
[[shorthand_symbology_painter, Program: Setting up a symbology painter using the shorthand notation for retrieval of simple properties]] .Program: Setting up a symbology painter using the shorthand notation for retrieval of simple properties
const symbologyPainter = new MilitarySymbologyPainter(
//The military standard this painter should paint.
MIL_STD_2525b, {
//this is shorthand for a function that returns feature.properties.code
codeFunction: "code",
//this is shorthand for a function that returns feature.properties.modifiers
modifiers: "modifiers",
style: function(feature) {
return {
selectionColor: "#FF9900",
affiliationColors: {
"Friend": "rgb(128, 224, 255)",
"Hostile": "#FF8080"
},
lineWidth: 2,
iconSize: 64
};
},
//this is shorthand for a function that returns feature.properties.width
width: "width"
}
);
Customizing the styling of a label
Since LuciadRIA allows you to use HTML and CSS to style labels, you can modify the labels
of military symbols by overriding the CSS styling properties of the lcdSymbologyLabel
CSS class.
An example is provided in the sample below.
/*Configuring the labels of the symbology*/
.luciad .lcdSymbologyLabel {
font-family: Arial, monospace;
font-weight: normal;
color: white;
font-size: 10px;
text-shadow: 0 0 5px rgba(0, 0, 0, 1)
}
Movement direction arrows
LuciadRIA shows movement direction arrows for moving symbols. Ground units have an arrow starting from a vertical stem.
The following modifiers affect the arrows:
-
movementDirection
: a number indicating the heading of the object. Must be an azimuth: degrees, clock-wise, 0 is north. -
speedLabel
: a string expressing the movement speed, for example17 km/h
or11 kn
. Affects the length of the arrow. Only relevant for APP-6C and MIL-STD-2525C.
The length of the arrow is determined by the existing style property iconSize
in combination with the speedLabel
modifier if available.
The line-width of the arrow is determined by the existing style properties lineWidth
.
In 3D, ground units have no stem.
Creating a new Symbol
You can use a CreateController
to create a new military icon or tactical graphic, just like you would ordinarily do to
create shapes in LuciadRIA.
The SymbologyNode.createTemplates()
method creates a list of Shape
objects that match the nature of the military symbol.
Alternatively, if you want to provide your own custom geometry for the tactical graphics, you can use
the ShapeFactory.createShape()
method.
Program: Setting up the method CreateController.onCreateNewObject(map,layer)
. illustrates the recommended way to create a new symbol.
Create a new shape, and then create a new Feature
that includes the shape and the desired properties.
CreateController.onCreateNewObject(map,layer)
. (from samples/symbology/components/CreationPanel.tsx
)
// SampleCreateController is a CreateController that is re-used throughout RIA samples.
// It adds two-step Cancellation on Escape keypresses and creates undoables for created shapes.
class SymbologyCreateController extends SampleCreateController {
private readonly _symbology: HierarchicalSymbology;
private readonly _code: string;
constructor(symbology: HierarchicalSymbology, code: string) {
super(ShapeType.POINT);
this._symbology = symbology;
this._code = code;
}
onCreateNewObject(map: RIAMap, layer: Layer) {
return new Feature(
this._symbology
.getSymbologyNode(this._code)!
.createTemplates(layer.model!.reference, 0, 0, 1.6)?.[0] ?? null,
{
code: this._code,
symbology: this._symbology,
}
);
}
onObjectCreated(map: RIAMap, layer: FeatureLayer, object: Feature) {
addCreateFeatureUndoable(map, layer.model, object);
return Promise.resolve(layer.workingSet.add(object)).then(() => {
//select the created object (standard action is adding without selecting)
map.selectObjects([
{
layer,
objects: [object],
},
]);
});
}
}
The |
For more information about creating and working with a SymbologyNode
, refer to Using a symbology node.
Creating a preview image of a Symbol
You can use the MilitarySymbologyPainter.createSymbolImage(feature, size)
to create a preview HTLMImageElement
of a symbol. Figure 1, “The Military Symbols Sample demonstrates a few of the available military symbols” shows an example of such a symbol preview.
Program: getting a preview image CreationPanel.getInstructions(…​)
. illustrates the recommended way to create a symbol preview.
Create a template shape, and then create a new Feature
that includes the shape and the desired properties.
With that Feature
, ask the Painter
to generate a preview.
CreationPanel.getInstructions(…​)
. (from samples/symbology/components/CreationPanel.tsx
)
const layer: FeatureLayer = layerMap.get(symbology) as FeatureLayer;
const painter: MilitarySymbologyClusteringPainter = (layer.painter as MilitarySymbologyClusteringPainter);
const shape = symbologyNode.createTemplates(layer.model!.reference, 0, 0, 0.5)?.[0] ?? null;
const properties = {
code: symbologyNode.code,
symbology: symbology,
modifiers: {}
}
const feature = new Feature(shape, properties, 1);
const size: number = minPointCount === 0 ? 100 : 150;
return painter.createSymbolImage(feature, size)
.then(function(previewImage: HTMLImageElement | null) {
Manipulating symbol properties
In the APP6 and MS2525 standards, the visualization of a symbol depends on the type of the symbol, and on a variety of symbol attributes. For example, a symbol can have an affiliation such as "Friend", "Neutral", or "Hostile", or it can show the status of an action. An action can have a "Planned" or "Anticipated" status, for example.
The military symbology standard defines which modifiers are allowed for each symbol. The section Using a hierarchical symbology explains how you can import a symbology standard, and retrieve particular symbols for it. These components do not allow you to edit any properties, however.
To modify the properties of a symbol, LuciadRIA offers the symbology.military.MilitarySymbol
component.
This object allows you to manipulate the attributes of a symbol, and read out the code of that symbol. Program: Changing the properties of a symbol and retrieving the associated code.
shows how you can create a new MilitarySymbol
, modify its properties and read out the correct symbol code.
samples/allsymbols/main.tsx
)
const symbol = new MilitarySymbol(symbology, child.code);
for (const modifier in symbol) {
if (symbol.hasOwnProperty(modifier)) {
const possibleValues = symbol.possibleValues(modifier);
if (possibleValues !== null) {
//using a randomised value for a modifier with possible values
const index = random.nextInt(possibleValues.length);
(symbol as any)[modifier] = possibleValues[index]!;
} else {
//using a default value for a modifier that has no defined possible values
if (MODIFIER_DEFAULTS.hasOwnProperty(modifier)) {
(symbol as any)[modifier] = (MODIFIER_DEFAULTS as Record<string, string>)[modifier];
}
}
}
}
Symbol icons from the Symbology Service
The Symbology Service
is a web service that serves MS2525/APP6
icons with specified styling information. See the LuciadFusion Defense Symbology
component documentation for more details on setting up and configuring the symbology service.
LuciadFusion still makes this service available, but LuciadRIA no longer needs it, nor uses it to show Military Symbology icons. LuciadRIA now generates the icons on the client.