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 + p * this_tri->r12 + q * this_tri->r13
266 );
267}
268
269//=============================================================================================================
270
271Eigen::Vector3f MNESurface::project_to_triangle(int best, const Eigen::Vector3f& r) const
272{
273 float p, q, dist;
274 nearest_triangle_point(r, best, p, q, dist);
275 return project_to_triangle(best, p, q);
276}
277
278//=============================================================================================================
279
280int MNESurface::project_to_surface(const MNEProjData *proj_data, const Eigen::Vector3f& r, float &distp) const
281{
282 float dist;
283 float p, q;
284 float p0, q0, dist0;
285 int best;
286 int k;
287
288 p0 = q0 = 0.0;
289 dist0 = 0.0;
290 for (best = -1, k = 0; k < ntri; k++) {
291 if (nearest_triangle_point(r, proj_data, k, p, q, dist)) {
292 if (best < 0 || std::fabs(dist) < std::fabs(dist0)) {
293 dist0 = dist;
294 best = k;
295 p0 = p;
296 q0 = q;
297 }
298 }
299 }
300 distp = dist0;
301 return best;
302}
303
304//=============================================================================================================
305
307 Eigen::VectorXi& nearest_tri,
308 Eigen::VectorXf& dist, int nstep) const
309{
310 MNEProjData* p = new MNEProjData(this);
311 int k, was;
312
313 printf("%s for %d points %d steps...", nearest_tri[0] < 0 ? "Closest" : "Approx closest", np_points, nstep);
314
315 for (k = 0; k < np_points; k++) {
316 was = nearest_tri[k];
317 Eigen::Vector3f pt = Eigen::Map<const Eigen::Vector3f>(r.row(k).data());
318 decide_search_restriction(*p, nearest_tri[k], nstep, pt);
319 nearest_tri[k] = project_to_surface(p, pt, dist[k]);
320 if (nearest_tri[k] < 0) {
321 decide_search_restriction(*p, -1, nstep, pt);
322 nearest_tri[k] = project_to_surface(p, pt, dist[k]);
323 }
324 }
325 (void)was;
326
327 printf("[done]\n");
328 delete p;
329}
330
331//=============================================================================================================
332
334 int approx_best,
335 int nstep,
336 const Eigen::Vector3f& r) const
337{
338 int k;
339 float diff[3], dist_val, mindist;
340 int minvert;
341
342 for (k = 0; k < ntri; k++)
343 p.act[k] = FALSE;
344
345 if (approx_best < 0) {
346 mindist = 1000.0;
347 minvert = 0;
348 for (k = 0; k < np; k++) {
349 VEC_DIFF_17(r, &rr(k, 0), diff);
350 dist_val = VEC_LEN_17(diff);
351 if (dist_val < mindist && nneighbor_tri[k] > 0) {
352 mindist = dist_val;
353 minvert = k;
354 }
355 }
356 }
357 else {
358 const MNETriangle* this_tri = &tris[approx_best];
359 VEC_DIFF_17(r, this_tri->r1, diff);
360 mindist = VEC_LEN_17(diff);
361 minvert = this_tri->vert[0];
362
363 VEC_DIFF_17(r, this_tri->r2, diff);
364 dist_val = VEC_LEN_17(diff);
365 if (dist_val < mindist) {
366 mindist = dist_val;
367 minvert = this_tri->vert[1];
368 }
369 VEC_DIFF_17(r, this_tri->r3, diff);
370 dist_val = VEC_LEN_17(diff);
371 if (dist_val < mindist) {
372 mindist = dist_val;
373 minvert = this_tri->vert[2];
374 }
375 }
376
377 activate_neighbors(minvert, p.act, nstep);
378
379 for (k = 0, p.nactive = 0; k < ntri; k++)
380 if (p.act[k])
381 p.nactive++;
382}
383
384//=============================================================================================================
385
386void MNESurface::activate_neighbors(int start, Eigen::VectorXi &act, int nstep) const
387{
388 int k;
389
390 if (nstep == 0)
391 return;
392
393 for (k = 0; k < nneighbor_tri[start]; k++)
394 act[neighbor_tri[start][k]] = TRUE;
395 for (k = 0; k < nneighbor_vert[start]; k++)
396 activate_neighbors(neighbor_vert[start][k], act, nstep - 1);
397}
398
399//=============================================================================================================
400// Static factory methods
401//=============================================================================================================
402
403MNESurface* MNESurface::read_bem_surface(const QString& name, int which, int add_geometry, float *sigmap)
404{
405 return read_bem_surface(name, which, add_geometry, sigmap, true);
406}
407
408//=============================================================================================================
409
410MNESurface* MNESurface::read_bem_surface2(const QString& name, int which, int add_geometry, float *sigmap)
411{
412 return read_bem_surface(name, which, add_geometry, sigmap, FALSE);
413}
414
415//=============================================================================================================
416
417MNESurface* MNESurface::read_bem_surface(const QString& name, int which, int add_geometry, float *sigmap, bool check_too_many_neighbors)
418{
419 QFile file(name);
420 FiffStream::SPtr stream(new FiffStream(&file));
421
422 QList<FiffDirNode::SPtr> surfs;
423 QList<FiffDirNode::SPtr> bems;
425 FiffTag::UPtr t_pTag;
426
427 int id = -1;
428 int nnode, ntri_count;
429 MNESurface* s = NULL;
430 int k;
431 MatrixXf tmp_node_normals;
433 float sigma = -1.0;
434 MatrixXf tmp_nodes;
435 MatrixXi tmp_triangles;
436
437 if (!stream->open())
438 goto bad;
439
440 bems = stream->dirtree()->dir_tree_find(FIFFB_BEM);
441 if (bems.size() > 0) {
442 node = bems[0];
443 if (node->find_tag(stream, FIFF_BEM_COORD_FRAME, t_pTag)) {
444 coord_frame = *t_pTag->toInt();
445 }
446 }
447 surfs = stream->dirtree()->dir_tree_find(FIFFB_BEM_SURF);
448 if (surfs.size() == 0) {
449 printf("No BEM surfaces found in %s", name.toUtf8().constData());
450 goto bad;
451 }
452 if (which >= 0) {
453 for (k = 0; k < surfs.size(); ++k) {
454 node = surfs[k];
455 if (node->find_tag(stream, FIFF_BEM_SURF_ID, t_pTag)) {
456 id = *t_pTag->toInt();
457 if (id == which)
458 break;
459 }
460 }
461 if (id != which) {
462 printf("Desired surface not found in %s", name.toUtf8().constData());
463 goto bad;
464 }
465 }
466 else
467 node = surfs[0];
468
469 if (!node->find_tag(stream, FIFF_BEM_SURF_NNODE, t_pTag))
470 goto bad;
471 nnode = *t_pTag->toInt();
472
473 if (!node->find_tag(stream, FIFF_BEM_SURF_NTRI, t_pTag))
474 goto bad;
475 ntri_count = *t_pTag->toInt();
476
477 if (!node->find_tag(stream, FIFF_BEM_SURF_NODES, t_pTag))
478 goto bad;
479 tmp_nodes = t_pTag->toFloatMatrix().transpose();
480
481 if (node->find_tag(stream, FIFF_BEM_SURF_NORMALS, t_pTag)) {
482 tmp_node_normals = t_pTag->toFloatMatrix().transpose();
483 }
484
485 if (!node->find_tag(stream, FIFF_BEM_SURF_TRIANGLES, t_pTag))
486 goto bad;
487 tmp_triangles = t_pTag->toIntMatrix().transpose();
488
489 if (node->find_tag(stream, FIFF_MNE_COORD_FRAME, t_pTag)) {
490 coord_frame = *t_pTag->toInt();
491 }
492 else if (node->find_tag(stream, FIFF_BEM_COORD_FRAME, t_pTag)) {
493 coord_frame = *t_pTag->toInt();
494 }
495 if (node->find_tag(stream, FIFF_BEM_SIGMA, t_pTag)) {
496 sigma = *t_pTag->toFloat();
497 }
498
499 stream->close();
500
501 s = new MNESurface();
502 tmp_triangles.array() -= 1;
503 s->itris = tmp_triangles;
504 s->id = which;
505 s->sigma = sigma;
507 s->rr = tmp_nodes;
508 s->nn = tmp_node_normals;
509 s->ntri = ntri_count;
510 s->np = nnode;
512 s->nuse_tri = 0;
513 s->tot_area = 0.0;
514 s->dist_limit = -1.0;
515 s->vol_dims[0] = s->vol_dims[1] = s->vol_dims[2] = 0;
516 s->MRI_vol_dims[0] = s->MRI_vol_dims[1] = s->MRI_vol_dims[2] = 0;
517 s->cm[0] = s->cm[1] = s->cm[2] = 0.0;
518
519 if (add_geometry) {
520 if (check_too_many_neighbors) {
521 if (s->add_geometry_info(s->nn.rows() == 0) != OK)
522 goto bad;
523 }
524 else {
525 if (s->add_geometry_info2(s->nn.rows() == 0) != OK)
526 goto bad;
527 }
528 }
529 else if (s->nn.rows() == 0) {
530 if (s->add_vertex_normals() != OK)
531 goto bad;
532 }
533 else
535
536 s->nuse = s->np;
537 s->inuse = Eigen::VectorXi::Ones(s->np);
538 s->vertno = Eigen::VectorXi::LinSpaced(s->np, 0, s->np - 1);
539 if (sigmap)
540 *sigmap = sigma;
541
542 return s;
543
544bad : {
545 stream->close();
546 if (s)
547 delete s;
548 return NULL;
549 }
550}
#define TRUE
#define FALSE
#define OK
#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.
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
std::unique_ptr< FiffTag > UPtr
Definition fiff_tag.h:158
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 r2
Eigen::Vector3f r1
Eigen::Vector3f r3
Eigen::Vector3f r12