SoView2DExtensions¶
Introduction¶
The SoView2D
module allows the display of slices or slabs of an attached image volume in a 2D viewer. The functionality of the SoView2D can be extended using modules of the SoView2DExtension-framework. These modules fulfill several functions:
- Modification of the display of the image data in the viewer (Zooming, Panning, Slicing, Modification of the transfer function)
- Generation and modification of geometry (Markers, CSOs, etc.)
- Display of additional data/information (annotations, overlays, geometry including Open Inventor and GVR projected onto the slab)
General Usage and Scene Graph Traversal¶
Extensions are inserted into the scene graph to the left of the SoView2D. They are not treated like other Open Inventor nodes! Although they are traversed in the normal way (top to bottom, left to right), they are not drawn during traversal and do not evaluate events during traversal. The traversal serves only one purpose: all extensions that belong to a SoView2D are collected in a list. Once the SoView2D executes an action (drawing, event evaluation), it applies this action to the extensions in the list. The following image illustrates this behavior:
What happens during traversal?
SoView2DSlicePan
is added to the extension listSoView2DAnnotation
is added to the extension list- The action (drawing, event evaluation) is applied to the SoView2D. The SoView2D applies this action to the extensions in the list, starting with SoView2DSlicePan.
Common Parameters¶
There are several parameters that are common to all extensions. Most of them are normally hidden on the automatic panel. Not all of them are used in every extension!
Rendering¶
Field | Function |
---|---|
color | Color that should be used for drawing. |
drawingOn | Flag if the extension should draw itself. |
renderOnSlab | Defines if the extension should be rendered on all slab slices. |
clipToSlice | Flag if drawing should be clipped to slice. |
Events¶
Field | Function |
---|---|
color | Color that should be used for drawing. |
drawingOn | Flag if the extension should draw itself. |
renderOnSlab | Defines if the extension should be rendered on all slab slices. |
editingOn | Flag if the extension should edit objects on mouse events. |
selectionTolerance | The selection tolerance in pixels. |
setEventHandled | Flag if the event should be set ‘handled’ if it is indeed consumed by this extension. |
ignoreHandledEvents | Flag if events, that have been handled/consumed by previous extensions, should be ignored. |
button1 | Mouse mask for button 1 |
button2 | Mouse mask for button 2 |
button3 | Mouse mask for button 3 |
shift | Shift modifier for the mouse mask |
control | Control modifier for the mouse mask |
alt | Alt modifier for the mouse mask |
needsValidVoxel | If true, an event is only evaluated if it occurred on a valid voxel. |
maskValid | Indicates if the incoming event meets the criteria of the mouse mask. It is updated from inside the module. Do not set it! |
cursorShape | Set cursor shape if the mouse mask fits and mouseEvents are evaluated. |
wantsAllEvents | Flag if ALL events should be evaluated. If it is disabled, events are only evaluated if the mouse mask gets valid. However, consumed events will not be evaluated, if ignoreHandledEvents is set to true. |
wantsKeyEvents | Flag if keyboard events should be evaluated. |
wantsMouseWheelEvents | Flag if mouse wheel events should be evaluated. |
Mouse Masks¶
Incoming events can be filtered by button number and special keys. An event is processed only if the criteria for all buttons and special keys are met.
There are three states for a button and key filter:
- Pressed: the button or key must be pressed
- Released: the button or key must be released
- Ignored: the state of the button or key does not affect the processing of the event
The field maskValid indicates for an incoming event if it fulfills all criteria of the mask. This means, that every extension can be used to detect mouse clicks.
Event Handling and Consumption¶
Depending on the used mouse masks, several extensions might evaluate the same event. This can be avoided due to event consumption. This means that an extension can set an event as ‘handled’ (if the field setEventHandled is set to true) if the extension really performed an interaction.
Following extensions then can decide if they want to evaluate this event again (if ignoreHandledEvents is false) or ignore it (if ignoreHandledEvents is true).
Using this mechanism, several behaviors can be implemented. For example, while dragging a SoView2DPlane
, SoView2DSliceZoom
will not change the zoom factor. You do not need to assign different button and key masks to your extensions.
Evaluation Order¶
If certain extensions do not evaluate an event because it has been handled before, the order of event evaluation in the extensions becomes more important. The left-most extension is evaluated at first per default and therefore evaluates every event according to the mouse mask.
Following extensions might not evaluate the event because of the settings. Keep this in mind during scene graph design!
In most cases, it makes sense to arrange extensions that generate or modify geometry (SoView2DPlane
, SoView2DMarkerEditor
, etc.) to the left of extensions that do not need any clickable geometry (SoView2DSliceZoom
, SoView2DSliceShift
, SoView2DAutoCenter
,etc.).
Drawing Order¶
The evaluation order (left to right) is also used for drawing per default. That way, the right-most extension is drawn last and might occlude previous extensions. The result might be that a completely occluded extension evaluates an event while the visible one does not.
The SoView2D has a field reverseDrawingOrder that allows the inversion of this behavior. If it is set to true
, the right-most extension will be drawn first and the left-most last. The appearance matches the evaluation of the events in this case. The default value of this field is false
.
Cooperative Mode¶
In several modules (SoView2DMarkerEditor
, SoView2DRectangle
, SoView2DPosition
), there exists a “Cooperative”-mode that controls if the handled-flag of the event is set or read.
In those modules, setEventHandled and ignoreHandledEvents have no consequence at the moment (although they are available in the automatic panel). These modules ignore handled events per default and set events as handled if the cooperative mode is set. This means that they can cooperate with all other extensions too. However, their behavior cannot be parameterized in the same way.
Extension Grouping¶
To implement complex event consumption strategies you can use the SoView2DExtensionSeparator
module. It groups its child extensions and manages drawing order and event consumption for them.
Coordination with Other Open Inventor Nodes¶
There are other nodes that handle events, such as SoMouseGrabber
(this will be used exemplary for now). To coordinate event consumption between such nodes and SoView2DExtensions the order of nodes is very important. There are only two essential variants:
- If you want a
SoMouseGrabber
to handle the event before any extension, it has to be placed to the left of theSoView2D
. It is absolutely irrelevant where it is placed in relation to the extensions. If it is left to the SoView2D, it handles the event before the SoView2D and therefore before ALL extensions that belong to that SoView2D due to the way how extensions are treated during traversal (see General Usage and Scene Graph Traversal). There is no way to place a SoMouseGrabber such that it handles an event between two extensions! If the mouse grabber consumes the event (fields setEventhandled and setWheelEventhandled), the SoView2D will not receive this event, and therefore no extension can handle it. - If you want SoView2DExtensions to handle events before the SoMouseGrabber, then the SoMouseGrabber has to be placed right to the SoView2D. The extensions might consume an event as described before. If you want the SoMouseGrabber to handle the event, even if it has been consumed by the extensions, you have to set the option Pass handled-flag to Inventor of the SoView2D to
false
. If you set it totrue
, the event will not be forwarded to any node after the SoView2D!
The same holds for other Open Inventor nodes besides the event consumption of SoMouseGrabber. There are no fields in other nodes yet that are equivalent to setEventHandled and setWheelEventHandled.