Skip to main content

MultimodalScene

Namespace: DISP3DLIB  ·  Library: 3D Display Library

#include <disp3D/multimodalscene.h>

class DISP3DLIB::MultimodalScene

Host-app-agnostic controller that owns the ordered renderable set and dispatches picks back to the producing layer.

Responsibilities:

  • Maintain an ordered registry of SceneLayer payloads keyed by id.
  • Emit layersChanged whenever a layer is added, removed, or its visibility/opacity flips, so the renderer can rebuild its draw list.
  • Maintain a shared timeline (current time index) that data overlays across modalities consume; emits timeSampleChanged.
  • Maintain the most recent PickResult and emit picked when a layer producer reports a hit; consumers (Pick dock, status bar, MRI ortho viewer) subscribe to that signal.

The class is non-virtual on purpose: it is a pure data/dispatch hub with no rendering logic. The renderer (BrainRenderer or a future MultimodalRenderer) reads layers via layers() and per-kind downcasts the payload pointer.

src/examples/ex_disp3d_scene/main.cpp
MultimodalScene scene;
scene.registerBoundsFn(SceneLayerKind::Electrode, [](const SceneLayer& layer, QVector3D& bbMin, QVector3D& bbMax) {
const auto* object = static_cast<const ElectrodeObject*>(layer.payload.get());
const Eigen::MatrixX3f positions = object->implantation().positions();
const Eigen::Vector3f lo = positions.colwise().minCoeff().transpose();
const Eigen::Vector3f hi = positions.colwise().maxCoeff().transpose();
bbMin = QVector3D(lo.x(), lo.y(), lo.z());
bbMax = QVector3D(hi.x(), hi.y(), hi.z());
return true;
});
SceneLayer layer;
layer.id = "seeg_LH";
layer.kind = SceneLayerKind::Electrode;
auto payload = std::make_shared<ElectrodeObject>();
payload->setImplantation(electrodes.implantation());
layer.payload = payload;
scene.addLayer(layer);
scene.setOverlayThresholds(2.0f, 4.0f, 8.0f);
QVector3D bbMin;
QVector3D bbMax;
scene.worldBounds(bbMin, bbMax); // union over visible layers with a bounds function

Inheritance​


Public Methods​

MultimodalScene(parent)​


~MultimodalScene()​


addLayer(layer)​

Add or replace a layer.

If a layer with the same SceneLayer::id already exists, the stored layer is overwritten in place (preserving its slot in the draw order). Otherwise the new layer is appended to its kind's group.

Parameters:

  • layer : SceneLayer Layer record. The caller retains ownership of the underlying payload via the shared_ptr.

removeLayer(id)​

Remove a layer by id.

Parameters:

  • id : const QString & Layer id supplied to addLayer.

Returns:

  • bool — true if a layer was removed, false if the id was unknown.

clear()​

Remove every layer.


layers()​

Returns:

  • QVector< SceneLayer > — All layers in current draw order (sorted by kind, then by drawOrder, then by insertion order).

findLayer(id)​

Parameters:

  • id : const QString & Layer id.

Returns:

  • *const SceneLayer ** — Pointer to the layer with the given id, or nullptr. The pointer is valid only until the next mutation.

setLayerVisible(id, visible)​

Toggle visibility of a layer.

No-op if the id is unknown.

Parameters:

  • id : const QString & Layer id.

  • visible : bool True to show the layer, false to hide it.


setLayerOpacity(id, opacity)​

Set per-layer opacity in [0, 1].

No-op if the id is unknown.

Parameters:

  • id : const QString & Layer id.

  • opacity : float Opacity, clamped to [0, 1].


currentTimeSample()​

Returns:

  • int — Current shared time index (used by data overlays). -1 if no time-resolved data is loaded.

setCurrentTimeSample(sample)​

Set the current time index.

Emits timeSampleChanged if it actually changes. Negative values are clamped to -1.

Parameters:

  • sample : int New time sample index, or -1 for no time-resolved data.

timeCursor()​

Returns:

  • double — Current shared time cursor in seconds. Independent of the integer-sample timeline (currentTimeSample) — overlay widgets that drive a continuous time slider operate in seconds. Default 0.

setTimeCursor(seconds)​

Set the shared time cursor in seconds.

Emits timeCursorChanged if the value actually changes.

Parameters:

  • seconds : double New time cursor position in seconds.

overlayFmin()​

Returns:

  • float — Current overlay min threshold. Default 0.

overlayFmid()​

Returns:

  • float — Current overlay mid threshold. Default 0.5.

overlayFmax()​

Returns:

  • float — Current overlay max threshold. Default 1.

setOverlayThresholds(fmin, fmid, fmax)​

Set the shared (fmin, fmid, fmax) overlay thresholds used by the data-driven Overlay dock and the renderables it drives.

The values are clamped to fmin <= fmid <= fmax. Emits overlayThresholdsChanged if any value actually changes.

Parameters:

  • fmin : float Minimum threshold.

  • fmid : float Mid threshold, raised to fmin if smaller.

  • fmax : float Maximum threshold, raised to fmid if smaller.


lastPick()​

Returns:

  • const PickResult & — Most recent pick reported via reportPick. Default- constructed (kind == None) until the first hit.

reportPick(pick)​

Report a pick result from a layer's renderer or hit-tester.

Emits picked. Used by both real ray-cast picking and synthetic picks (e.g. wizard "show this contact" navigation).

Parameters:

  • pick : const PickResult & Pick result to store as the last pick and broadcast.

worldBounds(bbMin, bbMax)​

Scene-wide axis-aligned bounding box union of all visible layers, computed by the supplied per-kind extractor.

The scene itself does not know how to read each payload type; the host registers extractors via registerBoundsFn.

Parameters:

  • bbMin : QVector3D & Minimum corner of the union box; (-1, -1, -1) if no layer contributed.

  • bbMax : QVector3D & Maximum corner of the union box; (1, 1, 1) if no layer contributed.


registerBoundsFn(kind, fn)​

Register an AABB extractor for a given layer kind.

Replaces any previously registered fn for that kind.

Parameters:

  • kind : SceneLayerKind Layer kind the extractor handles.

  • fn : BoundsFn Extractor returning false when the layer has no bounds.


Example​

Used in examples​

ex_disp3d_scene​

Disp3D scene data: sensor-to-surface interpolation, electrodes, MRI slices, video overlay and layers.

src/examples/ex_disp3d_scene/main.cpp, line 176
MultimodalScene scene;
scene.registerBoundsFn(SceneLayerKind::Electrode, [](const SceneLayer& layer, QVector3D& bbMin, QVector3D& bbMax) {
const auto* object = static_cast<const ElectrodeObject*>(layer.payload.get());
const Eigen::MatrixX3f positions = object->implantation().positions();
const Eigen::Vector3f lo = positions.colwise().minCoeff().transpose();
const Eigen::Vector3f hi = positions.colwise().maxCoeff().transpose();
bbMin = QVector3D(lo.x(), lo.y(), lo.z());
bbMax = QVector3D(hi.x(), hi.y(), hi.z());
return true;
});
SceneLayer layer;
layer.id = "seeg_LH";
layer.kind = SceneLayerKind::Electrode;
auto payload = std::make_shared<ElectrodeObject>();

Authors of this file​