v2.0.0
Loading...
Searching...
No Matches
viewstate.cpp
Go to the documentation of this file.
1//=============================================================================================================
12
13//=============================================================================================================
14// INCLUDES
15//=============================================================================================================
16
17#include "viewstate.h"
18
20#include "view/brainrenderer.h"
21
22#include <QSettings>
23#include <cmath>
24#include <limits>
25
26//=============================================================================================================
27// ViewVisibilityProfile
28//=============================================================================================================
29
30bool ViewVisibilityProfile::isObjectVisible(const QString &object) const
31{
32 if (object == "lh") return lh;
33 if (object == "rh") return rh;
34 if (object == "bem_head") return bemHead;
35 if (object == "bem_outer_skull") return bemOuterSkull;
36 if (object == "bem_inner_skull") return bemInnerSkull;
37 if (object == "sens_meg") return sensMeg;
38 if (object == "sens_meg_grad") return sensMegGrad;
39 if (object == "sens_meg_mag") return sensMegMag;
40 if (object == "sens_meg_helmet") return sensMegHelmet;
41 if (object == "sens_eeg") return sensEeg;
42 if (object == "dig") return dig;
43 if (object == "dig_cardinal") return digCardinal;
44 if (object == "dig_hpi") return digHpi;
45 if (object == "dig_eeg") return digEeg;
46 if (object == "dig_extra") return digExtra;
47 if (object == "field_meg") return megFieldMap;
48 if (object == "field_eeg") return eegFieldMap;
49 if (object == "contour_meg") return megFieldContours;
50 if (object == "contour_eeg") return eegFieldContours;
51 if (object == "dipoles") return dipoles;
52 if (object == "source_space") return sourceSpace;
53 if (object == "network") return network;
54 if (object == "mri_slices") return mriSlices;
55 return true; // unknown objects default visible
56}
57
58//=============================================================================================================
59
60void ViewVisibilityProfile::setObjectVisible(const QString &object, bool visible)
61{
62 if (object == "lh") lh = visible;
63 else if (object == "rh") rh = visible;
64 else if (object == "bem_head") bemHead = visible;
65 else if (object == "bem_outer_skull") bemOuterSkull = visible;
66 else if (object == "bem_inner_skull") bemInnerSkull = visible;
67 else if (object == "sens_meg") sensMeg = visible;
68 else if (object == "sens_meg_grad") sensMegGrad = visible;
69 else if (object == "sens_meg_mag") sensMegMag = visible;
70 else if (object == "sens_meg_helmet") sensMegHelmet = visible;
71 else if (object == "sens_eeg") sensEeg = visible;
72 else if (object == "dig") dig = visible;
73 else if (object == "dig_cardinal") digCardinal = visible;
74 else if (object == "dig_hpi") digHpi = visible;
75 else if (object == "dig_eeg") digEeg = visible;
76 else if (object == "dig_extra") digExtra = visible;
77 else if (object == "field_meg") megFieldMap = visible;
78 else if (object == "field_eeg") eegFieldMap = visible;
79 else if (object == "contour_meg") megFieldContours = visible;
80 else if (object == "contour_eeg") eegFieldContours = visible;
81 else if (object == "dipoles") dipoles = visible;
82 else if (object == "source_space") sourceSpace = visible;
83 else if (object == "network") network = visible;
84 else if (object == "mri_slices") mriSlices = visible;
85}
86
87//=============================================================================================================
88
89void ViewVisibilityProfile::load(const QSettings &settings, const QString &prefix)
90{
91 lh = isTrue(settings.value(prefix + "lh"), lh);
92 rh = isTrue(settings.value(prefix + "rh"), rh);
93 bemHead = isTrue(settings.value(prefix + "bemHead"), bemHead);
94 bemOuterSkull = isTrue(settings.value(prefix + "bemOuterSkull"), bemOuterSkull);
95 bemInnerSkull = isTrue(settings.value(prefix + "bemInnerSkull"), bemInnerSkull);
96 sensMeg = isTrue(settings.value(prefix + "sensMeg"), sensMeg);
97 sensMegGrad = isTrue(settings.value(prefix + "sensMegGrad"), sensMegGrad);
98 sensMegMag = isTrue(settings.value(prefix + "sensMegMag"), sensMegMag);
99 sensMegHelmet = isTrue(settings.value(prefix + "sensMegHelmet"), sensMegHelmet);
100 sensEeg = isTrue(settings.value(prefix + "sensEeg"), sensEeg);
101 dig = isTrue(settings.value(prefix + "dig"), dig);
102 digCardinal = isTrue(settings.value(prefix + "digCardinal"), digCardinal);
103 digHpi = isTrue(settings.value(prefix + "digHpi"), digHpi);
104 digEeg = isTrue(settings.value(prefix + "digEeg"), digEeg);
105 digExtra = isTrue(settings.value(prefix + "digExtra"), digExtra);
106 megFieldMap = isTrue(settings.value(prefix + "megFieldMap"), megFieldMap);
107 eegFieldMap = isTrue(settings.value(prefix + "eegFieldMap"), eegFieldMap);
108 megFieldContours = isTrue(settings.value(prefix + "megFieldContours"), megFieldContours);
109 eegFieldContours = isTrue(settings.value(prefix + "eegFieldContours"), eegFieldContours);
110 dipoles = isTrue(settings.value(prefix + "dipoles"), dipoles);
111 sourceSpace = isTrue(settings.value(prefix + "sourceSpace"), sourceSpace);
112 network = isTrue(settings.value(prefix + "network"), network);
113 megFieldMapOnHead = isTrue(settings.value(prefix + "megFieldMapOnHead"), megFieldMapOnHead);
114 mriSlices = isTrue(settings.value(prefix + "mriSlices"), mriSlices);
115}
116
117//=============================================================================================================
118
119void ViewVisibilityProfile::save(QSettings &settings, const QString &prefix) const
120{
121 settings.setValue(prefix + "lh", lh);
122 settings.setValue(prefix + "rh", rh);
123 settings.setValue(prefix + "bemHead", bemHead);
124 settings.setValue(prefix + "bemOuterSkull", bemOuterSkull);
125 settings.setValue(prefix + "bemInnerSkull", bemInnerSkull);
126 settings.setValue(prefix + "sensMeg", sensMeg);
127 settings.setValue(prefix + "sensMegGrad", sensMegGrad);
128 settings.setValue(prefix + "sensMegMag", sensMegMag);
129 settings.setValue(prefix + "sensMegHelmet", sensMegHelmet);
130 settings.setValue(prefix + "sensEeg", sensEeg);
131 settings.setValue(prefix + "dig", dig);
132 settings.setValue(prefix + "digCardinal", digCardinal);
133 settings.setValue(prefix + "digHpi", digHpi);
134 settings.setValue(prefix + "digEeg", digEeg);
135 settings.setValue(prefix + "digExtra", digExtra);
136 settings.setValue(prefix + "megFieldMap", megFieldMap);
137 settings.setValue(prefix + "eegFieldMap", eegFieldMap);
138 settings.setValue(prefix + "megFieldContours", megFieldContours);
139 settings.setValue(prefix + "eegFieldContours", eegFieldContours);
140 settings.setValue(prefix + "dipoles", dipoles);
141 settings.setValue(prefix + "sourceSpace", sourceSpace);
142 settings.setValue(prefix + "network", network);
143 settings.setValue(prefix + "megFieldMapOnHead", megFieldMapOnHead);
144 settings.setValue(prefix + "mriSlices", mriSlices);
145}
146
147//=============================================================================================================
148// SubView
149//=============================================================================================================
150
151bool SubView::isBrainSurfaceKey(const QString &key)
152{
153 if (key.isEmpty()) return false;
154 if (key.startsWith("bem_")) return false;
155 if (key.startsWith("sens_")) return false;
156 if (key.startsWith("srcsp_")) return false;
157 if (key.startsWith("dig_")) return false;
158 return true;
159}
160
161//=============================================================================================================
162
163bool SubView::matchesSurfaceType(const QString &key) const
164{
165 return isBrainSurfaceKey(key) && key.endsWith(surfaceType);
166}
167
168//=============================================================================================================
169
170bool SubView::shouldRenderSurface(const QString &key) const
171{
172 if (key.startsWith("lh_")) return visibility.lh;
173 if (key.startsWith("rh_")) return visibility.rh;
174
175 if (key == "bem_head") return visibility.bemHead;
176 if (key == "bem_outer_skull") return visibility.bemOuterSkull;
177 if (key == "bem_inner_skull") return visibility.bemInnerSkull;
178
179 if (key.startsWith("sens_contour_meg")) return visibility.megFieldMap && visibility.megFieldContours;
180 if (key.startsWith("sens_contour_eeg")) return visibility.eegFieldMap && visibility.eegFieldContours;
181 if (key.startsWith("sens_surface_meg")) return visibility.sensMegHelmet;
182 if (key.startsWith("sens_meg_grad_")) return visibility.sensMeg && visibility.sensMegGrad;
183 if (key.startsWith("sens_meg_mag_")) return visibility.sensMeg && visibility.sensMegMag;
184 if (key.startsWith("sens_meg_")) return visibility.sensMeg;
185 if (key.startsWith("sens_eeg_")) return visibility.sensEeg;
186
187 if (key.startsWith("dig_live_")) return true; // always show live tracker
188 if (key.startsWith("dig_static_")) return true; // always show static markers
189 if (key.startsWith("dig_ray_")) return true; // always show optical ray
190 if (key.startsWith("dig_probe_")) return true; // always show catheter probe
191 if (key.startsWith("dig_cardinal")) return visibility.dig && visibility.digCardinal;
192 if (key.startsWith("dig_hpi")) return visibility.dig && visibility.digHpi;
193 if (key.startsWith("dig_eeg")) return visibility.dig && visibility.digEeg;
194 if (key.startsWith("dig_extra")) return visibility.dig && visibility.digExtra;
195 if (key.startsWith("dig_")) return visibility.dig;
196
197 if (key.startsWith("srcsp_")) return visibility.sourceSpace;
198
199 return true;
200}
201
202//=============================================================================================================
203
205 QMap<QString, std::shared_ptr<BrainSurface>> &surfaces) const
206{
207 for (auto it = surfaces.begin(); it != surfaces.end(); ++it) {
208 if (matchesSurfaceType(it.key())) {
209 it.value()->setVisualizationMode(overlayMode);
210 }
211 }
212}
213
214//=============================================================================================================
215// Camera presets
216//=============================================================================================================
217
219{
220 return QQuaternion::fromEulerAngles(-45.0f, -40.0f, -130.0f);
221}
222
223//=============================================================================================================
224
225QString multiViewPresetName(int preset)
226{
227 switch (preset) {
228 case 0: return QStringLiteral("Top");
229 case 1: return QStringLiteral("Perspective");
230 case 2: return QStringLiteral("Front");
231 case 3: return QStringLiteral("Left");
232 case 4: return QStringLiteral("Bottom");
233 case 5: return QStringLiteral("Back");
234 case 6: return QStringLiteral("Right");
235 default: return QStringLiteral("Top");
236 }
237}
238
239//=============================================================================================================
240
241QQuaternion multiViewPresetOffset(int preset)
242{
243 switch (preset) {
244 case 0:
245 return QQuaternion::fromAxisAndAngle(0, 0, 1, 180);
246 case 1:
248 case 2:
249 return QQuaternion::fromAxisAndAngle(0, 1, 0, 180)
250 * QQuaternion::fromAxisAndAngle(0, 0, 1, 180)
251 * QQuaternion::fromAxisAndAngle(1, 0, 0, 90)
252 * QQuaternion::fromAxisAndAngle(0, 0, 1, 180);
253 case 3:
254 return QQuaternion::fromAxisAndAngle(1, 0, 0, 90)
255 * QQuaternion::fromAxisAndAngle(0, 1, 0, -90);
256 case 4:
257 return QQuaternion::fromAxisAndAngle(1, 0, 0, 180)
258 * QQuaternion::fromAxisAndAngle(0, 0, 1, 180);
259 case 5:
260 return QQuaternion::fromAxisAndAngle(1, 0, 0, 90);
261 case 6:
262 return QQuaternion::fromAxisAndAngle(1, 0, 0, 90)
263 * QQuaternion::fromAxisAndAngle(0, 1, 0, 90);
264 default:
265 return QQuaternion::fromAxisAndAngle(0, 0, 1, 180);
266 }
267}
268
269//=============================================================================================================
270
272{
273 return preset == 1;
274}
275
276//=============================================================================================================
277// SubView factory
278//=============================================================================================================
279
281{
282 static constexpr ShaderMode kShaderCycle[] = {
284 Standard,
286 };
287 static constexpr int kNumShaders = 3;
288 static constexpr int kNumPresets = 7; // Top..Right
289
290 SubView sv;
291 sv.preset = index % kNumPresets;
292 sv.brainShader = kShaderCycle[index % kNumShaders];
293 sv.enabled = true;
294 return sv;
295}
296
297//=============================================================================================================
298// Enum ↔ string conversion
299//=============================================================================================================
300
301int normalizedVisualizationTarget(int target, int maxIndex)
302{
303 return std::clamp(target, -1, maxIndex);
304}
305
306//=============================================================================================================
307
308ShaderMode shaderModeFromName(const QString &name)
309{
310 if (name == "Holographic") return Holographic;
311 if (name == "Anatomical") return Anatomical;
312 if (name == "XRay") return XRay;
313 return Standard;
314}
315
316//=============================================================================================================
317
319{
320 if (mode == Holographic) return QStringLiteral("Holographic");
321 if (mode == Anatomical) return QStringLiteral("Anatomical");
322 return QStringLiteral("Standard");
323}
324
325//=============================================================================================================
326
328{
329 if (name == "Annotation") return ModeAnnotation;
330 if (name == "Scientific") return ModeScientific;
331 if (name == "Source Estimate") return ModeSourceEstimate;
332 return ModeSurface;
333}
334
335//=============================================================================================================
336
338{
339 if (mode == ModeAnnotation) return QStringLiteral("Annotation");
340 if (mode == ModeScientific) return QStringLiteral("Scientific");
341 if (mode == ModeSourceEstimate) return QStringLiteral("Source Estimate");
342 return QStringLiteral("Surface");
343}
344
345//=============================================================================================================
346// Colormap
347//=============================================================================================================
348
349QRgb mneAnalyzeColor(double v)
350{
351 double x = 2.0 * v - 1.0;
352 x = std::clamp(x, -1.0, 1.0);
353
354 static constexpr int N = 7;
355 static const double pos[N] = { -1.0, -0.90, -0.30, 0.0, 0.30, 0.90, 1.0 };
356 static const double rr[N] = { 0.0, 0.0, 0.5, 0.5, 0.5, 1.0, 1.0 };
357 static const double gg[N] = { 1.0, 0.0, 0.5, 0.5, 0.5, 0.0, 1.0 };
358 static const double bb[N] = { 1.0, 1.0, 0.5, 0.5, 0.5, 0.0, 0.0 };
359
360 int seg = 0;
361 for (int i = 0; i < N - 1; ++i) {
362 if (x >= pos[i] && x <= pos[i + 1]) {
363 seg = i;
364 break;
365 }
366 }
367 if (x > pos[N - 1]) seg = N - 2;
368
369 double t = (pos[seg + 1] != pos[seg])
370 ? (x - pos[seg]) / (pos[seg + 1] - pos[seg])
371 : 0.0;
372 t = std::clamp(t, 0.0, 1.0);
373
374 int r = static_cast<int>(std::round((rr[seg] + t * (rr[seg + 1] - rr[seg])) * 255.0));
375 int g = static_cast<int>(std::round((gg[seg] + t * (gg[seg + 1] - gg[seg])) * 255.0));
376 int b = static_cast<int>(std::round((bb[seg] + t * (bb[seg + 1] - bb[seg])) * 255.0));
377
378 return qRgb(std::clamp(r, 0, 255), std::clamp(g, 0, 255), std::clamp(b, 0, 255));
379}
380
381//=============================================================================================================
382// SubView serialisation
383//=============================================================================================================
384
385void SubView::load(const QSettings &settings, const QString &prefix,
386 const QQuaternion &fallbackRotation)
387{
388 surfaceType = settings.value(prefix + "surfaceType", surfaceType).toString();
389 brainShader = shaderModeFromName(settings.value(prefix + "shader", shaderModeName(brainShader)).toString());
390 bemShader = shaderModeFromName(settings.value(prefix + "bemShader", shaderModeName(bemShader)).toString());
391 overlayMode = visualizationModeFromName(settings.value(prefix + "overlay", visualizationModeName(overlayMode)).toString());
392
393 visibility.load(settings, prefix + "vis_");
394
395 zoom = settings.value(prefix + "zoom", zoom).toFloat();
396 pan = QVector2D(
397 settings.value(prefix + "panX", pan.x()).toFloat(),
398 settings.value(prefix + "panY", pan.y()).toFloat());
399 preset = std::clamp(settings.value(prefix + "preset", preset).toInt(), 0, 6);
400
401 const bool hasQuat = settings.contains(prefix + "perspRotW")
402 && settings.contains(prefix + "perspRotX")
403 && settings.contains(prefix + "perspRotY")
404 && settings.contains(prefix + "perspRotZ");
405 if (hasQuat) {
406 const float w = settings.value(prefix + "perspRotW", 1.0f).toFloat();
407 const float x = settings.value(prefix + "perspRotX", 0.0f).toFloat();
408 const float y = settings.value(prefix + "perspRotY", 0.0f).toFloat();
409 const float z = settings.value(prefix + "perspRotZ", 0.0f).toFloat();
410 perspectiveRotation = QQuaternion(w, x, y, z);
411 if (perspectiveRotation.lengthSquared() <= std::numeric_limits<float>::epsilon()) {
412 perspectiveRotation = QQuaternion();
413 } else {
414 perspectiveRotation.normalize();
415 }
416 } else {
417 perspectiveRotation = fallbackRotation;
418 }
419}
420
421//=============================================================================================================
422
423void SubView::save(QSettings &settings, const QString &prefix) const
424{
425 settings.setValue(prefix + "surfaceType", surfaceType);
426 settings.setValue(prefix + "shader", shaderModeName(brainShader));
427 settings.setValue(prefix + "bemShader", shaderModeName(bemShader));
428 settings.setValue(prefix + "overlay", visualizationModeName(overlayMode));
429
430 visibility.save(settings, prefix + "vis_");
431
432 settings.setValue(prefix + "zoom", zoom);
433 settings.setValue(prefix + "panX", pan.x());
434 settings.setValue(prefix + "panY", pan.y());
435 settings.setValue(prefix + "preset", preset);
436
437 settings.setValue(prefix + "perspRotW", perspectiveRotation.scalar());
438 settings.setValue(prefix + "perspRotX", perspectiveRotation.x());
439 settings.setValue(prefix + "perspRotY", perspectiveRotation.y());
440 settings.setValue(prefix + "perspRotZ", perspectiveRotation.z());
441}
Renderable cortical / BEM mesh with interleaved vertex attributes and Qt-RHI buffer management.
ShaderMode
Definition rendertypes.h:61
@ Standard
Definition rendertypes.h:62
@ Holographic
Definition rendertypes.h:63
@ Anatomical
Definition rendertypes.h:64
@ XRay
Definition rendertypes.h:66
VisualizationMode
Definition rendertypes.h:78
@ ModeScientific
Definition rendertypes.h:81
@ ModeAnnotation
Definition rendertypes.h:80
@ ModeSurface
Definition rendertypes.h:79
@ ModeSourceEstimate
Definition rendertypes.h:82
QQuaternion multiViewPresetOffset(int preset)
QString shaderModeName(ShaderMode mode)
VisualizationMode visualizationModeFromName(const QString &name)
QString visualizationModeName(VisualizationMode mode)
bool multiViewPresetIsPerspective(int preset)
QRgb mneAnalyzeColor(double v)
ShaderMode shaderModeFromName(const QString &name)
int normalizedVisualizationTarget(int target, int maxIndex)
QQuaternion perspectivePresetRotation()
QString multiViewPresetName(int preset)
Per-viewport state (camera preset, zoom, pan, visibility filter) and serialisation helpers.
DISP3DSHARED_EXPORT ShaderMode shaderModeFromName(const QString &name)
DISP3DSHARED_EXPORT QString visualizationModeName(VisualizationMode mode)
DISP3DSHARED_EXPORT VisualizationMode visualizationModeFromName(const QString &name)
bool isTrue(const QVariant &value, bool fallback)
Definition viewstate.h:291
DISP3DSHARED_EXPORT QString shaderModeName(ShaderMode mode)
Qt-RHI scene renderer: shader pipelines, lighting, dual render targets and per-frame draw orchestrati...
void save(QSettings &settings, const QString &prefix) const
void load(const QSettings &settings, const QString &prefix)
Definition viewstate.cpp:89
void setObjectVisible(const QString &object, bool visible)
Definition viewstate.cpp:60
bool isObjectVisible(const QString &object) const
Definition viewstate.cpp:30
Viewport subdivision holding its own camera, projection, and scissor rectangle.
Definition viewstate.h:139
bool enabled
Definition viewstate.h:152
void save(QSettings &settings, const QString &prefix) const
void applyOverlayToSurfaces(QMap< QString, std::shared_ptr< BrainSurface > > &surfaces) const
bool matchesSurfaceType(const QString &key) const
ViewVisibilityProfile visibility
Definition viewstate.h:145
static bool isBrainSurfaceKey(const QString &key)
ShaderMode bemShader
Definition viewstate.h:143
QVector2D pan
Definition viewstate.h:149
bool shouldRenderSurface(const QString &key) const
QQuaternion perspectiveRotation
Definition viewstate.h:150
QString surfaceType
Definition viewstate.h:141
VisualizationMode overlayMode
Definition viewstate.h:144
static SubView defaultForIndex(int index)
ShaderMode brainShader
Definition viewstate.h:142
int preset
Definition viewstate.h:151
float zoom
Definition viewstate.h:148
void load(const QSettings &settings, const QString &prefix, const QQuaternion &fallbackRotation=QQuaternion())