The drawing add-on adds functionality to Lucy for drawing various shapes, such as points, polylines, polygons, buffers, and so on, on the map in multiple drawing layers.

Overview

The drawing add-on is the add-on that creates and registers the TLcyDrawingFormat. This format supports drawing models containing a variety of domain objects. The domain objects are typically drawn and manipulated by the end user. The TLcyDrawingDataModelDescriptor of the model contains the definition of the model properties. The TLcyDrawingFormat encodes/decodes its model in/from an extension of the OGC Geography Markup Language (GML). The schema for this format can be found as drawing.xsd in the Lucy distribution.

The drawing add-on is designed in such a way that all logic relevant to a specific kind of domain object — for instance, a circle, an ellipse, or a polyline — is grouped in an ALcyDomainObjectSupplier. Most of the interaction with the domain objects therefore happens through this supplier. This design makes the format very extensible. Supporting a new kind of shape, for instance MIL-STD 2525 symbols, is realized by adding a new ALcyDomainObjectSupplier instance. See the next sections for more information.

The TLcyDrawingFormat also adds an ALcyFormatBar. See Format Bar documentation for more information about format bars. This format bar is typically available below the map component when a drawing layer is selected. It displays a toolbar with many buttons to create and manipulate the various shape domain objects in the selected drawing layer. Figure 1, “Overview of the TLcyDrawingAddOn.” shows the drawing add-on and its most important classes in a UML diagram.

drawing addon overview
Figure 1. Overview of the TLcyDrawingAddOn.

The domain object supplier

The most important class in extending and customizing the drawing format is ALcyDomainObjectSupplier. This class groups all functionality related to a specific type of domain object in a single class. Its functionality consists of three major groups.

Model

An ALcyDomainObjectSupplier instance is used as a factory to create new domain objects. It also provides functionality for object conversion (ALcyDomainObjectConverter). The basic responsibility of a converter is to convert a domain object from one model to another. This is basically a clone operation with appropriate model transformations applied, for example, from a geodetic reference to a grid reference. The converter is also used for extruding domain object. It can also provide adapters to allow interaction with domain objects according to a given interface. This converter is used in many places in the drawing add-on. For instance, the drag-and-drop functionality uses the converter to copy and paste domain objects. Various actions in the toolbar also rely on the converter to interact with the domain objects. For instance, the create dome action uses the converter to adapt a domain object into an ILcdCircle from which it can easily create an appropriate dome. To allow editing of all properties of a domain object, the ALcyDomainObjectSupplier also provides an ILcyCustomizerPanelFactory.

Painting and editing

The supplier is a provider for painters and editors. As such, it has complete control over the handling of geometries and styling.

File format

When a drawing model is saved in, or loaded from the drawing file format, an extension of GML, the domain object suppliers are used to (un)marshall the shapes they are responsible for. As such, each domain object can have a specialized XML representation that is appropriate to completely describe its state. The ALcyDomainObjectSupplier realizes this by providing appropriate XML marshallers and unmarshallers. See the LuciadLightspeed XML documentation for more information about the XML framework that is used for this.

The following figure shows this structure in a UML class diagram.

domain object supplier
Figure 2. Class diagram for ALcyDomainObjectSupplier.

This design allows for a very heterogeneous drawing model. The only constraint on a domain object is that there must be an ALcyDomainObjectSupplier in the TLcyDrawingFormat that can handle it. Adding a new domain object instance to a drawing model is typically done as follows. First, an appropriate domain object supplier is selected. There are various methods on TLcyDrawingFormat to access the existing domain object suppliers. To make finding a specific domain object supplier easier, each supplier is given a unique ID. The ID’s of the default suppliers can be found as constants on TLcyDrawingFormat. Note that the instance of TLcyDrawingFormat can easily be retrieved from the drawing add-on instance. Once the domain object supplier is found, it is asked to create a new domain object. This object can then be added to the drawing model.

Adding custom domain object types

An important feature of this design is the ability to add support for new kinds of shapes. This includes adding a button to the toolbar that adds the shape to the drawing layer and providing painters, editors and appropriate customizers for properties of these new shapes. The file format can be extended such that new shapes can also be read from and written into this format.

