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