Opticks Developer Guide/Concepts
This sections describes some of the main concepts for working with Opticks. The first section describes the plug-in architecture.
Plug-In Architecture
editThe Opticks plug-in architecture enables developers to easily add capability for import, processing, and export of remote sensing data. Upon startup, Opticks scans the plug-in directory for Opticks plug-ins. Any new plug-ins are automatically registered and the functionality becomes available for use. As new plug-ins become available, the Opticks main application doesn't need to be updated. This enables multiple teams of developers to quickly, independently create capability.
As shown in the diagram on the right, the plug-in architecture is made up of the Opticks main application, modules, and plug-ins. A module packages one or more plug-ins in a DLL or shared object and defines the interface through which Opticks will load a plug-in. A module is also a convenient place to put code that is shared by more than one plug-in. For example, the diagram shows the NITF importer and exporter in the same module since they share code to read and write the NITF file format.
A plug-in is implemented as a C++ class. To create a plug-in you simply inherit from one of several pre-defined plug-in class types and add your own capability. The following table shows the basic plug-in types:
- Algorithm - A general processing and exploitation algorithm.
- Exporter - A plug-in to save data.
- Georeference - A plug-in that supports adding a new type of georeferencing algorithm.
- Importer - A plug-in used to load data.
- Interpreter - Scripting language support.
- RasterPager - A plug-in for dynamically requesting raster "pixel" data.
- Viewer - A plug-in that supports basic modeless dialogs.
As shown in the diagram, Opticks provides common services to the plug-ins. These are all accessed through the common Service class. ApplicationServices, DesktopServices, ModelServices, and PlugInManagerServices are some of the main services. Check the Service documentation for a full list. Each of the services are obtained in the same way and provides methods for the plug-in to communicate with Opticks.
- ApplicationServices provides access to configuration settings and session information.
- DesktopServices gives access to Opticks’s main display mechanisms It provides capability to create workspace windows, dockable windows, and toolbars.
- ModelServices provides access to data elements within the active session.
- PlugInManagerServices provides plug-ins with the ability to access other available plug-ins.
ModuleManager
editModules are implemented through the ModuleManager class. The class is declared in the ModuleManager.h header file included in the ‘include’ directory with the Opticks software development kit (SDK). A default implementation is provided in the ModuleManager.cpp source file. The plug-in developer should take the default ModuleManager.cpp source file provided and modify it to describe the module being developed. The ModuleManager.h header file should not be modified.
There are module setting variables that are declared in ModuleManager.h and defined in ModuleManager.cpp that describe the module. These modules settings include module name, version, description, and a unique module identifier string. The ModuleManager also has a method called getPlugIn(). This method is used by Opticks to get the plug-in class. This method takes an index as an argument that specifies which plug-in should be returned, with zero indicating the first plug-in. The implementation of getPlugIn() in the default ModuleManager.cpp source file should be edited to create and return your plug-ins. The code snippet below shows a possible implementation of the getPlugIn() method for a module containing two plug-ins: an importer and an exporter.
PlugIn* ModuleManager::getPlugIn(unsigned long plugInNumber) { PlugIn* pPlugIn = NULL; switch (plugInNumber) { case 0: // Get importer plug-in pPlugIn = new NitfImporter(); break; case 1: // Get exporter plug-in pPlugIn = new NitfExporter(); break; default: break; } return pPlugIn; }
Each plug-in shouldn't be in its own module, too many modules can significantly increase the Opticks load time.
Plug-Ins
editA plug-in can be started in either interactive mode or batch mode. A plug-in executed in interactive mode typically uses a dialog to request information from the user. The user inputs are then used for further execution of the plug-in. On the contrary, a plug-in executed in batch mode should not have user interface components to obtain necessary input from the user, but rather should require those inputs to be present in the plug-in’s input argument list. This means that the plug-in may have different number of arguments in interactive mode and batch mode.
Shell classes are built for each plug-in type. These shell classes can be used as a starting point to create a plug-in. AlgorithmShell, ExporterShell, GeoreferenceShell, ImporterShell, InterpreterShell, RasterPagerShell, and ViewerShell are a few examples. The shell implements common functionality for that plug-in type. For example, the diagram below shows the NITF Exporter inheriting from the ExporterShell class. The ExporterShell implements many of the common methods. The plug-in developer should inherit from the shell class, overload the methods, and use the Opticks Services to implement their unique functionality.
Most shell classes inherit from the PlugIn and Executable interfaces. These common plug-in interfaces provide the Opticks with a standard way of interacting with the plug-in. PlugIn provides a common class used to describe the plug-in. This includes information like plug-in name, version, description, and menu location. Executable is a very powerful common interface that enables all plug-ins to be called in a common way.
The Executable interface enables Opticks to determine plug-in input and output parameters, to specify whether the plug-in is going to be run in batch or interactive mode, and to execute the plug-in. This interface enables the analyst to use the Opticks Wizard Builder to chain together algorithms and automate common tasks.
class Executable { ... bool setBatch() = 0; bool setInteractive() = 0; bool getInputSpecification(PlugInArgList*& pArgList) = 0; bool getOutputSpecification(PlugInArgList*& pArgList) = 0; bool execute(PlugInArgList* pInArgList, PlugInArgList* pOutArgList) = 0; bool abort() = 0; ... }
The getInputSpecification() and getOutputSpecification() methods specify the input and output parameters of a plug-in. The setBatch() and setInteractive() methods serve two purposes, to inform the plug-in that it should be executed in batch mode or interactive mode and to query whether the mode is supported by the plug-in. The execute() method starts the plug-in and can be called by Opticks or by another plug-in. The abort() method is called by the Opticks when the user clicks the Cancel button in the progress dialog or it can be called by another plug-in.