As an ALcyDomainObjectSupplier instance represents the complete functionality for a certain domain object, adding (or removing) support for a domain object is therefore equivalent to adding or removing an instance of this class. The TLcyDrawingFormat comes into play here. It serves as manager of all domain object suppliers. It provides methods to add (addDomainObjectSupplier(ALcyDomainObjectSupplier)) and remove instances (removeDomainObjectSupplier(ALcyDomainObjectSupplier)). Note that adding and/or removing domain object suppliers is only supported during the add-on initialization phase, when no drawing layers exist.

All suppliers typically have an active settable in the drawing toolbar to start creating a new domain object by clicking on the map. This settable is automatically created. The only thing that needs to be done to make the active settable appear is to configure it properly in the drawing add-on configuration file (see Layout of the drawing toolbar).

The lucy.drawing.customdomainobject sample shows how to add a custom domain object. It implements a custom ALcyDomainObjectSupplier extension and registers a new instance to the drawing format. Look at this example to learn more details about how to create your own ALcyDomainObjectSupplier.

SLD

In many cases, the functionality of an ALcyDomainObjectSupplier can be split in two distinct parts. On the one hand there is functionality that is specific to the geometry of the shape. For instance, drawing a circle is different from drawing a polygon. On the other hand there is functionality that does not depend on geometry. An example here is for instance supporting metadata (properties) or style information. To support this common case, the drawing add-on provides TLcySLDDomainObjectSupplier as an extension of ALcyDomainObjectSupplier that implements this pattern. This class uses a separate ALcyShapeSupplier class for all geometry-specific functionality. All default domain object suppliers of the drawing add-on use this extension.

SLD domain objects

In this extension, domain objects are TLcySLDDomainObject instances. This class implements ILcdShapeList, but instances will always contain exactly one ILcdShape. This shape is typically a standard LuciadLightspeed shape such as for instance a TLcdXYCircle or a TLcdLonLatHeightBuffer. In case of grouping, the shape is an ILcdShapeList containing the grouped domain objects. In case of extruded shapes, the shape is an ILcdExtrudedShape.

TLcySLDDomainObject keeps track of the properties of the shape and therefore implements ILcdDataObject. Style information is also kept in the TLcySLDDomainObject in a SLD style. This style is used during painting and contains the correct fill color, font information, icons, and so on. Figure 3, “The model of the default drawing format.” shows this in a UML diagram.

drawing domain model
Figure 3. The model of the default drawing format.

Each drawing model has also one TLcyDrawingStyleRepository that is accessible through the TLcyDrawingDataModelDescriptor. This repository is used to store permanent styles that need to be stored and restored even if no domain object is currently using them. These styles are encoded and decoded together with the rest of the model. The lucy.drawing.styles sample gives an example of how this repository can be used.

SLD domain object supplier

TLcySLDDomainObjectSupplier is the specialized ALcyDomainObjectSupplier that handles the TLcySLDDomainObject instances. This supplier has an associated ALcyShapeSupplier that is responsible for shape-specific functionality. Functionality that is common is handled by the TLcySLDDomainObjectSupplier itself. Figure 4, “Class diagram for TLcySLDDomainObjectSupplier and ALcyShapeSupplier.” shows this in a UML diagram.

sld domain object supplier
Figure 4. Class diagram for TLcySLDDomainObjectSupplier and ALcyShapeSupplier.

TLcySLDDomainObjectSupplier creates TLcySLDDomainObject instances as model object. This happens as follows. First, the TLcySLDDomainObjectSupplier asks its associated ALcyShapeSupplier to create a new shape. The domain object supplier then selects an appropriate style for this shape. Then a new TLcySLDDomainObject instance is created and returned. This object can then be added to the drawing model. Figure 5, “Creating domain objects.” shows this in an interaction diagram.

creating domain objects
Figure 5. Creating domain objects.

