LuciadLightspeed provides an easy transition path to convert your application to use a Lightspeed view. It allows for a quick upgrade of standard GXY layer implementations, which speeds up rendering when painting many objects or displaying complex visualizations such as hypsometry data and density plots. At the same time, you can keep certain existing GXY layer implementations and the code interacting with it. Refer to Benefits of Lightspeed views for more information on the benefits of using Lightspeed rendering.

Converting a GXY view to a Lightspeed view and Converting a GXY layer to a Lightspeed layer highlight the most important similarities and differences you must keep in mind when moving your view and your layers. Adapting GXY layers discusses how to adapt your custom GXY layer implementations to a Lightspeed view.

Converting a GXY view to a Lightspeed view

In many aspects, a Lightspeed view is similar to a GXY view: it also has a specific world reference and separates its content into layers that are added, removed, moved and retrieved, just as in an GXY view. TLspViewBuilder provides a convenient way to set up a Lightspeed view, as demonstrated in Creating the map.

The default Lightspeed view (TLspAWTView), unlike its GXY counterpart (for example, TLcdMapJPanel), is in itself not a Java Component. This means that existing instanceof checks and cast operations in your code may fail. Instead, you can retrieve the view’s host component by calling the getHostComponent method. As an added convenience, the view also exposes an overlay panel to insert Java Component instances on top of the view (see the getOverlayComponent method).

A Lightspeed view comes by default with a controller for panning, zooming, selecting and editing, but you can create your own controller or chain of controllers. For more information, see Introduction to controllers. In addition, TLspViewNavigationUtil offers functionality to fit and center on layers.

Setting the number of cached background layers is no longer necessary in a Lightspeed view: a Lightspeed layer can indicate whether it is a background layer or not. See the getLayerType method in ILspLayer for more information.

An ILspView picks up elevation data automatically if the data is visualized in a TLspRasterLayer and one of the following conditions is fulfilled:

  • The data is part of an ILcdEarthTileSet with a CoverageType.ELEVATION type.

  • The data is part of an ILcd(Multilevel)Raster. The model descriptor is a TLcd(Multilevel)RasterModelDescriptor, and its isElevation() method returns true.

The combined elevation data of a view can be accessed from ILspView.getServices().getTerrainSupport(). If layers with elevation data overlap, the elevation of the top-most layer will be selected.

Converting a GXY layer to a Lightspeed layer

The Lightspeed equivalent of a ILcdGXYLayer is an ILspInteractivePaintableLayer. ILspInteractivePaintableLayer paints and styles the objects of its model using stylers, and optionally uses one or more ILspEditor instances to edit these objects. The default ILspInteractivePaintableLayer implementation is TLspLayer.

Raster and vector layers

A raster layer is particularly easy to convert. A special layer builder, TLspRasterLayerBuilder, allows you to visualize any model with an ILcdRaster, ILcdMultilevelRaster, or ILcdEarthTileSet, without any configuration. Simply create an ILspLayer using the builder, add it to your view, and you are ready to go.

Similarly, you can use TLspShapeLayerBuilder for vector layers. This builder creates layers that can paint all LuciadLightspeed shapes. Hence, there is no need for a specific circle, point list, or icon painter.

Paint representations

LuciadLightspeed allows you to visualize many different representations of the same object. All these visualizations use the same painter interface: ILspPainter.

As opposed to the requirements of a GXY layer, there is no need for a special label painter interface in a Lightspeed layer. Instead, you can configure different painters for different paint representations, including labels.

See Introduction to labeling vector data for more information.

Styling

LuciadLightspeed has an elaborate API for styling, from line types and fill colors to icons and label content. The styling API can be used to replace most, if not all, of your custom GXY layer implementations.

A major difference with GXY view styling is that Lightspeed view styling can be configured per object. To achieve this, Lightspeed painters map styles onto objects using an ILspStyler. A TLspStyler returns the same style(s) for every object, and is particularly useful when you are replacing GXY painters. This is illustrated in Introduction to styling vector data.

While styling is usually performed by the painter, most of the Lightspeed layer implementations implement ILspStyledLayer, allowing you to directly configure styling by calling setStyler.

To see other examples of layer and painter styles, have a look at the many Lightspeed samples on labels, icons, and styling. Note that no explicit layer invalidation is necessary when you change a styler.

Adapting GXY layers

For some custom layer implementations; such as layers with a custom painter or custom styling, you might prefer to keep the entire layer implementation. In that case, you can add the GXY layer to a Lightspeed view by wrapping it into an adapter. For performance reasons, the adapter will paint the original layer implementation in another thread.

This process is similar to using an ILcdGXYAsynchronousLayerWrapper (see Asynchronous painting in GXY views). Converting such layers is often only a matter of replacing your ILcdGXYAsynchronousLayerWrapper with a Lightspeed TLspGXYLayerAdapter and adjusting some calls.

Program: Using an adapter to include an ILcdGXYLayer in an ILspView (from samples/lightspeed/integration/gxy/AdaptedLayerFactory)
TLspGXYLayerAdapter adapter = new TLspGXYLayerAdapter((ILcdGXYLayer) aLayer);

As an added bonus, the Lightspeed layer adapter will work in both 2D and 3D Lightspeed views.

Using a layer adapter in 2D

