Terrain analysis add-ons
The Terrain Analysis (TEA) add-ons provide a wide range of terrain analysis functions, with matching graphical user interfaces. The TEA functionality has been implemented in six different add-ons:
- TLcyContourAddOn:
-
computes and visualizes height lines for
ILcdShape
objects; - TLcyExtremePointAddOn:
-
computes and visualizes highest and lowest points for
ILcdShape
objects; - TLcyHypsometryAddon:
-
computes and visualizes hypsometric information for a given layer or the entire view;
- TLcyLOSCoverageAddOn:
-
computes and visualizes line-of-sight coverages (LOS coverages). LOS coverages show the altitude under which aircraft (or helicopters) have to stay in order not to be detected by the radar;
- TLcyVisibilityAddOn:
-
computes and visualizes what parts of one or more objects can be seen from one or more other objects;
- TLcyTEAControllerAddOn:
-
shows a tooltip for elevation data and allows you to inspect the height of an area specified by a line segment.
- TLcyViewshedAddOn:
-
computes and visualizes visibility for a 3D scene composed of terrain, buildings and 3D meshes.
Note that all these add-ons require the Terrain Analysis Engine component. For more information on this component, please consult the TEA developer’s guide.
|
Except for the controller add-on, all TEA add-ons consist of 4 important parts:
-
a back-end class, providing access to the non-GUI related TEA functionality;
-
a GUI factory, creating all GUI elements;
-
a data format, providing persistence for the TEA analysis results;
-
the add-on class itself, which is plugged into Lucy. It binds together the previously mentioned parts.
The controller add-on only contains a back-end class and the add-on class.
Figure 1, “TEA add-on structure” shows the typical structure of a deployed TEA add-on.

The GUI actions do not depend on GUI elements, but rather on a central ALcyProperties
object, in which GUI elements may freely read and write properties.
The GUI actions pass the necessary properties to the back-end methods in order to compute TEA results.
The computed results, as well as the GUI property values used to compute them, are then stored in the appropriate TEA layer.
The structure and API of these classes gives you the possibility to customize the TEA add-ons in many different ways:
- Change the back-end
-
plug in new algorithms, or change the behavior of the existing ones;
- Change the GUI
-
replace, omit, and add GUI elements, or simply write an entirely new GUI;
- Customize the data format
-
change the layer style or write out TEA results to your custom file format.
The next sections detail how to perform such customizations.
Customizing the GUI
The TEA add-on’s GUI is built around actions, components and panels. The GUI factory is built so that every existing action, component and panel can be replaced. The first step to customize the GUI consists of subclassing the add-on’s GUI factory and subclassing the add-on to return the custom factory. This way, you can easily tap into the various creation methods of the GUI factory.
Adding a GUI element simply comes down to overriding ALcyGUIFactory.createPanel
to add your custom element to an existing panel.
When you want to replace a GUI element, for example to change its appearance, you can override ALcyGUIFactory.createComponent
and return you custom element for the respective GUI identifier.
For more information, we refer to the ALcyGUIFactory
's reference manual.
The add-on’s application pane tool by default instantiates the GUI using the workspace’s composite workspace preferences. This means that all GUI elements will
retrieve and store their values to and from the same ALcyProperties
object, as shown in Figure 1, “TEA add-on structure”.
The Update action stores a selection of these properties for the selected layer (see the reference documentation for more information).
Conversely, the application pane tool updates the properties if a different TEA layer is selected by the user.
If you want your GUI value to be linked in this way, simply define a property name for it, store it in the composite workspace
preferences, and make sure that your GUI element is updated upon any change of the property.
If your GUI value is to be stored in the workspace or if it must be parsed from the add-on’s configuration file, you might
have to register a ILcyPropertyConverter
for it. For the TEA add-ons, you can add a custom property converter by overriding the createPreferencesTool
method.
Customizing the back-end
Every TEA add-on has a specific method that creates its back-end. For example, for TLcyExtremePointAddOn
this is createExtremePointBackEnd
.
You can override this method to return a subclassed implementation of the add-on’s back-end.
It is a good idea to pass the addon’s composite workspace preferences to your back-end. This way, you can easily access your
custom GUI values, as well as the existing ones.
As an example, sometimes it is insufficient to use the height provider factories registered in the ILcyLucyEnv
to retrieve the height data used for the TEA calculations. For example when buildings are added that are placed upon the
terrain. In that case, it is possible to use a custom altitude provider in TEA by overriding the createAltitudeProvider
method in the back-end.
Customizing the data format
The add-on creates the format by calling its createBaseFormat
method. The latter method’s reference documentation describes the model content.
The format is easily customized by creating a wrapper for it.
For example, to add reading from and writing to your own custom format, you can add your own model decoder and encoder. To
change the layer style of a created layer, you could wrap the format’s layer factory and perform your changes after the former
finished the creation.
An extension example
As an example, we create a custom line-of-sight coverage add-on that adds a propagation function to the existing list. The actual propagation function is beyond the scope of this sample, so we will just make it return a fixed visibility value. Figure 2, “Adding a custom propagation” shows the desired result of our TEA customization.

