v2.0.0
Loading...
Searching...
No Matches
mne_msh_display_surface_set.cpp
Go to the documentation of this file.
1//=============================================================================================================
16
17//=============================================================================================================
18// INCLUDES
19//=============================================================================================================
20
22
24#include "mne_surface.h"
25#include "mne_surface_patch.h"
26#include "mne_source_space.h"
27#include "mne_msh_light_set.h"
28#include "mne_msh_light.h"
29#include "mne_msh_eyes.h"
30
31//=============================================================================================================
32// EIGEN INCLUDES
33//=============================================================================================================
34
35#include <Eigen/Core>
36
37//=============================================================================================================
38// QT INCLUDES
39//=============================================================================================================
40
41#include <qmath.h>
42#include <QDebug>
43
44//=============================================================================================================
45// CONSTANTS
46//=============================================================================================================
47
48namespace
49{
50
51constexpr int SURF_LEFT_HEMI = FIFFV_MNE_SURF_LEFT_HEMI;
52constexpr int SURF_RIGHT_HEMI = FIFFV_MNE_SURF_RIGHT_HEMI;
53constexpr int SURF_LEFT_MORPH_HEMI = (1 << 16 | FIFFV_MNE_SURF_LEFT_HEMI);
54constexpr int SURF_RIGHT_MORPH_HEMI = (1 << 16 | FIFFV_MNE_SURF_RIGHT_HEMI);
55
56constexpr int SHOW_CURVATURE_NONE = 0;
57constexpr int SHOW_OVERLAY_HEAT = 1;
58
59// Curvature overlay mode and colours (kept for documentation).
60[[maybe_unused]] constexpr int SHOW_CURVATURE_OVERLAY = 1;
61[[maybe_unused]] constexpr float POS_CURV_COLOR = 0.25f;
62[[maybe_unused]] constexpr float NEG_CURV_COLOR = 0.375f;
63[[maybe_unused]] constexpr float EVEN_CURV_COLOR = 0.375f;
64
65} // anonymous namespace
66
67//=============================================================================================================
68// STATIC DATA
69//=============================================================================================================
70
71static MNELIB::MNEMshEyes default_eyes;
72static MNELIB::MNEMshEyes* all_eyes = nullptr;
73static int neyes = 0;
74static int current_eyes = -1;
75
76static std::unique_ptr<MNELIB::MNEMshLightSet> custom_lights;
77
78//=============================================================================================================
79// USED NAMESPACES
80//=============================================================================================================
81
82using namespace MNELIB;
83
84//=============================================================================================================
85// DEFINE MEMBER METHODS
86//=============================================================================================================
87
89{
90 Eigen::Map<Eigen::Vector3f>(default_eyes.left) = Eigen::Vector3f(-0.2f, 0.0f, 0.0f);
91 Eigen::Map<Eigen::Vector3f>(default_eyes.right) = Eigen::Vector3f(0.2f, 0.0f, 0.0f);
92 Eigen::Map<Eigen::Vector3f>(default_eyes.left_up) = Eigen::Vector3f(0.0f, 0.0f, 1.0f);
93 Eigen::Map<Eigen::Vector3f>(default_eyes.right_up) = Eigen::Vector3f(0.0f, 0.0f, 1.0f);
94
95 this->nsurf = nsurf;
96 if (nsurf > 0) {
97 surfs.resize(nsurf);
98 patches.resize(nsurf);
99 patch_rot.resize(nsurf, 0.0f);
100 active = Eigen::VectorXi::Zero(nsurf);
101 drawable = Eigen::VectorXi::Ones(nsurf);
102 }
103
104 use_patches = false;
105
106 Eigen::Vector3f::Map(rot) = Eigen::Vector3f::Zero();
107 Eigen::Vector3f::Map(move) = Eigen::Vector3f::Zero();
108 Eigen::Vector3f::Map(eye) = Eigen::Vector3f(1.0f, 0.0f, 0.0f);
109 Eigen::Vector3f::Map(up) = Eigen::Vector3f(0.0f, 0.0f, 1.0f);
110
111 Eigen::Vector3f::Map(bg_color) = Eigen::Vector3f::Zero();
112 Eigen::Vector3f::Map(text_color) = Eigen::Vector3f::Ones();
113}
114
115//=============================================================================================================
116
118
119//=============================================================================================================
120
121std::unique_ptr<MNEMshDisplaySurfaceSet> MNEMshDisplaySurfaceSet::load(const QString& subject_id, const QString& surf, const QString& subjects_dir)
122/*
123 * Load new display surface data
124 */
125{
126 QString pathLh = QString("%1/%2/surf/%3.%4").arg(subjects_dir).arg(subject_id).arg("lh").arg(surf);
127 QString pathLhCurv = QString("%1/%2/surf/%3.%4").arg(subjects_dir).arg(subject_id).arg("lh").arg("curv");
128 QString pathRh = QString("%1/%2/surf/%3.%4").arg(subjects_dir).arg(subject_id).arg("rh").arg(surf);
129 QString pathRhCurv = QString("%1/%2/surf/%3.%4").arg(subjects_dir).arg(subject_id).arg("rh").arg("curv");
130
131 qInfo("Loading surface %s ...\n", pathLh.toUtf8().constData());
132 auto left = MNESourceSpace::load_surface(pathLh, pathLhCurv);
133 if (!left) {
134 left = MNESourceSpace::load_surface(pathLh, QString());
135 if (!left)
136 return nullptr;
137 left->add_uniform_curv();
138 }
139
140 qInfo("Loading surface %s ...\n", pathRh.toUtf8().constData());
141 auto right = MNESourceSpace::load_surface(pathRh, pathRhCurv);
142 if (!right) {
143 right = MNESourceSpace::load_surface(pathRh, QString());
144 if (!right)
145 return nullptr;
146 right->add_uniform_curv();
147 }
148
149 auto result = std::make_unique<MNEMshDisplaySurfaceSet>(2);
150
151 result->surfs[0] = std::make_unique<MNEMshDisplaySurface>();
152 result->surfs[1] = std::make_unique<MNEMshDisplaySurface>();
153
154 result->active[0] = true;
155 result->active[1] = false;
156 result->drawable[0] = true;
157 result->drawable[1] = true;
158
159 auto* pThis = result->surfs[0].get();
160 pThis->filename = pathLh;
161 static_cast<MNESurfaceOrVolume&>(*pThis) = std::move(static_cast<MNESurfaceOrVolume&>(*left));
162 pThis->id = SURF_LEFT_HEMI;
163 pThis->subj = subject_id;
164 pThis->surf_name = surf;
165
166 pThis->decide_surface_extent("Left hemisphere");
167 pThis->decide_curv_display(surf);
168 pThis->setup_curvature_colors();
169
170 pThis = result->surfs[1].get();
171 pThis->filename = pathRh;
172 static_cast<MNESurfaceOrVolume&>(*pThis) = std::move(static_cast<MNESurfaceOrVolume&>(*right));
173 pThis->id = SURF_RIGHT_HEMI;
174 pThis->subj = subject_id;
175 pThis->surf_name = surf;
176
177 pThis->decide_surface_extent("Right hemisphere");
178 pThis->decide_curv_display(surf);
179 pThis->setup_curvature_colors();
180
181 result->apply_left_right_eyes();
182 result->setup_current_lights();
183
184 return result;
185}
186
187//=============================================================================================================
188
190 int kind,
191 const QString& bemname,
192 int full_geom,
193 int check)
194{
195 qInfo("Loading BEM surface %s (id = %d) from %s ...\n",
196 bemname.toUtf8().constData(), kind, filepath.toUtf8().constData());
197
198 std::unique_ptr<MNESurface> surf(MNESurface::read_bem_surface2(filepath, kind, full_geom));
199 if (!surf)
200 return -1;
201
202 if (check) {
203 surf->compute_surface_cm();
204 double sum = surf->sum_solids(Eigen::Map<const Eigen::Vector3f>(surf->cm)) / (4 * M_PI);
205 if (std::fabs(sum - 1.0) > 1e-4) {
206 qCritical("%s surface is not closed "
207 "(sum of solid angles = %g * 4*PI).",
208 bemname.toUtf8().constData(), sum);
209 return -1;
210 }
211 }
212
213 auto newSurf = std::make_unique<MNEMshDisplaySurface>();
214 newSurf->filename = filepath;
215 //newSurf->time_loaded = time(nullptr); //Comment out due to unknown timestamp function ToDo
216 static_cast<MNESurfaceOrVolume&>(*newSurf) = std::move(static_cast<MNESurfaceOrVolume&>(*surf));
217 newSurf->id = kind;
218 newSurf->surf_name = bemname;
219
220 newSurf->curvature_color_mode = SHOW_CURVATURE_NONE;
221 newSurf->overlay_color_mode = SHOW_OVERLAY_HEAT;
222
223 newSurf->decide_surface_extent(bemname);
224 add_replace_surface(std::move(newSurf), true, true);
227
228 return 0;
229}
230
231//=============================================================================================================
232
233void MNEMshDisplaySurfaceSet::add_replace_surface(std::unique_ptr<MNEMshDisplaySurface> newSurf,
234 bool replace,
235 bool isDrawable)
236{
237 if (replace) {
238 for (int k = 0; k < nsurf; k++) {
239 auto& surf = surfs[k];
240 if (surf->id == newSurf->id) {
241 newSurf->transparent = surf->transparent;
242 newSurf->show_aux_data = surf->show_aux_data;
243 surfs[k] = std::move(newSurf);
244 if (!isDrawable) {
245 active[k] = false;
246 this->drawable[k] = false;
247 }
248 return;
249 }
250 }
251 }
252 if (newSurf) { /* New surface */
253 surfs.push_back(std::move(newSurf));
254 patches.push_back(nullptr);
255 patch_rot.push_back(0.0f);
256 active.conservativeResize(nsurf + 1);
257 this->drawable.conservativeResize(nsurf + 1);
258 active[nsurf] = isDrawable;
259 this->drawable[nsurf] = isDrawable;
260 nsurf++;
261 }
262}
263
264//=============================================================================================================
265
267{
268 MNEMshEyes* eyes = nullptr;
269
270 if (neyes == 0 || current_eyes < 0 || current_eyes > neyes - 1) {
271 eyes = &default_eyes;
272 } else {
273 eyes = all_eyes + current_eyes;
274 }
275
276 for (int k = 0; k < nsurf; k++) {
277 auto* surf = surfs[k].get();
278 switch (surf->id) {
279 case SURF_LEFT_HEMI:
280 case SURF_LEFT_MORPH_HEMI:
281 surf->eye = Eigen::Vector3f::Map(eyes->left);
282 surf->up = Eigen::Vector3f::Map(eyes->left_up);
283 break;
284 case SURF_RIGHT_HEMI:
285 case SURF_RIGHT_MORPH_HEMI:
286 surf->eye = Eigen::Vector3f::Map(eyes->right);
287 surf->up = Eigen::Vector3f::Map(eyes->right_up);
288 break;
289 default:
290 surf->eye = Eigen::Vector3f::Map(eyes->left);
291 surf->up = Eigen::Vector3f::Map(eyes->left_up);
292 break;
293 }
294 }
295}
296
297//=============================================================================================================
298
300{
301 for (int k = 0; k < nsurf; k++) {
302 if (neyes == 0 || current_eyes < 0 || current_eyes > neyes - 1) {
303 surfs[k]->eye = Eigen::Vector3f::Map(default_eyes.left);
304 surfs[k]->up = Eigen::Vector3f::Map(default_eyes.left_up);
305 } else {
306 surfs[k]->eye = Eigen::Vector3f::Map(all_eyes[current_eyes].left);
307 surfs[k]->up = Eigen::Vector3f::Map(all_eyes[current_eyes].left_up);
308 }
309 }
310}
311
312//=============================================================================================================
313
319
320//=============================================================================================================
321
323{
324 if (!custom_lights) {
325 custom_lights = std::make_unique<MNEMshLightSet>();
326
327 custom_lights->lights.push_back(std::make_unique<MNEMshLight>(true, 0.0f, 0.0f, 1.0f, 0.8f, 0.8f, 0.8f));
328 custom_lights->lights.push_back(std::make_unique<MNEMshLight>(true, 0.0f, 0.0f, -1.0f, 0.8f, 0.8f, 0.8f));
329 custom_lights->lights.push_back(std::make_unique<MNEMshLight>(true, 0.6f, -1.0f, -1.0f, 0.6f, 0.6f, 0.6f));
330 custom_lights->lights.push_back(std::make_unique<MNEMshLight>(true, -0.6f, -1.0f, -1.0f, 0.6f, 0.6f, 0.6f));
331 custom_lights->lights.push_back(std::make_unique<MNEMshLight>(true, 1.0f, 0.0f, 0.0f, 0.8f, 0.8f, 0.8f));
332 custom_lights->lights.push_back(std::make_unique<MNEMshLight>(true, -1.0f, 0.0f, 0.0f, 0.8f, 0.8f, 0.8f));
333 custom_lights->lights.push_back(std::make_unique<MNEMshLight>(true, 0.0f, 1.0f, 0.5f, 0.6f, 0.6f, 0.6f));
334 custom_lights->lights.push_back(std::make_unique<MNEMshLight>(false, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, 1.0f));
335 }
336}
337
338//=============================================================================================================
339
340std::unique_ptr<MNEMshLightSet> MNEMshDisplaySurfaceSet::dup_light_set(const MNEMshLightSet& s)
341{
342 auto res = std::make_unique<MNEMshLightSet>();
343
344 for (const auto& light : s.lights)
345 res->lights.push_back(std::make_unique<MNEMshLight>(*light));
346
347 return res;
348}
349
350//=============================================================================================================
351
#define FIFFV_MNE_SURF_RIGHT_HEMI
#define FIFFV_MNE_SURF_LEFT_HEMI
#define M_PI
constexpr float NEG_CURV_COLOR
constexpr int SHOW_CURVATURE_OVERLAY
constexpr float POS_CURV_COLOR
constexpr int SHOW_CURVATURE_NONE
constexpr int SHOW_OVERLAY_HEAT
constexpr float EVEN_CURV_COLOR
Set of MNELIB::MNEMshDisplaySurface objects sharing a camera, lights and selection.
One renderable surface (cortex / pial / inflated / BEM) inside an MSH display set.
Mesh-viewer camera state (position, focal point, up vector, field of view).
Local surface patch (neighbours-of-neighbours) used by patch-based source priors.
Lightweight triangulated surface (vertices, triangles, normals) used by surface-based routines.
Single-hemisphere source space (cortical surface or volume grid) loaded from FIFF.
Collection of MNELIB::MNEMshLight sources making up the viewer lighting rig.
Single directional / positional light source for the mesh viewer.
Core MNE data structures (source spaces, source estimates, hemispheres).
void setup_lights(const MNEMshLightSet &set)
static std::unique_ptr< MNEMshDisplaySurfaceSet > load(const QString &subject_id, const QString &surf, const QString &subjects_dir)
std::unique_ptr< MNEMshLightSet > lights
static std::unique_ptr< MNEMshLightSet > dup_light_set(const MNEMshLightSet &s)
void add_replace_surface(std::unique_ptr< MNEMshDisplaySurface > newSurf, bool replace, bool isDrawable)
std::vector< std::unique_ptr< MNEMshDisplaySurface > > surfs
std::vector< std::unique_ptr< MNESurfacePatch > > patches
int add_bem_surface(const QString &filepath, int kind, const QString &bemname, int full_geom, int check)
Eye/camera position and gaze direction for 3-D surface rendering.
Collection of lights defining the lighting setup for 3-D rendering.
std::vector< std::unique_ptr< MNEMshLight > > lights
static std::unique_ptr< MNESourceSpace > load_surface(const QString &surf_file, const QString &curv_file)
static std::unique_ptr< MNESurface > read_bem_surface2(const QString &name, int which, bool add_geometry)
Defines a source space or a surface.