To allow editing the properties of a drawing shape, the TLcySLDDomainObjectSupplier provides an ILcyCustomizerPanelFactory (see Customizer Panels documentation for more details about customizers in Lucy). This factory creates a ILcyCompositeCustomizerPanel containing customizers for (1) editing the properties and (2) extrusion properties and (3) one or more customizers for the geometry properties of the shape. The latter customizers are created using the factories supplied by ALcyShapeSupplier.createShapeCustomizerPanelFactories. An ALcyShapeSupplier should also provide an ALcyShapeCodec. This codec is needed, among other things, to implement undo in the customizers, to clone shapes and to implement shape conversion.

For painting, TLcySLDDomainObjectSupplier separates styling from geometry. Styling is implemented based on the SLD implementation provided by LuciadLightspeed (consult for more info on this the LuciadLightspeed Developer’s Guide). The basic idea here is that the painters provided by ALcyShapeSupplier are only concerned with the geometry. So no fill or line style, colors, and so on, are taken into account. From the point of view of the ALcyShapeSupplier, this means that it doesn’t have to provide a normal ILcdGXYPainter, but instead a set of painters (one for strokes, one for fills, and so on). The TLcyShapePainterProviderContainer class facilitates this. The styling characteristics are retrieved from the TLcdSLDFeatureTypeStyle instance associated with the domain object.

For (un)marshalling drawing shapes to the drawing file format, TLcySLDDomainObjectSupplier takes care of styling and metadata properties. The ALcyShapeSupplier only needs to provide support for its specific shape.

Custom shapes

The introduction of ALcyShapeSupplier makes adding custom shapes even more simple. In cases where this separation of style and geometry is applicable, new types of domain objects can be supported by registering new TLcySLDDomainObjectSupplier instances with an appropriate ALcyShapeSupplier. This is usually much more simple then creating a new ALcyDomainObjectSupplier from scratch because a lot of the functionality is already handled by TLcySLDDomainObjectSupplier.

The sample lucy.drawing.hippodrome shows how to add a hippodrome shape. It is based on the existing LuciadLightspeed hippodrome sample and defines a HippodromeShapeSupplier. Look at this example to learn more details about how to create your own ALcyShapeSupplier.

Configuration

The TLcyDrawingAddOn.cfg properties file allows many properties of the drawing add-on to be configured. The following paragraph provide some more details on some important parts. The file itself is also documented with many comments explaining the different properties.

Similar to the toolbar of a map component or Lucy’s menu bar, the toolbar of the drawing add-on can be fully customized. It can be customized in the configuration file of the drawing add-on in the same fashion the other menu bars and toolbars can be customized. Please refer to Action Bars documentation to learn how to do this customization. The name of the drawing toolbar is drawingToolBar.

Apart from the menu- and toolbar items, there is one more important part of the Drawing add-on that can be customized: predefined layers. With predefined layers, one can provide the default properties a Drawing layer should have and its default model reference. Program: The properties in config/lucy/drawing/TLcyDrawingAddOn.cfg that determine the predefined layers. shows the relevant section of the configuration file that configures the predefined layers. The result of this sample configuration is shown in Figure 6, “The resulting dialog that is shown when creating a Drawing layer.”.

Program: The properties in config/lucy/drawing/TLcyDrawingAddOn.cfg that determine the predefined layers.
TLcyDrawingAddOn.defaultFeatures.names=NAME, Population, Capital
TLcyDrawingAddOn.defaultFeatures.classes=String, Integer, Boolean
TLcyDrawingAddOn.defaultReference=lucy/drawing/defaultReference.ref
TLcyDrawingAddOn.allowCustomLayers=true
predefined layer
Figure 6. The resulting dialog that is shown when creating a Drawing layer.

Drawing in Lightspeed views

To visualize drawing layers in a Lightspeed view, the TLcyLspDrawingFormat is introduced. This format is designed in a similar way to the TLcyDrawingFormat:

To support a custom domain object with custom styling in Lightspeed, you’ll need to create both an ALcyDomainObjectSupplier and a ALcyLspDomainObjectSupplier extension. The lucy.drawing.customdomainobject sample shows how to do this.

Similarly, if you want to support a custom shape that uses the default SLD styling, you only need to create a ALcyShapeSupplier and ALcyLspShapeSupplier. This is shown in the lucy.drawing.hippodrome sample.