The 2D rendering of layer adapters is similar to the rendering of asynchronously painted layers in an ILcdGXYView. The active Lightspeed controller deals with layer interaction, such as selection and editing.

The following restrictions apply in 2D views:

  • No support for interactive labels. These are labels that respond to mouse and keyboard input to let users modify object properties.

  • No support for view-wide label placement: label placers only take the objects within a layer into account, and can no longer handle all the objects visible in the view.

Using a layer adapter in 3D

As opposed to a GXY view, a Lightspeed view can display 3D content. A TLspGXYLayerAdapter is capable of displaying the GXY layers in 3D, with the following restrictions:

  • All 2D restrictions listed in Using a layer adapter in 2D

  • No interaction

  • The two-dimensional content is rendered onto small image tiles which are combined together and draped on the world. Because of this, view-dependent content, such as labels, may be cut off at the tile boundaries.

Safely accessing adapted layers

Like all Swing/AWT/JavaFX components, the Lightspeed view implementations and its layers are accessed and manipulated on the toolkit thread — the Event Dispatch Thread (EDT) for Swing or the JavaFX Application Thread — with the exception of TLspOffscreenView.

To ensure performance, a TLspGXYLayerAdapter paints its GXY layer in a separate thread. However, a GXY layer in itself is not thread-safe. Therefore, you must take special care before accessing or modifying an adapter’s wrapped layer. A safe way to retrieve and modify the wrapped layer is to ask the layer adapter to execute the modification code at a safe point in time, on an appropriate thread. The adapter provides the methods invokeAndWaitOnGXYLayer and invokeLaterOnGXYLayer for this purpose:

  • The method invokeAndWaitOnGXYLayer executes a given runnable on the caller’s thread (usually the EDT) when the adapter is not painting. The method receives the wrapped layer as an argument and it can safely work on it. Use this method when you need the operation to complete before carrying on with the rest of your code.

  • The method invokeLaterOnGXYLayer executes a given runnable on the asynchronous painting thread. The method receives the wrapped layer as an argument. The method must not invoke any blocking methods on the toolkit thread, such as using SwingUtilities.invokeAndWait, because this might result in dead-locks. Use this method when you do not want to wait for the operation to complete, for example to prevent the blockage of the toolkit thread.

For more information on thread safety for asynchronously painted layers, refer to Asynchronous painting in GXY views and Threading and locking in LuciadLightspeed.

Editing the model of an adapted wrapped layer

You need to edit the model of a wrapped layer in a thread-safe way, because the model is being painted in a separate painting thread. The layer adapter guards asynchronous read access by means of read locks on the model, as described in Accessing asynchronously painted layers. Any code that modifies the model or its elements therefore has to make sure that it obtains a write lock on the model, as shown in Threading and locking in LuciadLightspeed.

Labeling adapted layers

GXY labeling is distinct from Lightspeed labeling. However, the layer adapter is capable of applying a GXY labeling algorithm to its wrapped layer. To configure this algorithm, call setGXYLayerLabelingAlgorithm.

As an alternative if you are using a TLcdGXYLayer, you can set up a layer label painter on this layer by calling setGXYLayerLabelPainter.

In both cases, label decluttering will only happen for the GXY layer itself. The decluttering process will not take into account other GXY or Lightspeed layers.

Adapting layer tree nodes

TLspGXYLayerTreeNodeAdapter is an ILcdGXYLayer adapter that can have Lightspeed child layers. Therefore, to adapt an entire ILcdLayerTreeNode, all its children need to be adapted as well. This is illustrated in Program: Using an adapter to include a layer tree node in an ILspView.

Program: Using an adapter to include an ILcdLayerTreeNode in an ILspView (from samples/lightspeed/integration/gxy/AdaptedLayerFactory)
private static TLspGXYLayerAdapter adapt(ILcdLayer aLayer) {
  if (aLayer instanceof ILcdLayerTreeNode) {
    return adaptNode((ILcdLayerTreeNode) aLayer);
  } else if (aLayer instanceof ILcdGXYLayer) {
    @SuppressWarnings("UnnecessaryLocalVariable")
        TLspGXYLayerAdapter adapter = new TLspGXYLayerAdapter((ILcdGXYLayer) aLayer);
    return adapter;
  } else {
    throw new IllegalArgumentException("Cannot handle : " + aLayer.getClass());
  }
}

private static TLspGXYLayerTreeNodeAdapter adaptNode(ILcdLayerTreeNode aLayerTree) {
  // adapt the node
  TLspGXYLayerTreeNodeAdapter adapter = new TLspGXYLayerTreeNodeAdapter((ILcdGXYLayer) aLayerTree);
  adapter.setPaintOnTopOfChildrenHint(aLayerTree.isPaintOnTopOfChildrenHint());
  adapter.setInitialLayerIndexProvider(aLayerTree.getInitialLayerIndexProvider());
  for (int i = 0, n = aLayerTree.layerCount(); i != n; i++) {
    ILcdLayer layer = aLayerTree.getLayer(i);
    // adapt the child layers as well
    adapter.addLayer(adapt(layer));
  }

Layer adapter performance tips

Just as with asynchronous layer wrappers in ILcdGXYView instances, you can reduce the compositing overhead for multiple adapted layers if you make them adjacent. This means that, for the best performance, all adapters should be stacked on top of one another, and no regular (non-adapter) layer should be inserted in between the adapters.