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.startsWith("bem_")) return false;
172 if (key.startsWith("sens_")) return false;
173 if (key.startsWith("srcsp_")) return false;
174 if (key.startsWith("dig_")) return false;
175 return true;
176}
177
178//=============================================================================================================
179
180bool SubView::matchesSurfaceType(const QString &key) const
181{
182 return isBrainSurfaceKey(key) && key.endsWith(surfaceType);
183}
184
185//=============================================================================================================
186
187bool SubView::shouldRenderSurface(const QString &key) const
188{
189 if (key.startsWith("lh_")) return visibility.lh;
190 if (key.startsWith("rh_")) return visibility.rh;
191
192 if (key == "bem_head") return visibility.bemHead;
193 if (key == "bem_outer_skull") return visibility.bemOuterSkull;
194 if (key == "bem_inner_skull") return visibility.bemInnerSkull;
195
196 if (key.startsWith("sens_contour_meg")) return visibility.megFieldMap && visibility.megFieldContours;
197 if (key.startsWith("sens_contour_eeg")) return visibility.eegFieldMap && visibility.eegFieldContours;
198 if (key.startsWith("sens_surface_meg")) return visibility.sensMegHelmet;
199 if (key.startsWith("sens_meg_grad_")) return visibility.sensMeg && visibility.sensMegGrad;
200 if (key.startsWith("sens_meg_mag_")) return visibility.sensMeg && visibility.sensMegMag;
201 if (key.startsWith("sens_meg_")) return visibility.sensMeg;
202 if (key.startsWith("sens_eeg_")) return visibility.sensEeg;
203
204 if (key.startsWith("dig_cardinal")) return visibility.dig && visibility.digCardinal;
205 if (key.startsWith("dig_hpi")) return visibility.dig && visibility.digHpi;
206 if (key.startsWith("dig_eeg")) return visibility.dig && visibility.digEeg;
207 if (key.startsWith("dig_extra")) return visibility.dig && visibility.digExtra;
208 if (key.startsWith("dig_")) return visibility.dig;
209
210 if (key.startsWith("srcsp_")) return visibility.sourceSpace;
211
212 return true;
213}
214
215//=============================================================================================================
216
218 QMap<QString, std::shared_ptr<BrainSurface>> &surfaces) const
219{
220 for (auto it = surfaces.begin(); it != surfaces.end(); ++it) {
221 if (matchesSurfaceType(it.key())) {
222 it.value()->setVisualizationMode(overlayMode);
223 }
224 }
225}
226
227//=============================================================================================================
228// Camera presets
229//=============================================================================================================
230
232{
233 return QQuaternion::fromEulerAngles(-45.0f, -40.0f, -130.0f);
234}
235
236//=============================================================================================================
237
238QString multiViewPresetName(int preset)
239{
240 switch (preset) {
241 case 0: return QStringLiteral("Top");
242 case 1: return QStringLiteral("Perspective");
243 case 2: return QStringLiteral("Front");
244 case 3: return QStringLiteral("Left");
245 case 4: return QStringLiteral("Bottom");
246 case 5: return QStringLiteral("Back");
247 case 6: return QStringLiteral("Right");
248 default: return QStringLiteral("Top");
249 }
250}
251
252//=============================================================================================================
253
254QQuaternion multiViewPresetOffset(int preset)
255{
256 switch (preset) {
257 case 0:
258 return QQuaternion::fromAxisAndAngle(0, 0, 1, 180);
259 case 1:
261 case 2:
262 return QQuaternion::fromAxisAndAngle(0, 1, 0, 180)
263 * QQuaternion::fromAxisAndAngle(0, 0, 1, 180)
264 * QQuaternion::fromAxisAndAngle(1, 0, 0, 90)
265 * QQuaternion::fromAxisAndAngle(0, 0, 1, 180);
266 case 3:
267 return QQuaternion::fromAxisAndAngle(1, 0, 0, 90)
268 * QQuaternion::fromAxisAndAngle(0, 1, 0, -90);
269 case 4:
270 return QQuaternion::fromAxisAndAngle(1, 0, 0, 180)
271 * QQuaternion::fromAxisAndAngle(0, 0, 1, 180);
272 case 5:
273 return QQuaternion::fromAxisAndAngle(1, 0, 0, 90);
274 case 6:
275 return QQuaternion::fromAxisAndAngle(1, 0, 0, 90)
276 * QQuaternion::fromAxisAndAngle(0, 1, 0, 90);
277 default:
278 return QQuaternion::fromAxisAndAngle(0, 0, 1, 180);
279 }
280}
281
282//=============================================================================================================
283
285{
286 return preset == 1;
287}
288
289//=============================================================================================================
290// SubView factory
291//=============================================================================================================
292
294{
295 static constexpr ShaderMode kShaderCycle[] = {
297 Standard,
299 };
300 static constexpr int kNumShaders = 3;
301 static constexpr int kNumPresets = 7; // Top..Right
302
303 SubView sv;
304 sv.preset = index % kNumPresets;
305 sv.brainShader = kShaderCycle[index % kNumShaders];
306 sv.enabled = true;
307 return sv;
308}
309
310//=============================================================================================================
311// Enum ↔ string conversion
312//=============================================================================================================
313
314int normalizedVisualizationTarget(int target, int maxIndex)
315{
316 return std::clamp(target, -1, maxIndex);
317}
318
319//=============================================================================================================
320
321ShaderMode shaderModeFromName(const QString &name)
322{
323 if (name == "Holographic") return Holographic;
324 if (name == "Anatomical") return Anatomical;
325 return Standard;
326}
327
328//=============================================================================================================
329
331{
332 if (mode == Holographic) return QStringLiteral("Holographic");
333 if (mode == Anatomical) return QStringLiteral("Anatomical");
334 return QStringLiteral("Standard");
335}
336
337//=============================================================================================================
338
340{
341 if (name == "Annotation") return ModeAnnotation;
342 if (name == "Scientific") return ModeScientific;
343 if (name == "Source Estimate") return ModeSourceEstimate;
344 return ModeSurface;
345}
346
347//=============================================================================================================
348
350{
351 if (mode == ModeAnnotation) return QStringLiteral("Annotation");
352 if (mode == ModeScientific) return QStringLiteral("Scientific");
353 if (mode == ModeSourceEstimate) return QStringLiteral("Source Estimate");
354 return QStringLiteral("Surface");
355}
356
357//=============================================================================================================
358// Colormap
359//=============================================================================================================
360
361QRgb mneAnalyzeColor(double v)
362{
363 double x = 2.0 * v - 1.0;
364 x = std::clamp(x, -1.0, 1.0);
365
366 static constexpr int N = 7;
367 static const double pos[N] = { -1.0, -0.90, -0.30, 0.0, 0.30, 0.90, 1.0 };
368 static const double rr[N] = { 0.0, 0.0, 0.5, 0.5, 0.5, 1.0, 1.0 };
369 static const double gg[N] = { 1.0, 0.0, 0.5, 0.5, 0.5, 0.0, 1.0 };
370 static const double bb[N] = { 1.0, 1.0, 0.5, 0.5, 0.5, 0.0, 0.0 };
371
372 int seg = 0;
373 for (int i = 0; i < N - 1; ++i) {
374 if (x >= pos[i] && x <= pos[i + 1]) {
375 seg = i;
376 break;
377 }
378 }
379 if (x > pos[N - 1]) seg = N - 2;
380
381 double t = (pos[seg + 1] != pos[seg])
382 ? (x - pos[seg]) / (pos[seg + 1] - pos[seg])
383 : 0.0;
384 t = std::clamp(t, 0.0, 1.0);
385
386 int r = static_cast<int>(std::round((rr[seg] + t * (rr[seg + 1] - rr[seg])) * 255.0));
387 int g = static_cast<int>(std::round((gg[seg] + t * (gg[seg + 1] - gg[seg])) * 255.0));
388 int b = static_cast<int>(std::round((bb[seg] + t * (bb[seg + 1] - bb[seg])) * 255.0));
389
390 return qRgb(std::clamp(r, 0, 255), std::clamp(g, 0, 255), std::clamp(b, 0, 255));
391}
392
393//=============================================================================================================
394// SubView serialisation
395//=============================================================================================================
396
397void SubView::load(const QSettings &settings, const QString &prefix,
398 const QQuaternion &fallbackRotation)
399{
400 surfaceType = settings.value(prefix + "surfaceType", surfaceType).toString();
401 brainShader = shaderModeFromName(settings.value(prefix + "shader", shaderModeName(brainShader)).toString());
402 bemShader = shaderModeFromName(settings.value(prefix + "bemShader", shaderModeName(bemShader)).toString());
403 overlayMode = visualizationModeFromName(settings.value(prefix + "overlay", visualizationModeName(overlayMode)).toString());
404
405 visibility.load(settings, prefix + "vis_");
406
407 zoom = settings.value(prefix + "zoom", zoom).toFloat();
408 pan = QVector2D(
409 settings.value(prefix + "panX", pan.x()).toFloat(),
410 settings.value(prefix + "panY", pan.y()).toFloat());
411 preset = std::clamp(settings.value(prefix + "preset", preset).toInt(), 0, 6);
412
413 const bool hasQuat = settings.contains(prefix + "perspRotW")
414 && settings.contains(prefix + "perspRotX")
415 && settings.contains(prefix + "perspRotY")
416 && settings.contains(prefix + "perspRotZ");
417 if (hasQuat) {
418 const float w = settings.value(prefix + "perspRotW", 1.0f).toFloat();
419 const float x = settings.value(prefix + "perspRotX", 0.0f).toFloat();
420 const float y = settings.value(prefix + "perspRotY", 0.0f).toFloat();
421 const float z = settings.value(prefix + "perspRotZ", 0.0f).toFloat();
422 perspectiveRotation = QQuaternion(w, x, y, z);
423 if (perspectiveRotation.lengthSquared() <= std::numeric_limits<float>::epsilon()) {
424 perspectiveRotation = QQuaternion();
425 } else {
426 perspectiveRotation.normalize();
427 }
428 } else {
429 perspectiveRotation = fallbackRotation;
430 }
431}
432
433//=============================================================================================================
434
435void SubView::save(QSettings &settings, const QString &prefix) const
436{
437 settings.setValue(prefix + "surfaceType", surfaceType);
438 settings.setValue(prefix + "shader", shaderModeName(brainShader));
439 settings.setValue(prefix + "bemShader", shaderModeName(bemShader));
440 settings.setValue(prefix + "overlay", visualizationModeName(overlayMode));
441
442 visibility.save(settings, prefix + "vis_");
443
444 settings.setValue(prefix + "zoom", zoom);
445 settings.setValue(prefix + "panX", pan.x());
446 settings.setValue(prefix + "panY", pan.y());
447 settings.setValue(prefix + "preset", preset);
448
449 settings.setValue(prefix + "perspRotW", perspectiveRotation.scalar());
450 settings.setValue(prefix + "perspRotX", perspectiveRotation.x());
451 settings.setValue(prefix + "perspRotY", perspectiveRotation.y());
452 settings.setValue(prefix + "perspRotZ", perspectiveRotation.z());
453}
BrainSurface class declaration.
BrainRenderer class declaration.
ViewState declarations — per-view data structures and conversion helpers.
QString shaderModeName(ShaderMode mode)
VisualizationMode visualizationModeFromName(const QString &name)
QString visualizationModeName(VisualizationMode mode)
bool isTrue(const QVariant &value, bool fallback)
Definition viewstate.h:294
ShaderMode shaderModeFromName(const QString &name)
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
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())