This guide explains how to apply custom styling to layers created by the MGCP layer builders.

The MGCP module provides the styling specified by the MGCP Portrayal Standard, version 2.0.1. Some data sets may contain information that is generated for the MGCP 1.0 specification, with f-codes that are no longer supported in MGCP 2.0.1, or they may contain data that is not MGCP-compliant.

All objects for which no style is available within the MGCP 2.0.1 standard specification, are styled with these defaults:

  • Lines: red 0.1mm solid line

  • Areas: red 0.1mm solid red line applied to the perimeter, filled with 25% transparent red

  • Points: red filled circle, diameter 0.5mm

In some cases, you may need to override the default styling of objects.

This guide describes how to apply a custom style to objects. As an example, we will apply a different fill and outline style to objects with the f-code "EC030" (Wood).

The f-code property

The code examples in this article use the hard-coded property name "FCODE" for getting the f-code from a data object. Some data sets may use another name, such as "f-code", "fCode", and so on.

For both GXY and Lightspeed views, we wrap the layer factory in a new custom layer factory.

Custom MGCP styling in Lightspeed views

In a Lightspeed view, styling is done by a ILspStyler that is placed on the TLspLayer instance.

By wrapping the provided styler in a new styler, you can change the default visualization of the MGCP data.

private static final class CustomStyler extends ALspStyler {
  private final ILspStyler fDelegate;
  private final ALspStyle fFillStyle;
  private final ALspStyle fLineStyle;

  public CustomStyler(ILspStyler aDelegate) {
    fDelegate = aDelegate;
    fFillStyle = TLspFillStyle.newBuilder().color(new Color(192, 192, 0, 64)).build();
    fLineStyle = TLspLineStyle.newBuilder().color(new Color(192, 192, 0)).width(2).build();
  }

  @Override
  public void style(Collection<?> aObjects,
                    ALspStyleCollector aStyleCollector,
                    TLspContext aContext) {
    Function<ILcdDataObject, String> toFCode = o -> (String) o.getValue("FCODE");
    Map<String, List<ILcdDataObject>> byFCode = aObjects.stream()
                                                        .map(ILcdDataObject.class::cast)
                                                        .collect(Collectors.groupingBy(toFCode));
    for (Map.Entry<String, List<ILcdDataObject>> entry : byFCode.entrySet()) {
      if (entry.getKey().equals("EC030")) {
        for (ILcdDataObject dataObject : entry.getValue()) {
          aStyleCollector.object(dataObject)
                         .geometry(ALcdShape.fromDomainObject(dataObject))
                         .styles(fFillStyle, fLineStyle)
                         .submit();
        }
      } else {
        fDelegate.style(entry.getValue(), aStyleCollector, aContext);
      }
    }
  }
}

To apply the new styler to all layers that are created by the ILspLayerFactory, we also need to wrap that layer factory in a new layer factory:

public static ILspLayerFactory createCustomLayerFactory(TLspMGCPLayerFactory aLayerFactory) {
  return new ILspLayerFactory() {
    @Override
    public boolean canCreateLayers(ILcdModel aModel) {
      return aLayerFactory.canCreateLayers(aModel);
    }

    @Override
    public Collection<ILspLayer> createLayers(ILcdModel aModel) {
      Collection<ILspLayer> layers = aLayerFactory.createLayers(aModel);
      layers.forEach(l -> {
        TLspLayer mgcpLayer = (TLspLayer) l;
        ILspStyler delegate = mgcpLayer.getStyler(TLspPaintRepresentationState.REGULAR_BODY);
        mgcpLayer.setStyler(TLspPaintRepresentationState.REGULAR_BODY,
                            new CustomStyler(delegate));
      });
      return layers;
    }
  };
}
Applying custom styles on labels in Lightspeed views

For styling labels, you also need to create a custom ILspStyler in an analogous way. It is also placed on the layer with the same TLspLayer.setStyler method, but with a TLspPaintRepresentationState for labels.

Custom MGCP styling in GXY views

In a GXY view, styling is done by a ILcdGXYPainterProvider that is placed on the TLcdGXYLayer instance.

By wrapping the default provider in a new painter provider, you can change the default visualization of the MGCP data.

private static final class CustomPainterProvider implements ILcdGXYPainterProvider {

  private final ILcdGXYPainterProvider fDelegate;
  private final TLcdGXYShapePainter woodPainter;

  public CustomPainterProvider(TLcdGXYLayer aMGCPLayer) {
    fDelegate = aMGCPLayer.getGXYPainterProvider();

    Color lineColor = new Color(192, 192, 0);
    Color fillColor = new Color(192, 192, 0, 64);
    woodPainter = new TLcdGXYShapePainter();
    woodPainter.setLineStyle((graphics, _1, _2, _3) -> graphics.setColor(lineColor));
    woodPainter.setFillStyle((graphics, _1, _2, _3) -> graphics.setColor(fillColor));
  }

  @Override
  public ILcdGXYPainter getGXYPainter(Object aObject) {
    if (aObject instanceof ILcdDataObject) {
      ILcdDataObject dataObject = (ILcdDataObject) aObject;
      Object fcode = dataObject.getValue("FCODE");
      if (fcode.equals("EC030")) { // Wood
        woodPainter.setObject(dataObject);
        return woodPainter;
      }
    }
    return fDelegate.getGXYPainter(aObject);
  }

  @Override
  public Object clone() {
    try {
      return super.clone();
    } catch (CloneNotSupportedException aE) {
      throw new RuntimeException(aE);
    }
  }
}

To apply the new styler to all layers that are created by the ILcdGXYLayerFactory, we also need to wrap that layer factory in a new layer factory:

public static ILcdGXYLayerFactory createCustomLayerFactory(TLcdMGCPGXYLayerFactory aLayerFactory) {
  return new ILcdGXYLayerFactory() {
    @Override
    public ILcdGXYLayer createGXYLayer(ILcdModel aModel) {
      TLcdGXYLayer mgcpLayer = aLayerFactory.createGXYLayer(aModel);
      if (mgcpLayer != null) {
        mgcpLayer.setGXYPainterProvider(new CustomPainterProvider(mgcpLayer));
      }
      return mgcpLayer;
    }
  };
}
Applying custom styles on labels in GXY views

For styling labels, you need to create a new ILcdGXYLabelPainterProvider in an analogous way. It is placed on the layer by using the TLcdGXYLayer.setGXYLabelPainterProvider() method.