You are displaying the symbols defined in Military Symbology standards MIL-STD 2525 or APP-6 in your LuciadLightspeed application. Now, to fulfill specific requirements of your project, you need to decorate the standard symbology icons with your custom icons.

Why do it?

LuciadLightspeed provides military symbols that comply with the MIL-STD 2525B/C and APP-6A/B/C standards, but you may need to extend those standards to add your own symbology set.

How does it work?

A military symbol is either a TLcdEditableAPP6AObject or TLcdEditableMS2525bObject instance. You can create an ILcdIcon instance from a military symbol by using TLcdMS2525bObjectIconProvider or TLcdAPP6AObjectIconProvider, depending on the standard you are using. This ILcdIcon instance is a visual representation of the military symbol. LuciadLightspeed internally creates different visual representations of a military symbol, using symbol properties such as SIDC, affiliation, and echelon.

militarysymbols
Figure 1. Military symbols

To customize the visual representation of a symbol, you have to combine the created ILcdIcon instance of the symbol with your own ILcdIcon objects.

For more information about the support that LuciadLightspeed offers for military symbology, see the Military Symbology documentation.

How to do it?

To illustrate how to decorate symbols with icons, we are going to add an 'Operational' icon to a MIL-STD 2525 motorized infantry symbol.

LuciadLightspeed allows you to add more than decoration icon to a symbol if you need to.

Create a composite icon to represent the symbol

The first step of implementing this behavior is creating the visual representation of the decorated symbol.

Program: Obtaining an icon instance
    //First, we obtain a MIL-STD 2525 ILcdIcon instance from the related ILcdObjectIconProvider instance.
    //create an unknown motorized infantry
    TLcdEditableMS2525bObject symbol = new TLcdEditableMS2525bObject("10011000001211040000", ELcdMS2525Standard.MIL_STD_2525d);
    ILcdIcon symbolIcon = new TLcdMS2525bObjectIconProvider().getIcon(symbol);

Then, we need to load our decoration icon and resize it to the size of symbol icon, so that we can nicely align the two icons. SVG icons such as in the code below allow you to do this:

decorationicon
Figure 2. Decoration icon
Program: Resizing the decoration icon to the symbol icon
    TLcdSVGIcon svgIcon = new TLcdSVGIcon("operational.svg");
    svgIcon.setSize(symbolIcon.getIconWidth(), symbolIcon.getIconHeight());

Now that we have our two icons, we need to merge them into a TLcdCompositeIcon instance. TLcdCompositeIcon is an implementation of ILcdResizableIcon. This means that we need to wrap our symbol icon instance with a TLcdResizableIcon before putting it inside [TLcdCompositeIcon.

Program: Merge icons into composite icon
    TLcdCompositeIcon compositeIcon = new TLcdCompositeIcon();
    //wrap the symbol icon with a TLcdResizableIcon
    compositeIcon.addIcon(new TLcdResizeableIcon(symbolIcon));
    compositeIcon.addIcon(svgIcon);

Now we have the visual representation of the icon.

Implement the domain object, an icon provider, and a styler for the symbol

Next, we need to implement a domain object, as well as an icon provider and a styler for the decorated symbol domain objects.

Program: Create the domain object
  private static class MyDomainObject extends TLcdLonLatPoint {

    private final ILcdIcon fIcon;

    public MyDomainObject(ILcdIcon aIcon) {
      fIcon = aIcon;
    }

    public ILcdIcon getIcon() {
      return fIcon;
    }
  }
Program: Create the icon provider
  private static class MyIconProvider implements ILcdObjectIconProvider {

    @Override
    public ILcdIcon getIcon(Object aObject) throws IllegalArgumentException {
      if (canGetIcon(aObject)) {
        return ((MyDomainObject) aObject).getIcon();
      }
      throw new IllegalArgumentException("Object should be an instance of MyDomainObject : " + aObject);
    }

    @Override
    public boolean canGetIcon(Object aObject) {
      // get an icon only from a MyDomainObject instance
      return aObject instanceof MyDomainObject;
    }
  }
Program: Create the styler
  private static class MyStyler extends ALspStyler {

    private static final ILcdObjectIconProvider fIconProvider = new MyIconProvider();

    @Override
    public void style(Collection<?> aObjects, ALspStyleCollector aStyleCollector, TLspContext aContext) {
      for (Object object : aObjects) {
        if (fIconProvider.canGetIcon(object)) {
          TLspIconStyle iconStyle = TLspIconStyle.newBuilder()
                                                 .icon(fIconProvider.getIcon(object))
                                                 .build();

          aStyleCollector.object(object)
                         .style(iconStyle)
                         .submit();
        }
      }
    }
  }

Visualize the decorated symbol

After creating the model with the domain objects, we are ready to visualize the decorated symbol.

Program: Visualize the decorated symbol
    MyDomainObject domainObject = new MyDomainObject(compositeIcon);
    TLcdVectorModel ms2525Model = new TLcdVectorModel(new TLcdGeodeticReference(), new TLcdModelDescriptor());
    ms2525Model.addElement(domainObject, ILcdModel.NO_EVENT);
    ILspInteractivePaintableLayer ms2525Layer = TLspShapeLayerBuilder.newBuilder()
                                                                     .model(ms2525Model)
                                                                     .bodyStyler(TLspPaintState.REGULAR, new MyStyler())
                                                                     .build();
decoratedsymbol
Figure 3. Decorated symbol visualized