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