Model data files
You can add support for custom data formats to Lucy, so that it is possible to read and display the data in Lucy. To add basic support for a format, so that you can read and visualize the data, you must provide Lucy with at least two things:
- To read data
-
Add classes to Lucy that can convert a file to an
ILcdModel
. AnILcdModel
is a logical representation of the file data. The conversion is handled by anILcdModelDecoder
. For example, anILcdModelDecoder
could convert the information in a POL file to anILcdModel
containing polygons, lines, and so on. - To visualize data
-
Add classes to Lucy that can visualize the information contained in your
ILcdModel
instances. The visualization is handled by anILcdLayer
.
For more information on ILcdModelDecoder
instances, ILcdModel
instances, ILcdLayer
instances and their relationship, see LuciadLightspeed core concepts and Model reading and writing. The best practices sample of Lucy contains a sample implementation of an ILcdModelDecoder
that demonstrates the responsibilities of an ILcdModelDecoder
.
Working with the Lucy add-ons for model decoding
Lucy comes with all necessary add-ons to add the formats supported by LuciadLightspeed to Lucy. The TLcyDefaultDecodersAddOn
adds the formats that are supported by LuciadLightspeed, while the formats that depend on a LuciadLightspeed component, ECW
for instance, each have their own add-on. If you want to add support for a custom data format to Lucy, you can register an
ILcdModelDecoder
that can decode this format with Lucy. ILcyLucyEnv
provides these methods for the accounting of ILcdModelDecoder
instances, inherited from ILcyModelDecoderContainer
:
-
addModelDecoder( ILcdModelDecoder, ALcyFileTypeDescriptor )
adds theILcdModelDecoder
and the correspondingALcyFileTypeDescriptor
. -
removeModelDecoder( ILcdModelDecoder )
removes theILcdModelDecoder
and the correspondingALcyFileTypeDescriptor
. -
getModelDecoderCount
returns the number of addedILcdModelDecoder
objects. -
getModelDecoder( int )
retrieves theILcdModelDecoder
at the given index. -
getDecoderFileTypeDescriptor( int )
retrieves theALcyFileTypeDescriptor
at the given index.
When you register an ILcdModelDecoder
, you can specify an ALcyFileTypeDescriptor
. This is a descriptor that provides the user with a high-level description of the file types that can be decoded with the
ILcdModelDecoder
. When your decoder is not file-based, but reads data from a database for instance, you can specify null
as the file type descriptor. You can make your own implementation of ALcyFileTypeDescriptor
, or you can use TLcyFileTypeDescriptor
and just provide it with a display name and a list of extensions.
The file type descriptors are intended to be used to provide quick filtering of a directory listing for instance. Such a list
could contain thousands of files. Therefore, when you implement the |
If you want to decode a certain source to a ILcdModel
in your add-on, you can use the composite model decoder of Lucy. This decoder, which you can retrieve with the getCompositeModelDecoder
method of ILcyLucyEnv
, will decode the given source name with the first registered ILcdModelDecoder
that reports it can decode this source name. Lucy also contains a composite data source handler for the registered ALcyDataSourceHandler
instances.
Note that you can override the ILcdInputStreamFactory
used to load the data by registering your own in Lucy. You can do this either directly on the Lucy environment, or through
the composite factory TLcyCompositeInputStreamFactory
. Most built-in formats will use the composite factory to create an InputStream
. Notable exceptions are geotiff
, jpeg
, jai
, mrsid
and dimap
. If you want to write your own ILcdModelDecoder
, it is advised to use TLcyCompositeInputStreamFactory
as well.
Handling arbitrary non-model data files
Lucy also reads files that do not result in an ILcdModel
. As such, you cannot use a ILcdModelDecoder
to read these files. A workspace file is one example of this case. To read those kinds of files, Lucy works with ALcyDataSourceHandler
objects. An ALcyDataSourceHandler
is similar to an ILcdModelDecoder
, but instead of decoding the source to a model, a ALcyDataSourceHandler
can handle the source any way it wants in the method handleDataSource( String aSourceName, Object aTarget )
.
For the accounting of ALcyDataSourceHandler
objects, you can call the getCompositeDataSourceHandler()
method of TLcyDataFormatManager
of ILcyLucyEnv
. It provides:
-
addDataSourceHandler( ALcyDataSourceHandler, ALcyFileTypeDescriptor )
adds theALcyDataSourceHandler
and the correspondingALcyFileTypeDescriptor
. This file type descriptor serves the same purpose as for anILcdModelDecoder
. -
removeDataSourceHandler( ALcyDataSourceHandler )
removes theALcyDataSourceHandler
and the correspondingALcyFileTypeDescriptor
. -
getDataSourceHandlerCount
returns the number of addedALcyDataSourceHandler
objects. -
getDataSourceHandler( int )
retrieves theALcyDataSourceHandler
at the given index. -
getFileTypeDescriptor( int )
retrieves theALcyFileTypeDescriptor
at the given index.
Exporting and saving models
If you want to write model data to the new file format, you need to add an ILcdModelEncoder
to Lucy. For this purpose, ILcyLucyEnv
is an extension of ILcyModelEncoderContainer
. The addition of ILcdModelEncoder
instances is similar to the addition of ILcdModelDecoder
instances. Lucy uses these encoders when you click the Save as…​ menu item, for instance. Lucy will ask all registered encoders if they can encode the model of the selected layer using the
method canEncode( ILcdModel, String )
. All the encoders that can encode the model will be presented as a choice in the File type combo box of the file chooser. The user can then select in which format the file should be saved, or in other words, which
ILcdModelEncoder
should be used. Finally, the model is saved with the selected ILcdModelEncoder
to the specified destination name.
Note that you can override the ILcdOutputStreamFactory
used to save the data by registering your own in Lucy. You can do this either directly in the Lucy environment, or through
the composite factory TLcyCompositeOutputStreamFactory
. Most built-in formats will use the composite factory to create an OutputStream
. If you want to write your own ILcdModelEncoder
, it is advised to use TLcyCompositeOutputStreamFactory
as well.
Working with file type filters
When Lucy users open a file with the File→ Open menu item, the file type filter mechanism gives them the possibility to choose which files they want to see. The corresponding
drop-down box contains a list of group filters, followed by a sorted list of single-typed filters. The single-typed filters
represent the ALcyFileTypeDescriptor
instances registered together with the ILcdModelDecoder
instances and ALcyDataSourceHandler
instances. For a discussion about how these are registered, see Model data files and Handling arbitrary non-model data files. The group filters will combine a number of single-file-type filters. Lucy always contains the "All Known Files" filter,
which represents all registered single-file-type filters. Some add-ons, such as the TLcyDefaultDecodersAddOn
, will register the group filter "All Vector Files" or "All Raster Files", representing all vector or all raster files. You
can add other groups using getCompositeFileTypeDescriptorGroup()
on the TLcyDataFormatManager
of ILcyLucyEnv
. The best practices sample of Lucy shows how you can do that.
Opening a file in Lucy
The TLcyDataFormatManager
class contains two methods called handleDataSources
, which are used when a file is opened in Lucy:
-
If
handleDataSources
is invoked withoutILcdModelDecoder[]
andALcyDataSourceHandler[]
arrays, it goes over all registeredILcdModelDecoder
instances and asks each of them if they can decode a source with a particular name, using the methodcanDecodeSource( String )
. Lucy also uses the methodcanHandleDataSource( String aSourceName, Object aTarget )
on all registeredALcyDataSourceHandler
instances to ask them if they can handle the file. If multiple decoders/handlers report that they can decode/handle the source name, Lucy lets the user select the decoder or handler. The selectedILcdModelDecoder
orALcyDataSourceHandler
then decodes or handles the specified source name.You can replace this selection logic by setting a new
TLcyDataFormatManager.ALcyHandlerChooser
toTLcyDataFormatManager
. See the API reference for more details.When an
ILcdModelDecoder
has been selected, a layer is created and added to the map so that the data is visualized. -
The second
handleDataSources
method allows you to specify whichILcdModelDecoder
andALcyDataSourceHandler
objects should be used instead of all the registered ones.
If certain files fail to open on the map component specified in the call of handleDataSources
, an TLcyDataFormatManager.ALcyMapComponentChooser
will be used to choose another map
component to open the files on.
Registering an ILcyDataSourceListener to listen for file handling events
If a user opens multiple files, error messages should pop up once for each handled group of files. The model reference chooser
has an OK for All button to allow the user to choose a model reference once for a group of files. To accomplish this, ILcyDataSourceListener
instances are registered to ILcyLucyEnv.getDataFormatManager()
. Currently they can listen to two events:
-
A
TLcyDataSourceEvent
with IDTLcyDataSourceEvent.HANDLING_STARTED
, fired before the handling. -
A
TLcyDataSourceEvent
with IDTLcyDataSourceEvent.HANDLING_ENDED
, fired after the list of data sources is handled.
As intended, listeners can collect error messages between the two events, for example, and can show a combined message when the HANDLING_ENDED event is received. If no HANDLING_STARTED event is fired, the listeners should display a pop-up error message for each problem.
Registering and using ILcdModelHeightProviderFactory for height data
If a format contains height data, you must register an ILcdModelHeightProviderFactory
with the ILcyLucyEnv
. You can do this through the method ILcyLucyEnv.addService()
. Lucy then uses these registered height provider factories to retrieve height values. When you are implementing new functionality
in Lucy that uses height data, you should use these registered factories. This is demonstrated in the following code:
ILcdModelHeightProviderFactory
instances is used to create a height provider.
//Create a composite factory based on all ILcdModelHeightProviderFactory instances
//registered on the Lucy backend
TLcyCompositeModelHeightProviderFactory compositeFactory =
new TLcyCompositeModelHeightProviderFactory(lucyEnv);
// Create a set of required and optional properties.
Map<String, Object> requiredProperties = new HashMap<>();
requiredProperties.put(ALcdModelHeightProviderFactory.KEY_GEO_REFERENCE, reference);
Map<String, Object> optionalProperties = new HashMap<>();
// Create a height provider using the composite height provider factory.
ILcdHeightProvider heightProvider =
compositeFactory.createHeightProvider(model, requiredProperties, optionalProperties);
A useful class for registering and using ILcdModelHeightProviderFactory
instances is TLcyCompositeModelHeightProviderFactory
. Create an instance of this class using an ILcyLucyEnv
, and register height provider factories by adding them with TLcyCompositeModelHeightProviderFactory.addModelHeightProviderFactory()
. It then serves as a composite height provider factory that uses all registered ILcdModelHeightProviderFactory
instances registered in the ILcyLucyEnv
.
To retrieve height data from a view, use the class TLcyViewHeightProvider
. That class uses the registered height provider factories in the ILcyLucyEnv
to create a composite height provider from all models in the view that provide height data. It uses an instance of TLcyCompositeModelHeightProviderFactory
internally to do this.
Lightspeed views have a built-in height provider, which you can retrieve from the terrain support functionality of such a
view , through ILspView.getTerrainSupport
. See Visualizing terrain elevation in a Lightspeed view for more information.