-
Notifications
You must be signed in to change notification settings - Fork 1
Technical documentation (WIP)
You will find the following folder in the medInria sources.
├── app
├── cmake
├── doc
├── src
├── src-plugins
└── utils
-
src
contains a bunch of libraries providing all what is needed by both plugins and application. This includes various abstractions used throughout the application (ie: views, process, data, etc.). These abstraction are grouped in "layers" (ie:medProcessLayer
,medGuiLayer
etc.). Several layers can be found in one library if there is dependences between them. Implementations of those abstraction can be accessed dynamically via a dedicated factory and comes from a plugin or directly defined in the application. See the plugins section for more details. Other class used in both plugins and the application, but not loaded dynamically are also present. It is the case for all class deriving frommedAbstractParameter
for example. -
app
contains themain
function and the creation of the main widget composing the application. It is linked and use the header of the libraries insidesrc
. see the [application architecture](#application architecture) section for more details -
src-plugins
contains a bunch of plugins embedded by default in the public version of medInria.
Each abstraction of concept that we want to be dynamically loadable in medInria are provided via "layers" which regroup all the concept of a generic theme. For example the layer medProcessLayer
regroup all the different kind of process used in medInria (medAbstractSubtractImagesProcess
, medAbstractErosionProcess
, etc.)
Those layers are accessible via a lib (for example medCore
) in a dedecated folder located in src.
For example, let's say that we want to add the concept of medAbstractArea
. It's a GUI element, so it will be provided by the medGui
layer in the medCore
library
In addition of the medAbstractArea
class, we have a class for the plugin itself medAbstractAreaPlugin
that will have a concrete implementation for each plugin that specialize medAbstractArea.
There is also tow other classes medAbstractAreaPluginManager
that will have the role of loading the plugin at the start-up of the application and medAbstractAreaPluginFactory
that will have the role of returning a medAbstractArea*
of a concrete implementation defined in a plugin. The implementation is classically chosen from one (or many) identifier (a QString
).
The layer also give utility functions to access the plugin manager, launch the initialization and access the factory. Those function are keep in namespaces. For example to access the medAbstractAreaPluginFactory
:
medGuiLayer::area::pluginFactory()
Finally here is what it look likes on the file system:
src
├── CMakeLists.txt
├── medCore
│ ├── CMakeLists.txt
│ ├── gui
│ │ ├── area
│ │ │ ├── medAbstractArea.cpp
│ │ │ ├── medAbstractArea.h
│ │ │ ├── medAbstractAreaPlugin.cpp
│ │ │ └── medAbstractAreaPlugin.h
│ │ ├── medGuiLayer.cpp
│ │ ├── medGuiLayer.h
The utility function of the layer are in the medGuiLayer
files and the medAbstractAreaPluginManager
medAbstractAreaPluginFactory
classes are defined in the medAbstractAreaPlugin
files.
Now let's say that we want to make a plugin to provide a new class medFooArea
derived from medAbstractArea
.
It just need a class for medFooArea
and a class for medFooAreaPlugin
which inherits from medAbstractAreaPlugin
. This class will have to implement the initialize method which record the medFooArea
type to the medAbstractAreaPluginFactory
. In other words it will add an entry to a map of the factory where a function pointer that return an instance of medFooArea
is associated to an identifier.
ex:
void medFooAreaPlugin::initialize(void)
{
medGuiLayer::area::pluginFactory().record("medFooArea",
medFooAreaCreator);
}
Here is what the plugin will look likes on the file system:
medFooArea
├── CMakeLists.txt
├── medFooArea.cpp
├── medFooArea.h
├── medFooAreaPlugin.cpp
├── medFooAreaPlugin.h
└── medFooAreaPlugin.json
The json
file is used by Qt
during the loading of the plugin. It contains some information on the plugin like its name, a version number, a list of dependences etc.
The last step is to used the plugin in the application. To do it, it first need to load and initialize the plugins of all the needed layers. This is made at the start-up of the application in void medApplication::initialize()
:
void medApplication::initialize()
{
[...]
// gui layer:
// medGuiLayer::area::pluginManager().setVerboseLoading(true);
medGuiLayer::area::pluginManager().initialize(pathToThePluginLocation);
}
After that, whenever you want to get an instance of medFooArea
in the application you can use the factory:
medAbstractArea* fooArea = medGuiLayer::area::pluginFactory().create("medFooArea");
The list of all the type knowns by the factory is accessible via
QStringList medAbstractAreaPluginFactory::keys()
In medInria views are used to display on a widget one or several data. It provide the widget where the data are displayed as well as toolbar, toolboxes, etc, used to interact with the view.
Those interaction are done via object called interactors and navigators. They can be added dynamically in plugins.
Interactors handle all the interaction with one data in the view ie: changing the window-level of an image, change the colour of a surface, etc. Navigators handle interaction with only the view. This is mainly anything that may concern the camera. Panning, zoom, etc.
To let the interactors and navigators modify the state of the view from a plugin, the view provide a pointer to a medViewBackend
which is an empty class that can be extended to encapsulate the object requisite to manipulate the view.
Example:
class MEDVTKINRIA_EXPORT medVtkViewBackend : public medViewBackend
{
public:
medVtkViewBackend(vtkImageView2D * view2D_, vtkImageView3D * view3D_, vtkRenderWindow * renWin_);
vtkImageView2D * view2D;
vtkImageView3D * view3D;
vtkRenderWindow * renWin;
};
There is three level of view:
-
medAbstractView
It is the base class for any view. ExtendmedAbstractView
if you want view type that allow you to display one data at a time -
medAbstractLayerView
Provide the management of a stack of layer. Extend this class if you need to display several data in the view. -
medAbstractImageView
Provide the management a camera. Extend this class if you need to display your data in a three dimensional space.
Each of this level have this corresponding navigators and interactors (medAbstractLayerViewInteractor
, medAbstractImageViewInteractor
, etc.)
Interactors are used to change the way one particular data is displayed. For example in a view containing a grayscale image the interactor will allow you to change the window-level, the opacity, etc. It also construct the widgets used to drive those interactions.
Each data dropped in a view have at least one interactors called primary intercator
. It has to inherit from medAbstractLayerViewInteractors
if the base class of the view is medAbstractLayerView
, medAbstractImageViewInteractors
for medAbstractImageView
etc. In addition a data can also have other interactors called extra interactors
, they can inherits just from medAbstractInetractors
. The purpose of the extra interactors is to allow someone to add new way to interact with one particular type of data in a new plugin.
Navigators works almost like interactors except that there only one primary navigators for one view, plus optional extra navigators.
The purpose of concept of parameter in medInria is to encapsulate a value of a particular type, provide widgets to modify this value and offer a mean to keep several parameter representing the same thing (ie: the opacity of an image, a LUT used to visualized a mesh, etc.) synchronized between them.
Eeach one of this parameter is identified by a name (QString
) all the parameter having the same name inside a medParameterPool
are synchronized between them.
Here is a list (non exhaustive) of parameters that you can find in medInria:
medBoolParameter
medIntParameter
medDoubleParameter
medStringListParameter
medVector2DParamter
medVector3DParamter
medTriggerParameter
medCompositeParameter
medTriggerParameter
doesn't encapsulate any value, it just emit a triggerd
signals, if a button is clicked for example.
medCompositeParameter
encapsulate a list of values via a QMap<QString, QVariant>
. The keys of the QMap
is play the role of identifier for each QVariant
. The idea is to trigger
the update of all those values at the same time when one of them is changing. This is done for performance purpose (example: if the window-level of an image change we want to update at the same time the window and the level, if the position of the camera change we want to update it in three axes at the same time, etc.).