The sample works as follows:
-
a new back-end
LOSCoverageBackEnd
subclassesTLcyLOSCoverageBackEnd
and overridescreatePropagationFunction
,retrievePropagationFunctionLabel
, andcreatePropagationMatrixRasterValueMapper
. It adds functionality to these methods for a new propagation function if the passedPROPAGATION_FUNCTION_KEY
argument equals a newly defined constantPROPAGATION_CUSTOM_ID
. This can be seen in Program: A TEA line-of-sight back-end extension adding a custom propagation function; -
a new GUI factory
LOSCoverageGUIFactory
subclassesTLcyLOSCoverageGUIFactory
and overridescreatePanel
. It replaces the style panel, so we can add our own style GUI elements for our custom function. This can be seen in Program: A TEA line-of-sight GUI factory extension replacing the style panel; -
the main add-on class
LOSCoverageAddOn
extends fromTLcyLOSCoverageAddOn
and redefinescreateLOSCoverageBackEnd
andcreateGUIFactory
to return our new back-end and GUI factory. This can be seen in Program: A TEA line-of-sight add-on extension returning our own back-end; -
the add-on’s configuration file is changed so that our propagation function (the String value of
PROPAGATION_CUSTOM_ID
) is added to the propagation function list. We could also have done this by changing the GUI preferences'PROPAGATION_LIST_KEY
property.
samples/lucy/gxy/tea/LOSCoverageBackEnd
)
public class LOSCoverageBackEnd extends TLcyLOSCoverageBackEnd {
/**
* The property name for our custom propagation function.
*/
public static final String PROPAGATION_CUSTOM_ID = "customPropagation";
@Override
public ILcdLOSPropagationFunction createPropagationFunction(ALcyProperties aProperties) {
if (PROPAGATION_CUSTOM_ID.equals(aProperties.getString(PROPAGATION_FUNCTION_KEY, ""))) {
return new LOSPropagationFunction();
}
return super.createPropagationFunction(aProperties);
}
samples/lucy/gxy/tea/LOSCoverageGUIFactory
)
public class LOSCoverageGUIFactory extends TLcyLOSCoverageGUIFactory {
public LOSCoverageGUIFactory(ILcyLucyEnv aLucyEnv) {
super(aLucyEnv);
}
@Override
protected Component createPanel(int aID, ALcyProperties aProperties) {
if (aID == STYLE_PANEL) {
return createStylePanel(super.createPanel(aID, aProperties), aProperties);
}
return super.createPanel(aID, aProperties);
}
}
samples/lucy/gxy/tea/LOSCoverageAddOn
)
public class LOSCoverageAddOn extends TLcyLOSCoverageAddOn {
@Override
protected TLcyLOSCoverageBackEnd createLOSCoverageBackEnd() {
return new LOSCoverageBackEnd(getLucyEnv());
}
@Override
protected ALcyGUIFactory<Component> createGUIFactory() {
return new LOSCoverageGUIFactory(getLucyEnv());
}
}