Why do it ?

The Lucy UI allows the Lucy user to load and edit existing drawing files, or to create and populate a new drawing layer from scratch and save this data to disk. Lucy developers can perform the same operations through the API of the TLcyDrawingAddOn, which allows them to automate the creation and editing of drawing shapes.

Create a new drawing layer

Before you can create or edit any drawing shapes, you must make a drawing layer available:

  • The Lucy user can create such a layer through the UI, or open an existing drawing file. You can obtain a reference to that layer by iterating over all layers in the view, and searching for a layer which is accepted by the drawing format:

    Retrieve a drawing layer from a view
    // For GXY layers
    private ILcdGXYLayer findDrawingLayer(ILcdGXYView aView, ILcyLucyEnv aLucyEnv){
      Enumeration layers = aView.layers();
      TLcyDrawingAddOn drawingAddOn = aLucyEnv.retrieveAddOnByClass(TLcyDrawingAddOn.class);
      for(Object layer : layers){
        ILcdGXYLayer gxyLayer = (ILcdGXYLayer)layer;
        if (drawingAddOn.getFormat().isGXYLayerOfFormat(gxyLayer)){
          return gxyLayer;
        }
      }
      return null;
    }
    
    // For Lightspeed layers
    private ILspLayer findDrawingLayer(ILspView aView, ILcyLucyEnv aLucyEnv){
      Enumeration layers = aView.layers();
      TLcyLspDrawingAddOn drawingAddOn = aLucyEnv.retrieveAddOnByClass(TLcyLspDrawingAddOn.class);
      for(Object layer : layers){
        ILspLayer lspLayer = (ILspLayer)layer;
        if (drawingAddOn.getFormat().isLayerOfFormat(lspLayer)){
          return lspLayer;
        }
      }
      return null;
    }
  • The API user can create a drawing layer with the factories available in Lucy:

    Creating a drawing layer using the API
    TLcyDrawingDataModelDescriptor.Builder builder = TLcyDrawingDataModelDescriptor.Builder.newInstance();
    builder.sourceName(null) //null source as we create a model from scratch
           .displayName("My drawing model");
    
    //add some properties
    builder.addStringProperty("Name")
           .addIntegerProperty("Population");
    
    //build the model descriptor
    TLcyDrawingDataModelDescriptor descriptor = builder.build();
    
    //Create a model and layer using the available model factories and layer factories from Lucy
    ILcyLucyEnv lucy = ...;
    ILcdModel drawingModel = new TLcyCompositeModelFactory(lucy).createModel(descriptor, new TLcdGeodeticReference());
    
    ILcdGXYLayer gxyLayer = new TLcyCompositeGXYLayerFactory(lucy).createGXYLayer(drawingModel);
    Collection<ILspLayer> lspLayer = new TLcyLspCompositeLayerFactory(lucy).createLayers(drawingModel);

If you want to use the API to make the drawing tool bar available with a new drawing layer, you need to activate the Map | Drawing Bar active settable. How to gain programmatic access to an existing action explains how to gain access to an action or active settable through the API. In this case, the ID of the active settable is TLcyFormatBarAddOn.formatBarActiveSettable, the context is the map component and the action bar name is menuBar.

Create drawing domain objects

You can create drawing domain objects by invoking the ALcyDomainObjectSupplier.createDomainObject method:

Creating a new drawing domain object
ILcyLucyEnv lucy = ...;
ILcdLayer drawingLayer = ...;//see the previous section on how to get the drawing layer

ILcdModel drawingModel = drawingLayer.getModel();
TLcyDrawingFormat drawingFormat = lucy.retrieveAddOnByClass(TLcyDrawingAddOn.class).getDrawingFormat();

//In this example, we create a point
ALcyDomainObjectSupplier supplier = drawingFormat.getDomainObjectSupplierWithID(TLcyDrawingFormat#POINT_DOMAIN_OBJECT_ID);
if (supplier.canCreateDomainObject(drawingModel)){
  Object pointDomainObject = supplier.createDomainObject(drawingModel);
  //Modifying the model requires a write lock
  try(TLcdLockUtil.Lock autoUnlock = TLcdLockUtil.writeLock(drawingModel)){
    drawingModel.addElement(pointDomainObject, FIRE_LATER);
  } finally{
    drawingModel.fireCollectedModelChanges();
  }
}

At this point, the domain has been added to the model and will be painted on the map. Typically, you also want to modify the properties of the domain object. This is illustrated in the next section.

Modify the shape of a drawing domain object

You can use ALcyDomainObjectConverter instances to modify the shape of a drawing domain object:

Editing the geometry of a drawing domain object
ILcyLucyEnv lucy = ...;
ILcdLayer drawingLayer = ...;

ILcdModel drawingModel = drawingLayer.getModel();
Object pointDomainObject = ...;//The domain object created in the previous section

TLcyDrawingFormat drawingFormat = lucy.retrieveAddOnByClass(TLcyDrawingAddOn.class).getDrawingFormat();
ALcyDomainObjectConverter converter = drawingFormat.getDomainObjectConverter();

//In this example, we move the point we previously created to a new location
//As this modifies the model, we need to take a write lock on the model
try(TLcdLockUtil.Lock autoUnlock = TLcdLockUtil.writeLock(drawingModel)){
  if (converter.canAdapt(pointDomainObject, aModel, ILcd2DEditablePoint.class){
    ILcd2DEditablePoint editablePoint = converter.adapt(pointDomainObject, aModel, ILcd2DEditablePoint.class);
    editablePoint.move2D(30.0, 20.0);
    aModel.elementChanged(pointDomainObject, FIRE_LATER);
  }
} finally{
  aModel.fireCollectedModelChanges();
}

Copy-paste, import, extrude shapes

Copy-pasting objects between drawing models, importing shapes from other models, or extruding shapes can all be done with the ALcyDomainObjectConvertor, as illustrated with code snippets in the Javadoc of that class.