v2.0.0
Loading...
Searching...
No Matches
mne_surface.cpp
Go to the documentation of this file.
1//=============================================================================================================
36
37//=============================================================================================================
38// INCLUDES
39//=============================================================================================================
40
41#include "mne_surface.h"
42#include "mne_source_space.h"
43#include "mne_triangle.h"
44#include "mne_proj_data.h"
45
46#include <fiff/fiff_stream.h>
48
49#include <QFile>
50
51#define _USE_MATH_DEFINES
52#include <math.h>
53
54#include <Eigen/Dense>
55
56//=============================================================================================================
57// USED NAMESPACES
58//=============================================================================================================
59
60using namespace Eigen;
61using namespace FIFFLIB;
62using namespace MNELIB;
63
64//=============================================================================================================
65
66#ifndef TRUE
67#define TRUE 1
68#endif
69
70#ifndef FALSE
71#define FALSE 0
72#endif
73
74#ifndef FAIL
75#define FAIL -1
76#endif
77
78#ifndef OK
79#define OK 0
80#endif
81
82#define X_17 0
83#define Y_17 1
84#define Z_17 2
85
86#define VEC_DOT_17(x,y) ((x)[X_17]*(y)[X_17] + (x)[Y_17]*(y)[Y_17] + (x)[Z_17]*(y)[Z_17])
87#define VEC_LEN_17(x) sqrt(VEC_DOT_17(x,x))
88#define VEC_DIFF_17(from,to,diff) {\
89 (diff)[X_17] = (to)[X_17] - (from)[X_17];\
90 (diff)[Y_17] = (to)[Y_17] - (from)[Y_17];\
91 (diff)[Z_17] = (to)[Z_17] - (from)[Z_17];\
92 }
93#define VEC_COPY_17(to,from) {\
94 (to)[X_17] = (from)[X_17];\
95 (to)[Y_17] = (from)[Y_17];\
96 (to)[Z_17] = (from)[Z_17];\
97 }
98
99//=============================================================================================================
100// DEFINE MEMBER METHODS
101//=============================================================================================================
102
106
107//=============================================================================================================
108
112
113//=============================================================================================================
114// Const geometry methods
115//=============================================================================================================
116
117double MNESurface::sum_solids(const Eigen::Vector3f& from) const
118{
119 int k;
120 double tot_angle, angle;
121 for (k = 0, tot_angle = 0.0; k < ntri; k++) {
122 angle = solid_angle(from, tris[k]);
123 tot_angle += angle;
124 }
125 return tot_angle;
126}
127
128//=============================================================================================================
129
130void MNESurface::triangle_coords(const Eigen::Vector3f& r, int tri, float &x, float &y, float &z) const
131{
132 double rr[3];
133 double a, b, c, v1, v2, det;
134 const MNETriangle* this_tri;
135
136 this_tri = &tris[tri];
137
138 VEC_DIFF_17(this_tri->r1, r, rr);
139 z = VEC_DOT_17(rr, this_tri->nn);
140
141 a = VEC_DOT_17(this_tri->r12, this_tri->r12);
142 b = VEC_DOT_17(this_tri->r13, this_tri->r13);
143 c = VEC_DOT_17(this_tri->r12, this_tri->r13);
144
145 v1 = VEC_DOT_17(rr, this_tri->r12);
146 v2 = VEC_DOT_17(rr, this_tri->r13);
147
148 det = a * b - c * c;
149
150 x = (b * v1 - c * v2) / det;
151 y = (a * v2 - c * v1) / det;
152}
153
154//=============================================================================================================
155
156int MNESurface::nearest_triangle_point(const Eigen::Vector3f& r, const MNEProjData *user, int tri, float &x, float &y, float &z) const
157{
158 double p, q, p0, q0, t0;
159 double rr[3];
160 double a, b, c, v1, v2, det;
161 double best, dist, dist0;
162 const MNEProjData* pd = user;
163 const MNETriangle* this_tri;
164
165 this_tri = &tris[tri];
166 VEC_DIFF_17(this_tri->r1, r, rr);
167 dist = VEC_DOT_17(rr, this_tri->nn);
168
169 if (pd) {
170 if (!pd->act[tri])
171 return FALSE;
172 a = pd->a[tri];
173 b = pd->b[tri];
174 c = pd->c[tri];
175 }
176 else {
177 a = VEC_DOT_17(this_tri->r12, this_tri->r12);
178 b = VEC_DOT_17(this_tri->r13, this_tri->r13);
179 c = VEC_DOT_17(this_tri->r12, this_tri->r13);
180 }
181
182 v1 = VEC_DOT_17(rr, this_tri->r12);
183 v2 = VEC_DOT_17(rr, this_tri->r13);
184
185 det = a * b - c * c;
186
187 p = (b * v1 - c * v2) / det;
188 q = (a * v2 - c * v1) / det;
189
190 if (p >= 0.0 && p <= 1.0 &&
191 q >= 0.0 && q <= 1.0 &&
192 q <= 1.0 - p) {
193 x = p;
194 y = q;
195 z = dist;
196 return TRUE;
197 }
198 /*
199 * Side 1 -> 2
200 */
201 p0 = p + 0.5 * (q * c) / a;
202 if (p0 < 0.0) p0 = 0.0;
203 else if (p0 > 1.0) p0 = 1.0;
204 q0 = 0.0;
205 dist0 = sqrt((p - p0) * (p - p0) * a +
206 (q - q0) * (q - q0) * b +
207 (p - p0) * (q - q0) * c +
208 dist * dist);
209 best = dist0;
210 x = p0;
211 y = q0;
212 z = dist0;
213 /*
214 * Side 2 -> 3
215 */
216 t0 = 0.5 * ((2.0 * a - c) * (1.0 - p) + (2.0 * b - c) * q) / (a + b - c);
217 if (t0 < 0.0) t0 = 0.0;
218 else if (t0 > 1.0) t0 = 1.0;
219 p0 = 1.0 - t0;
220 q0 = t0;
221 dist0 = sqrt((p - p0) * (p - p0) * a +
222 (q - q0) * (q - q0) * b +
223 (p - p0) * (q - q0) * c +
224 dist * dist);
225 if (dist0 < best) {
226 best = dist0;
227 x = p0;
228 y = q0;
229 z = dist0;
230 }
231 /*
232 * Side 1 -> 3
233 */
234 p0 = 0.0;
235 q0 = q + 0.5 * (p * c) / b;
236 if (q0 < 0.0) q0 = 0.0;
237 else if (q0 > 1.0) q0 = 1.0;
238 dist0 = sqrt((p - p0) * (p - p0) * a +
239 (q - q0) * (q - q0) * b +
240 (p - p0) * (q - q0) * c +
241 dist * dist);
242 if (dist0 < best) {
243 best = dist0;
244 x = p0;
245 y = q0;
246 z = dist0;
247 }
248 return TRUE;
249}
250
251//=============================================================================================================
252
253int MNESurface::nearest_triangle_point(const Eigen::Vector3f& r, int tri, float &x, float &y, float &z) const
254{
255 return nearest_triangle_point(r, nullptr, tri, x, y, z);
256}
257
258//=============================================================================================================
259
260Eigen::Vector3f MNESurface::project_to_triangle(int tri, float p, float q) const
261{
262 const MNETriangle* this_tri = &tris[tri];
263
264 return Eigen::Vector3f(
265 this_tri->r1[0] + p * this_tri->r12[0] + q * this_tri->r13[0],
266 this_tri->r1[1] + p * this_tri->r12[1] + q * this_tri->r13[1],
267 this_tri->r1[2] + p * this_tri->r12[2] + q * this_tri->r13[2]
268 );
269}
270
271//=============================================================================================================
272
273Eigen::Vector3f MNESurface::project_to_triangle(int best, const Eigen::Vector3f& r) const
274{
275 float p, q, dist;
276 nearest_triangle_point(r, best, p, q, dist);
277 return project_to_triangle(best, p, q);
278}
279
280//=============================================================================================================
281
282int MNESurface::project_to_surface(const MNEProjData *proj_data, const Eigen::Vector3f& r, float &distp) const
283{
284 float dist;
285 float p, q;
286 float p0, q0, dist0;
287 int best;
288 int k;
289
290 p0 = q0 = 0.0;
291 dist0 = 0.0;
292 for (best = -1, k = 0; k < ntri; k++) {
293 if (nearest_triangle_point(r, proj_data, k, p, q, dist)) {
294 if (best < 0 || std::fabs(dist) < std::fabs(dist0)) {
295 dist0 = dist;
296 best = k;
297 p0 = p;
298 q0 = q;
299 }
300 }
301 }
302 distp = dist0;
303 return best;
304}
305
306//=============================================================================================================
307
309 Eigen::VectorXi& nearest_tri,
310 Eigen::VectorXf& dist, int nstep) const
311{
312 MNEProjData* p = new MNEProjData(this);
313 int k, was;
314
315 printf("%s for %d points %d steps...", nearest_tri[0] < 0 ? "Closest" : "Approx closest", np_points, nstep);
316
317 for (k = 0; k < np_points; k++) {
318 was = nearest_tri[k];
319 Eigen::Vector3f pt = Eigen::Map<const Eigen::Vector3f>(r.row(k).data());
320 decide_search_restriction(*p, nearest_tri[k], nstep, pt);
321 nearest_tri[k] = project_to_surface(p, pt, dist[k]);
322 if (nearest_tri[k] < 0) {
323 decide_search_restriction(*p, -1, nstep, pt);
324 nearest_tri[k] = project_to_surface(p, pt, dist[k]);
325 }
326 }
327 (void)was;
328
329 printf("[done]\n");
330 delete p;
331}
332
333//=============================================================================================================
334
336 int approx_best,
337 int nstep,
338 const Eigen::Vector3f& r) const
339{
340 int k;
341 float diff[3], dist_val, mindist;
342 int minvert;
343
344 for (k = 0; k < ntri; k++)
345 p.act[k] = FALSE;
346
347 if (approx_best < 0) {
348 mindist = 1000.0;
349 minvert = 0;
350 for (k = 0; k < np; k++) {
351 VEC_DIFF_17(r, &rr(k, 0), diff);
352 dist_val = VEC_LEN_17(diff);
353 if (dist_val < mindist && nneighbor_tri[k] > 0) {
354 mindist = dist_val;
355 minvert = k;
356 }
357 }
358 }
359 else {
360 const MNETriangle* this_tri = &tris[approx_best];
361 VEC_DIFF_17(r, this_tri->r1, diff);
362 mindist = VEC_LEN_17(diff);
363 minvert = this_tri->vert[0];
364
365 VEC_DIFF_17(r, this_tri->r2, diff);
366 dist_val = VEC_LEN_17(diff);
367 if (dist_val < mindist) {
368 mindist = dist_val;
369 minvert = this_tri->vert[1];
370 }
371 VEC_DIFF_17(r, this_tri->r3, diff);
372 dist_val = VEC_LEN_17(diff);
373 if (dist_val < mindist) {
374 mindist = dist_val;
375 minvert = this_tri->vert[2];
376 }
377 }
378
379 activate_neighbors(minvert, p.act, nstep);
380
381 for (k = 0, p.nactive = 0; k < ntri; k++)
382 if (p.act[k])
383 p.nactive++;
384}
385
386//=============================================================================================================
387
388void MNESurface::activate_neighbors(int start, Eigen::VectorXi &act, int nstep) const
389{
390 int k;
391
392 if (nstep == 0)
393 return;
394
395 for (k = 0; k < nneighbor_tri[start]; k++)
396 act[neighbor_tri[start][k]] = TRUE;
397 for (k = 0; k < nneighbor_vert[start]; k++)
398 activate_neighbors(neighbor_vert[start][k], act, nstep - 1);
399}
400
401//=============================================================================================================
402// Static factory methods
403//=============================================================================================================
404
405MNESurface* MNESurface::read_bem_surface(const QString& name, int which, int add_geometry, float *sigmap)
406{
407 return read_bem_surface(name, which, add_geometry, sigmap, true);
408}
409
410//=============================================================================================================
411
412MNESurface* MNESurface::read_bem_surface2(const QString& name, int which, int add_geometry, float *sigmap)
413{
414 return read_bem_surface(name, which, add_geometry, sigmap, FALSE);
415}
416
417//=============================================================================================================
418
419MNESurface* MNESurface::read_bem_surface(const QString& name, int which, int add_geometry, float *sigmap, bool check_too_many_neighbors)
420{
421 QFile file(name);
422 FiffStream::SPtr stream(new FiffStream(&file));
423
424 QList<FiffDirNode::SPtr> surfs;
425 QList<FiffDirNode::SPtr> bems;
427 FiffTag::SPtr t_pTag;
428
429 int id = -1;
430 int nnode, ntri_count;
431 MNESurface* s = NULL;
432 int k;
433 MatrixXf tmp_node_normals;
435 float sigma = -1.0;
436 MatrixXf tmp_nodes;
437 MatrixXi tmp_triangles;
438
439 if (!stream->open())
440 goto bad;
441
442 bems = stream->dirtree()->dir_tree_find(FIFFB_BEM);
443 if (bems.size() > 0) {
444 node = bems[0];
445 if (node->find_tag(stream, FIFF_BEM_COORD_FRAME, t_pTag)) {
446 coord_frame = *t_pTag->toInt();
447 }
448 }
449 surfs = stream->dirtree()->dir_tree_find(FIFFB_BEM_SURF);
450 if (surfs.size() == 0) {
451 printf("No BEM surfaces found in %s", name.toUtf8().constData());
452 goto bad;
453 }
454 if (which >= 0) {
455 for (k = 0; k < surfs.size(); ++k) {
456 node = surfs[k];
457 if (node->find_tag(stream, FIFF_BEM_SURF_ID, t_pTag)) {
458 id = *t_pTag->toInt();
459 if (id == which)
460 break;
461 }
462 }
463 if (id != which) {
464 printf("Desired surface not found in %s", name.toUtf8().constData());
465 goto bad;
466 }
467 }
468 else
469 node = surfs[0];
470
471 if (!node->find_tag(stream, FIFF_BEM_SURF_NNODE, t_pTag))
472 goto bad;
473 nnode = *t_pTag->toInt();
474
475 if (!node->find_tag(stream, FIFF_BEM_SURF_NTRI, t_pTag))
476 goto bad;
477 ntri_count = *t_pTag->toInt();
478
479 if (!node->find_tag(stream, FIFF_BEM_SURF_NODES, t_pTag))
480 goto bad;
481 tmp_nodes = t_pTag->toFloatMatrix().transpose();
482
483 if (node->find_tag(stream, FIFF_BEM_SURF_NORMALS, t_pTag)) {
484 tmp_node_normals = t_pTag->toFloatMatrix().transpose();
485 }
486
487 if (!node->find_tag(stream, FIFF_BEM_SURF_TRIANGLES, t_pTag))
488 goto bad;
489 tmp_triangles = t_pTag->toIntMatrix().transpose();
490
491 if (node->find_tag(stream, FIFF_MNE_COORD_FRAME, t_pTag)) {
492 coord_frame = *t_pTag->toInt();
493 }
494 else if (node->find_tag(stream, FIFF_BEM_COORD_FRAME, t_pTag)) {
495 coord_frame = *t_pTag->toInt();
496 }
497 if (node->find_tag(stream, FIFF_BEM_SIGMA, t_pTag)) {
498 sigma = *t_pTag->toFloat();
499 }
500
501 stream->close();
502
503 s = new MNESurface();
504 tmp_triangles.array() -= 1;
505 s->itris = tmp_triangles;
506 s->id = which;
507 s->sigma = sigma;
509 s->rr = tmp_nodes;
510 s->nn = tmp_node_normals;
511 s->ntri = ntri_count;
512 s->np = nnode;
514 s->nuse_tri = 0;
515 s->tot_area = 0.0;
516 s->dist_limit = -1.0;
517 s->vol_dims[0] = s->vol_dims[1] = s->vol_dims[2] = 0;
518 s->MRI_vol_dims[0] = s->MRI_vol_dims[1] = s->MRI_vol_dims[2] = 0;
519 s->cm[0] = s->cm[1] = s->cm[2] = 0.0;
520
521 if (add_geometry) {
522 if (check_too_many_neighbors) {
523 if (s->add_geometry_info(s->nn.rows() == 0) != OK)
524 goto bad;
525 }
526 else {
527 if (s->add_geometry_info2(s->nn.rows() == 0) != OK)
528 goto bad;
529 }
530 }
531 else if (s->nn.rows() == 0) {
532 if (s->add_vertex_normals() != OK)
533 goto bad;
534 }
535 else
537
538 s->nuse = s->np;
539 s->inuse = Eigen::VectorXi::Ones(s->np);
540 s->vertno = Eigen::VectorXi::LinSpaced(s->np, 0, s->np - 1);
541 if (sigmap)
542 *sigmap = sigma;
543
544 return s;
545
546bad : {
547 stream->close();
548 if (s)
549 delete s;
550 return NULL;
551 }
552}
#define FIFF_MNE_COORD_FRAME
#define FIFFV_MNE_SPACE_SURFACE
#define FIFFV_COORD_MRI
FiffStream class declaration.
#define FIFFB_BEM_SURF
Definition fiff_file.h:404
#define FIFF_BEM_SURF_NNODE
Definition fiff_file.h:733
#define FIFF_BEM_SURF_NODES
Definition fiff_file.h:735
#define FIFF_BEM_SURF_TRIANGLES
Definition fiff_file.h:736
#define FIFF_BEM_COORD_FRAME
Definition fiff_file.h:743
#define FIFFB_BEM
Definition fiff_file.h:403
#define FIFF_BEM_SURF_ID
Definition fiff_file.h:731
#define FIFF_BEM_SURF_NTRI
Definition fiff_file.h:734
#define FIFF_BEM_SIGMA
Definition fiff_file.h:744
#define FIFF_BEM_SURF_NORMALS
Definition fiff_file.h:737
FiffCoordTrans class declaration.
MNETriangle class declaration.
MNESurface class declaration.
#define VEC_DIFF_17(from, to, diff)
#define VEC_LEN_17(x)
#define VEC_DOT_17(x, y)
MNEProjData class declaration.
MNESourceSpace class declaration.
#define TRUE
#define FALSE
#define OK
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
QSharedPointer< FiffDirNode > SPtr
FIFF File I/O routines.
QSharedPointer< FiffStream > SPtr
QSharedPointer< FiffTag > SPtr
Definition fiff_tag.h:155
Auxiliary projection data computed from MNEProjOp for efficient repeated application.
Eigen::VectorXf b
Eigen::VectorXf c
Eigen::VectorXi act
Eigen::VectorXf a
double sum_solids(const Eigen::Vector3f &from) const
void find_closest_on_surface_approx(const PointsT &r, int np, Eigen::VectorXi &nearest_tri, Eigen::VectorXf &dist, int nstep) const
static MNESurface * read_bem_surface2(const QString &name, int which, int add_geometry, float *sigmap)
Eigen::Vector3f project_to_triangle(int tri, float p, float q) const
void triangle_coords(const Eigen::Vector3f &r, int tri, float &x, float &y, float &z) const
int project_to_surface(const MNEProjData *proj_data, const Eigen::Vector3f &r, float &distp) const
void decide_search_restriction(MNEProjData &p, int approx_best, int nstep, const Eigen::Vector3f &r) const
static MNESurface * read_bem_surface(const QString &name, int which, int add_geometry, float *sigmap)
int nearest_triangle_point(const Eigen::Vector3f &r, const MNEProjData *user, int tri, float &x, float &y, float &z) const
void activate_neighbors(int start, Eigen::VectorXi &act, int nstep) const
std::vector< Eigen::VectorXi > neighbor_tri
int add_geometry_info(int do_normals, int check_too_many_neighbors)
std::vector< Eigen::VectorXi > neighbor_vert
FIFFLIB::FiffSparseMatrix dist
static double solid_angle(const Eigen::Vector3f &from, const MNELIB::MNETriangle &tri)
std::vector< MNETriangle > tris
Eigen::Matrix< float, Eigen::Dynamic, 3, Eigen::RowMajor > PointsT
Per-triangle geometric data for a cortical or BEM surface.
Eigen::Vector3f r13
Eigen::Vector3f nn
Eigen::Vector3f r12