58#include <QtConcurrent>
60#define _USE_MATH_DEFINES
69#define ALLOC_INT_51(x) MALLOC_51(x,int)
71#define MALLOC_51(x,t) (t *)malloc((x)*sizeof(t))
73#define ALLOC_CMATRIX_51(x,y) mne_cmatrix_51((x),(y))
95#define VEC_DOT_17(x,y) ((x)[X_17]*(y)[X_17] + (x)[Y_17]*(y)[Y_17] + (x)[Z_17]*(y)[Z_17])
97#define VEC_LEN_17(x) sqrt(VEC_DOT_17(x,x))
99#define VEC_DIFF_17(from,to,diff) {\
100 (diff)[X_17] = (to)[X_17] - (from)[X_17];\
101 (diff)[Y_17] = (to)[Y_17] - (from)[Y_17];\
102 (diff)[Z_17] = (to)[Z_17] - (from)[Z_17];\
105#define VEC_COPY_17(to,from) {\
106 (to)[X_17] = (from)[X_17];\
107 (to)[Y_17] = (from)[Y_17];\
108 (to)[Z_17] = (from)[Z_17];\
111#define FREE_17(x) if ((char *)(x) != NULL) free((char *)(x))
113#define MALLOC_17(x,t) (t *)malloc((x)*sizeof(t))
115#define ALLOC_CMATRIX_17(x,y) mne_cmatrix_17((x),(y))
117#define ALLOC_ICMATRIX_17(x,y) mne_imatrix_17((x),(y))
119#define FREE_CMATRIX_17(m) mne_free_cmatrix_17((m))
121#define FREE_ICMATRIX_17(m) mne_free_icmatrix_17((m))
125#define CURVATURE_FILE_MAGIC_NUMBER (16777215)
127#define TAG_OLD_MGH_XFORM 30
128#define TAG_OLD_COLORTABLE 1
129#define TAG_OLD_USEREALRAS 2
130#define TAG_USEREALRAS 4
132static void matrix_error_17(
int kind,
int nr,
int nc)
136 printf(
"Failed to allocate memory pointers for a %d x %d matrix\n",nr,nc);
138 printf(
"Failed to allocate memory for a %d x %d matrix\n",nr,nc);
140 printf(
"Allocation error for a %d x %d matrix\n",nr,nc);
141 if (
sizeof(
void *) == 4) {
142 printf(
"This is probably because you seem to be using a computer with 32-bit architecture.\n");
143 printf(
"Please consider moving to a 64-bit platform.");
145 printf(
"Cannot continue. Sorry.\n");
149static float** mne_cmatrix_17(
int nr,
int nc)
156 if (!m) matrix_error_17(1,nr,nc);
158 if (!whole) matrix_error_17(2,nr,nc);
165static int **mne_imatrix_17(
int nr,
int nc)
171 if (!m) matrix_error_17(1,nr,nc);
173 if (!whole) matrix_error_17(2,nr,nc);
179static void mne_free_cmatrix_17(
float **m)
187static void mne_free_icmatrix_17(
int **m)
195static void matrix_error_51(
int kind,
int nr,
int nc)
199 printf(
"Failed to allocate memory pointers for a %d x %d matrix\n",nr,nc);
201 printf(
"Failed to allocate memory for a %d x %d matrix\n",nr,nc);
203 printf(
"Allocation error for a %d x %d matrix\n",nr,nc);
204 if (
sizeof(
void *) == 4) {
205 printf(
"This is probably because you seem to be using a computer with 32-bit architecture.\n");
206 printf(
"Please consider moving to a 64-bit platform.");
208 printf(
"Cannot continue. Sorry.\n");
220 if (!m) matrix_error_51(1,nr,nc);
222 if (!whole) matrix_error_51(2,nr,nc);
233using namespace Eigen;
250int read_int3(QFile &in,
int &ival)
257 if (in.read(
reinterpret_cast<char*
>(&s), 3) != 3) {
258 qCritical(
"read_int3 could not read data");
262 ival = ((s >> 8) & 0xffffff);
266int read_int(QFile &in, qint32 &ival)
272 if (in.read(
reinterpret_cast<char*
>(&s),
sizeof(qint32)) !=
static_cast<qint64
>(
sizeof(qint32))) {
273 qCritical(
"read_int could not read data");
280int read_int2(QFile &in,
int &ival)
286 if (in.read(
reinterpret_cast<char*
>(&s),
sizeof(
short)) !=
static_cast<qint64
>(
sizeof(
short))) {
287 qCritical(
"read_int2 could not read data");
294int read_float(QFile &in,
float &fval)
300 if (in.read(
reinterpret_cast<char*
>(&f),
sizeof(
float)) !=
static_cast<qint64
>(
sizeof(
float))) {
301 qCritical(
"read_float could not read data");
308int read_long(QFile &in,
long long &lval)
314 if (in.read(
reinterpret_cast<char*
>(&s),
sizeof(
long long)) !=
static_cast<qint64
>(
sizeof(
long long))) {
315 qCritical(
"read_long could not read data");
326int check_vertex(
int no,
int maxno)
328 if (no < 0 || no > maxno-1) {
329 printf(
"Illegal vertex number %d (max %d).",no,maxno);
361 while (!fp.atEnd() && counter < 8)
363 QByteArray lineData = fp.readLine(256);
364 if (lineData.isEmpty())
366 const char *line = lineData.constData();
367 if (strlen(line) == 0)
369 sscanf(line,
"%s %s %*s", param, eq);
370 if (!strcmp(param,
"valid")) {
371 sscanf(line,
"%s %s %d", param, eq, &vg->
valid);
375 else if (!strcmp(param,
"filename")) {
376 if (sscanf(line,
"%s %s %s", param, eq, buf) >= 3)
380 else if (!strcmp(param,
"volume")) {
381 sscanf(line,
"%s %s %d %d %d",
385 else if (!strcmp(param,
"voxelsize")) {
386 sscanf(line,
"%s %s %f %f %f",
396 else if (!strcmp(param,
"xras")) {
397 sscanf(line,
"%s %s %f %f %f",
401 else if (!strcmp(param,
"yras")) {
402 sscanf(line,
"%s %s %f %f %f",
406 else if (!strcmp(param,
"zras")) {
407 sscanf(line,
"%s %s %f %f %f",
411 else if (!strcmp(param,
"cras")) {
412 sscanf(line,
"%s %s %f %f %f",
438int read_tag_data(QFile &fp,
int tag,
long long nbytes,
unsigned char *&val,
long long &nbytesp)
443 unsigned char *dum = NULL;
444 size_t snbytes = nbytes;
449 if (fp.read(
reinterpret_cast<char*
>(dum), nbytes) !=
static_cast<qint64
>(snbytes)) {
450 printf(
"Failed to read %d bytes of tag data",
static_cast<int>(nbytes));
463 val = (
unsigned char *)g;
468 if (read_int(fp,*vi) ==
FAIL)
470 val = (
unsigned char *)vi;
471 nbytesp =
sizeof(int);
474 printf(
"Encountered an unknown tag with no length specification : %d\n",tag);
486void add_mgh_tag_to_group(std::optional<MNEMghTagGroup>& g,
int tag,
long long len,
unsigned char *data)
490 auto new_tag = std::make_unique<MNEMghTag>();
493 new_tag->data = QByteArray(
reinterpret_cast<const char*
>(data),
static_cast<int>(len));
495 g->tags.push_back(std::move(new_tag));
502int read_next_tag(QFile &fp,
int &tagp,
long long &lenp,
unsigned char *&datap)
510 if (read_int(fp,tag) ==
FAIL) {
520 if (read_int(fp,ilen) ==
FAIL)
530 if (read_long(fp,len) ==
FAIL)
536 if (read_tag_data(fp,tag,len,datap,lenp) ==
FAIL)
545int read_mgh_tags(QFile &fp, std::optional<MNEMghTagGroup>& tagsp)
552 unsigned char *tag_data;
555 if (read_next_tag(fp,tag,len,tag_data) ==
FAIL)
559 add_mgh_tag_to_group(tagsp,tag,len,tag_data);
568int read_curvature_file(
const QString& fname,
569 Eigen::VectorXf& curv)
575 float curvmin,curvmax;
577 int nface,val_pervert;
581 if (!fp.open(QIODevice::ReadOnly)) {
582 qCritical() << fname;
585 if (read_int3(fp,magic) != 0) {
586 qCritical() <<
"Bad magic in" << fname;
593 if (read_int(fp,ncurv) != 0)
595 if (read_int(fp,nface) != 0)
598 printf(
"nvert = %d nface = %d\n",ncurv,nface);
600 if (read_int(fp,val_pervert) != 0)
602 if (val_pervert != 1) {
603 qCritical(
"Values per vertex not equal to one.");
610 curvmin = curvmax = 0.0;
611 for (k = 0; k < ncurv; k++) {
612 if (read_float(fp,fval) != 0)
615 if (curv[k] > curvmax)
617 if (curv[k] < curvmin)
626 if (read_int3(fp,nface) != 0)
629 printf(
"nvert = %d nface = %d\n",ncurv,nface);
635 curvmin = curvmax = 0.0;
636 for (k = 0; k < ncurv; k++) {
637 if (read_int2(fp,val) != 0)
639 curv[k] = (float)val/100.0;
640 if (curv[k] > curvmax)
642 if (curv[k] < curvmin)
648 printf(
"Curvature range: %f...%f\n",curvmin,curvmax);
662int read_triangle_file(
const QString& fname,
664 TrianglesT& triangles,
665 std::optional<MNEMghTagGroup>* tagsp)
674 qint32 nvert,ntri,nquad;
683 if (!fp.open(QIODevice::ReadOnly)) {
684 qCritical() << fname;
687 if (read_int3(fp,magic) != 0) {
688 qCritical() <<
"Bad magic in" << fname;
694 qCritical() <<
"Bad magic in" << fname;
701 printf(
"Triangle file : ");
702 for (fp.getChar(&c); c !=
'\n'; fp.getChar(&c)) {
704 qCritical()<<
"Bad triangle file.";
713 if (read_int(fp,nvert) != 0)
715 if (read_int(fp,ntri) != 0)
717 printf(
" nvert = %d ntri = %d\n",nvert,ntri);
723 for (k = 0; k < nvert; k++) {
724 if (read_float(fp,vert[k][
X_17]) != 0)
726 if (read_float(fp,vert[k][
Y_17]) != 0)
728 if (read_float(fp,vert[k][
Z_17]) != 0)
734 for (k = 0; k < ntri; k++) {
735 if (read_int(fp,tri[k][
X_17]) != 0)
737 if (check_vertex(tri[k][
X_17],nvert) !=
OK)
739 if (read_int(fp,tri[k][
Y_17]) != 0)
741 if (check_vertex(tri[k][
Y_17],nvert) !=
OK)
743 if (read_int(fp,tri[k][
Z_17]) != 0)
745 if (check_vertex(tri[k][
Z_17],nvert) !=
OK)
751 if (read_int3(fp,nvert) != 0)
753 if (read_int3(fp,nquad) != 0)
755 printf(
"%s file : nvert = %d nquad = %d\n",
760 for (k = 0; k < nvert; k++) {
761 if (read_int2(fp,val) != 0)
763 vert[k][
X_17] = val/100.0;
764 if (read_int2(fp,val) != 0)
766 vert[k][
Y_17] = val/100.0;
767 if (read_int2(fp,val) != 0)
769 vert[k][
Z_17] = val/100.0;
773 for (k = 0; k < nvert; k++) {
774 if (read_float(fp,vert[k][
X_17]) != 0)
776 if (read_float(fp,vert[k][
Y_17]) != 0)
778 if (read_float(fp,vert[k][
Z_17]) != 0)
784 for (k = 0, ntri = 0; k < nquad; k++) {
785 for (p = 0; p < 4; p++) {
786 if (read_int3(fp,quad[p]) != 0)
788 rr[p] = vert[quad[p]];
790 rr[4] = vert[quad[0]];
796#define EVEN(n) ((((n) / 2) * 2) == n)
798#define WHICH_FACE_SPLIT(vno0, vno1) \
799 (1*nearbyint(sqrt(1.9*vno0) + sqrt(3.5*vno1)))
801 which = WHICH_FACE_SPLIT(quad[0], quad[1]) ;
809 tri[ntri][
X_17] = quad[0];
810 tri[ntri][
Y_17] = quad[1];
811 tri[ntri][
Z_17] = quad[3];
814 tri[ntri][
X_17] = quad[2];
815 tri[ntri][
Y_17] = quad[3];
816 tri[ntri][
Z_17] = quad[1];
820 tri[ntri][
X_17] = quad[0];
821 tri[ntri][
Y_17] = quad[1];
822 tri[ntri][
Z_17] = quad[2];
825 tri[ntri][
X_17] = quad[0];
826 tri[ntri][
Y_17] = quad[2];
827 tri[ntri][
Z_17] = quad[3];
836 std::optional<MNEMghTagGroup> tags;
837 if (read_mgh_tags(fp, tags) ==
FAIL) {
840 *tagsp = std::move(tags);
845 for (k = 0; k < nvert; k++) {
846 vert[k][
X_17] = vert[k][
X_17]/1000.0;
847 vert[k][
Y_17] = vert[k][
Y_17]/1000.0;
848 vert[k][
Z_17] = vert[k][
Z_17]/1000.0;
850 vertices = Eigen::Map<PointsT>(vert[0], nvert, 3);
852 triangles = Eigen::Map<TrianglesT>(tri[0], ntri, 3);
867std::optional<MNEVolGeom> get_volume_geom_from_tag(
const MNEMghTagGroup *tagsp)
872 for (
const auto &t : tagsp->
tags)
878 return dup_vol_geom(*
reinterpret_cast<MNEVolGeom*
>(tag->
data.data()));
893 rr = PointsT::Zero(
np, 3);
894 nn = NormalsT::Zero(
np, 3);
948 auto copy = std::make_shared<MNESourceSpace>(this->
np);
949 copy->type = this->
type;
952 copy->ntri = this->ntri;
956 copy->nuse = this->
nuse;
957 copy->inuse = this->
inuse;
958 copy->vertno = this->
vertno;
959 copy->itris = this->
itris;
963 copy->dist = this->
dist;
975 for (k = 0; k <
np; k++)
991 for (k = 0, xave = 0.0; k <
np; k++)
1003 double xave =
rr.col(0).sum();
1019 inuse = std::move(new_inuse);
1021 for (k = 0, nuse_count = 0; k <
np; k++)
1028 for (k = 0, p = 0; k <
np; k++)
1049 printf(
"Coordinate transformation does not match with the source space coordinate system.");
1052 for (k = 0; k <
np; k++) {
1056 if (!
tris.empty()) {
1057 for (k = 0; k <
ntri; k++)
1070 std::vector<std::optional<MNEPatchInfo>> pinfo(
nuse);
1073 printf(
"Computing patch statistics...\n");
1079 qCritical(
"The patch information is not available.");
1089 printf(
"\tareas, average normals, and mean deviations...");
1092 nearest_data =
nearest.data();
1094 for (p = 1, q = 0; p <
np; p++) {
1097 qCritical(
"No vertices belong to the patch of vertex %d",nearest_data[p-1].
nearest);
1103 pinfo[q]->vert = nearest_data[p-1].
nearest;
1104 this_patch = nearest_data+p-nave;
1105 pinfo[q]->memb_vert.resize(nave);
1106 for (k = 0; k < nave; k++) {
1107 pinfo[q]->memb_vert[k] = this_patch[k].
vert;
1108 this_patch[k].
patch = &(*pinfo[q]);
1110 pinfo[q]->calculate_area(
this);
1111 pinfo[q]->calculate_normal_stats(
this);
1119 qCritical(
"No vertices belong to the patch of vertex %d",nearest_data[p-1].
nearest);
1124 pinfo[q]->vert = nearest_data[p-1].
nearest;
1125 this_patch = nearest_data+p-nave;
1126 pinfo[q]->memb_vert.resize(nave);
1127 for (k = 0; k < nave; k++) {
1128 pinfo[q]->memb_vert[k] = this_patch[k].
vert;
1129 this_patch[k].
patch = &(*pinfo[q]);
1131 pinfo[q]->calculate_area(
this);
1132 pinfo[q]->calculate_normal_stats(
this);
1135 printf(
" %d/%d [done]\n",q,
nuse);
1148 for (k = 0,
nuse = 0; k <
np; k++)
1157 for (k = 0, p = 0; k <
np; k++)
1173 auto res = std::make_unique<MNESourceSpace>();
1176 res->rr = PointsT::Zero(
np, 3);
1177 res->nn = NormalsT::Zero(
np, 3);
1178 res->inuse = VectorXi::Zero(
np);
1179 res->vertno = VectorXi::Zero(
np);
1183 res->tot_area = 0.0;
1190 res->subject.clear();
1194 res->dist_limit = -1.0;
1196 res->voxel_surf_RAS_t.reset();
1197 res->vol_dims[0] = res->vol_dims[1] = res->vol_dims[2] = 0;
1199 res->MRI_volume.clear();
1200 res->MRI_surf_RAS_RAS_t.reset();
1201 res->MRI_voxel_surf_RAS_t.reset();
1202 res->MRI_vol_dims[0] = res->MRI_vol_dims[1] = res->MRI_vol_dims[2] = 0;
1203 res->interpolator.reset();
1205 res->vol_geom.reset();
1206 res->mgh_tags.reset();
1208 res->cm[0] = res->cm[1] = res->cm[2] = 0.0;
1216 const QString& curv_file)
1224 const QString& curv_file,
1226 int check_too_many_neighbors)
1232 std::unique_ptr<MNESourceSpace> s;
1233 std::optional<MNEMghTagGroup> tags;
1234 Eigen::VectorXf curvs;
1238 if (read_triangle_file(surf_file,
1244 if (!curv_file.isEmpty()) {
1245 if (read_curvature_file(curv_file, curvs) == -1)
1247 if (curvs.size() != verts.rows()) {
1248 qCritical()<<
"Incorrect number of vertices in the curvature file.";
1253 s = std::make_unique<MNESourceSpace>(0);
1254 s->rr = std::move(verts);
1255 s->itris = std::move(
tris);
1256 s->ntri = s->itris.rows();
1257 s->np = s->rr.rows();
1258 if (curvs.size() > 0) {
1259 s->curv = std::move(curvs);
1261 s->val = Eigen::VectorXf::Zero(s->np);
1263 if (check_too_many_neighbors) {
1264 if (s->add_geometry_info(
TRUE) !=
OK)
1268 if (s->add_geometry_info2(
TRUE) !=
OK)
1272 else if (s->nn.rows() == 0) {
1273 if (s->add_vertex_normals() !=
OK)
1277 s->add_triangle_data();
1279 s->inuse = Eigen::VectorXi::Ones(s->np);
1280 s->vertno = Eigen::VectorXi::LinSpaced(s->np, 0, s->np - 1);
1281 s->mgh_tags = std::move(tags);
1282 s->vol_geom = get_volume_geom_from_tag(s->mgh_tags ? &(*s->mgh_tags) :
nullptr);
1293static std::optional<FiffCoordTrans> make_voxel_ras_trans(
float *r0,
1300 float rot[3][3],move[3];
1305 for (j = 0; j < 3; j++) {
1306 rot[j][0] = x_ras[j];
1307 rot[j][1] = y_ras[j];
1308 rot[j][2] = z_ras[j];
1311 for (j = 0; j < 3; j++)
1312 for (k = 0; k < 3; k++)
1313 rot[j][k] = voxel_size[k]*rot[j][k];
1316 Eigen::Map<Eigen::Matrix3f>(&rot[0][0]),
1317 Eigen::Map<Eigen::Vector3f>(move));
1325 float min[3],max[3],
cm[3];
1326 int minn[3],maxn[3];
1328 float maxdist,
dist,diff[3];
1330 std::unique_ptr<MNESourceSpace> sp;
1338 node = &surf.
rr(0,0);
1339 for (c = 0; c < 3; c++)
1340 min[c] = max[c] = node[c];
1342 for (k = 0; k < surf.
np; k++) {
1343 node = &surf.
rr(k,0);
1344 for (c = 0; c < 3; c++) {
1346 if (node[c] < min[c])
1348 if (node[c] > max[c])
1352 for (c = 0; c < 3; c++)
1358 for (k = 0; k < surf.
np; k++) {
1364 printf(
"Surface CM = (%6.1f %6.1f %6.1f) mm\n",
1366 printf(
"Surface fits inside a sphere with radius %6.1f mm\n",1000*maxdist);
1367 printf(
"Surface extent:\n"
1368 "\tx = %6.1f ... %6.1f mm\n"
1369 "\ty = %6.1f ... %6.1f mm\n"
1370 "\tz = %6.1f ... %6.1f mm\n",
1374 for (c = 0; c < 3; c++) {
1376 maxn[c] = floor(std::fabs(max[c])/grid)+1;
1378 maxn[c] = -floor(std::fabs(max[c])/grid)-1;
1380 minn[c] = floor(std::fabs(min[c])/grid)+1;
1382 minn[c] = -floor(std::fabs(min[c])/grid)-1;
1384 printf(
"Grid extent:\n"
1385 "\tx = %6.1f ... %6.1f mm\n"
1386 "\ty = %6.1f ... %6.1f mm\n"
1387 "\tz = %6.1f ... %6.1f mm\n",
1388 1000*(minn[
X_17]*grid),1000*(maxn[
X_17]*grid),
1389 1000*(minn[
Y_17]*grid),1000*(maxn[
Y_17]*grid),
1390 1000*(minn[
Z_17]*grid),1000*(maxn[
Z_17]*grid));
1395 for (c = 0; c < 3; c++)
1396 np =
np*(maxn[c]-minn[c]+1);
1401 sp->nneighbor_vert = Eigen::VectorXi::Constant(sp->np,
NNEIGHBORS);
1402 sp->neighbor_vert.resize(sp->np);
1403 for (k = 0; k < sp->np; k++) {
1404 sp->inuse[k] =
TRUE;
1406 sp->nn(k,
X_17) = sp->nn(k,
Y_17) = 0.0;
1407 sp->nn(k,
Z_17) = 1.0;
1408 sp->neighbor_vert[k] = Eigen::VectorXi::Constant(
NNEIGHBORS, -1);
1411 for (k = 0, z = minn[
Z_17]; z <= maxn[
Z_17]; z++) {
1412 for (y = minn[
Y_17]; y <= maxn[
Y_17]; y++) {
1413 for (x = minn[
X_17]; x <= maxn[
X_17]; x++, k++) {
1414 sp->rr(k,
X_17) = x*grid;
1415 sp->rr(k,
Y_17) = y*grid;
1416 sp->rr(k,
Z_17) = z*grid;
1421 Eigen::VectorXi& neigh = sp->neighbor_vert[k];
1423 neigh[0] = k - nplane;
1427 neigh[2] = k + nrow;
1431 neigh[4] = k - nrow;
1433 neigh[5] = k + nplane;
1438 if (z > minn[
Z_17]) {
1439 if (x < maxn[
X_17]) {
1440 neigh[6] = k + 1 - nplane;
1442 neigh[7] = k + 1 + nrow - nplane;
1445 neigh[8] = k + nrow - nplane;
1446 if (x > minn[
X_17]) {
1448 neigh[9] = k - 1 + nrow - nplane;
1449 neigh[10] = k - 1 - nplane;
1451 neigh[11] = k - 1 - nrow - nplane;
1453 if (y > minn[
Y_17]) {
1454 neigh[12] = k - nrow - nplane;
1456 neigh[13] = k + 1 - nrow - nplane;
1462 if (x < maxn[
X_17] && y < maxn[
Y_17])
1463 neigh[14] = k + 1 + nrow;
1464 if (x > minn[
X_17]) {
1466 neigh[15] = k - 1 + nrow;
1468 neigh[16] = k - 1 - nrow;
1470 if (y > minn[
Y_17] && x < maxn[
X_17])
1471 neigh[17] = k + 1 - nrow - nplane;
1475 if (z < maxn[
Z_17]) {
1476 if (x < maxn[
X_17]) {
1477 neigh[18] = k + 1 + nplane;
1479 neigh[19] = k + 1 + nrow + nplane;
1482 neigh[20] = k + nrow + nplane;
1483 if (x > minn[
X_17]) {
1485 neigh[21] = k - 1 + nrow + nplane;
1486 neigh[22] = k - 1 + nplane;
1488 neigh[23] = k - 1 - nrow + nplane;
1490 if (y > minn[
Y_17]) {
1491 neigh[24] = k - nrow + nplane;
1493 neigh[25] = k + 1 - nrow + nplane;
1499 printf(
"%d sources before omitting any.\n",sp->nuse);
1503 for (k = 0; k < sp->np; k++) {
1507 sp->inuse[k] =
FALSE;
1511 printf(
"%d sources after omitting infeasible sources.\n",sp->nuse);
1513 std::vector<std::unique_ptr<MNESourceSpace>> sp_vec;
1514 sp_vec.push_back(std::move(sp));
1516 sp = std::move(sp_vec[0]);
1519 sp = std::move(sp_vec[0]);
1521 printf(
"%d sources remaining after excluding the sources outside the surface and less than %6.1f mm inside.\n",sp->nuse,1000*mindist);
1525 printf(
"Adjusting the neighborhood info...");
1526 for (k = 0; k < sp->np; k++) {
1527 Eigen::VectorXi& neigh = sp->neighbor_vert[k];
1528 nneigh = sp->nneighbor_vert[k];
1530 for (c = 0; c < nneigh; c++)
1531 if (!sp->inuse[neigh[c]])
1535 for (c = 0; c < nneigh; c++)
1544 float r0[3],
voxel_size[3],x_ras[3],y_ras[3],z_ras[3];
1545 int width,height,depth;
1556 height = (maxn[
Y_17]-minn[
Y_17]+1);
1559 for (k = 0; k < 3; k++)
1560 x_ras[k] = y_ras[k] = z_ras[k] = 0.0;
1566 sp->voxel_surf_RAS_t = make_voxel_ras_trans(r0,x_ras,y_ras,z_ras,
voxel_size);
1567 if (!sp->voxel_surf_RAS_t || sp->voxel_surf_RAS_t->isEmpty())
1570 sp->vol_dims[0] = width;
1571 sp->vol_dims[1] = height;
1572 sp->vol_dims[2] = depth;
1576 return sp.release();
1593 float mindist,
dist,diff[3];
1595 int omit,omit_outside;
1597 int nspace =
static_cast<int>(spaces.size());
1600 printf(
"Source spaces are in head coordinates and no coordinate transform was provided!");
1606 printf(
"Source spaces are in ");
1608 printf(
"head coordinates.\n");
1610 printf(
"MRI coordinates.\n");
1612 printf(
"unknown (%d) coordinates.\n",spaces[0]->
coord_frame);
1613 printf(
"Checking that the sources are inside the bounding surface ");
1615 printf(
"and at least %6.1f mm away",1000*limit);
1616 printf(
" (will take a few...)\n");
1619 for (k = 0; k < nspace; k++) {
1620 s = spaces[k].get();
1621 for (p1 = 0; p1 < s->
np; p1++)
1629 tot_angle = surf.
sum_solids(Eigen::Map<const Eigen::Vector3f>(r1))/(4*
M_PI);
1630 if (std::fabs(tot_angle-1.0) > 1e-5) {
1635 *filtered << qSetFieldWidth(10) << qSetRealNumberPrecision(3) << Qt::fixed
1636 << 1000*r1[
X_17] <<
" " << 1000*r1[
Y_17] <<
" " << 1000*r1[
Z_17] <<
"\n" << qSetFieldWidth(0);
1638 else if (limit > 0.0) {
1644 for (p2 = 0; p2 < surf.
np; p2++) {
1647 if (
dist < mindist) {
1652 if (mindist < limit) {
1657 *filtered << qSetFieldWidth(10) << qSetRealNumberPrecision(3) << Qt::fixed
1658 << 1000*r1[
X_17] <<
" " << 1000*r1[
Y_17] <<
" " << 1000*r1[
Z_17] <<
"\n" << qSetFieldWidth(0);
1664 if (omit_outside > 0)
1665 printf(
"%d source space points omitted because they are outside the inner skull surface.\n",
1668 printf(
"%d source space points omitted because of the %6.1f-mm distance limit.\n",
1670 printf(
"Thank you for waiting.\n");
1681 int omit,omit_outside;
1683 float mindist,
dist,diff[3];
1686 QSharedPointer<MNESurface> surf = a->
surf.toStrongRef();
1695 for (p1 = 0; p1 < a->
s->
np; p1++) {
1705 tot_angle = surf->sum_solids(Eigen::Map<const Eigen::Vector3f>(r1))/(4*
M_PI);
1706 if (std::fabs(tot_angle-1.0) > 1e-5) {
1711 *a->
filtered << qSetFieldWidth(10) << qSetRealNumberPrecision(3) << Qt::fixed
1712 << 1000*r1[
X_17] <<
" " << 1000*r1[
Y_17] <<
" " << 1000*r1[
Z_17] <<
"\n" << qSetFieldWidth(0);
1714 else if (a->
limit > 0.0) {
1720 for (p2 = 0; p2 < surf->np; p2++) {
1723 if (
dist < mindist) {
1728 if (mindist < a->limit) {
1733 *a->
filtered << qSetFieldWidth(10) << qSetRealNumberPrecision(3) << Qt::fixed
1734 << 1000*r1[
X_17] <<
" " << 1000*r1[
Y_17] <<
" " << 1000*r1[
Z_17] <<
"\n" << qSetFieldWidth(0);
1740 if (omit_outside > 0)
1741 printf(
"%d source space points omitted because they are outside the inner skull surface.\n",
1744 printf(
"%d source space points omitted because of the %6.1f-mm distance limit.\n",
1745 omit,1000*a->
limit);
1757 QSharedPointer<MNESurface> surf;
1759 int nproc = QThread::idealThreadCount();
1761 int nspace =
static_cast<int>(spaces.size());
1763 if (bemfile.isEmpty())
1769 qCritical(
"BEM model does not have the inner skull triangulation!");
1772 surf.reset(rawSurf);
1777 printf(
"Source spaces are in ");
1779 printf(
"head coordinates.\n");
1781 printf(
"MRI coordinates.\n");
1783 printf(
"unknown (%d) coordinates.\n",spaces[0]->
coord_frame);
1784 printf(
"Checking that the sources are inside the inner skull ");
1786 printf(
"and at least %6.1f mm away",1000*limit);
1787 printf(
" (will take a few...)\n");
1788 if (nproc < 2 || nspace == 1 || !use_threads) {
1792 for (k = 0; k < nspace; k++) {
1794 a->
s = spaces[k].get();
1795 a->
mri_head_t = std::make_unique<FiffCoordTrans>(mri_head_t);
1802 spaces[k]->rearrange_source_space();
1809 QList<FilterThreadArg*> args;
1811 for (k = 0; k < nspace; k++) {
1813 a->
s = spaces[k].get();
1814 a->
mri_head_t = std::make_unique<FiffCoordTrans>(mri_head_t);
1825 for (k = 0; k < nspace; k++) {
1826 spaces[k]->rearrange_source_space();
1831 printf(
"Thank you for waiting.\n\n");
1846 std::vector<std::unique_ptr<MNESourceSpace>> local_spaces;
1847 std::unique_ptr<MNESourceSpace> new_space;
1848 QList<FiffDirNode::SPtr> sources;
1854 float *nearest_dist = NULL;
1855 int *nneighbors = NULL;
1856 int *neighbors = NULL;
1863 if (sources.size() == 0) {
1864 printf(
"No source spaces available here");
1867 for (j = 0; j < sources.size(); j++) {
1876 new_space->np = *t_pTag->toInt();
1877 if (new_space->np == 0) {
1878 printf(
"No points in this source space");
1884 MatrixXf tmp_rr = t_pTag->toFloatMatrix().transpose();
1885 new_space->rr = tmp_rr;
1889 MatrixXf tmp_nn = t_pTag->toFloatMatrix().transpose();
1890 new_space->nn = tmp_nn;
1895 new_space->coord_frame = *t_pTag->toInt();
1898 new_space->id = *t_pTag->toInt();
1901 new_space->subject = (
char *)t_pTag->data();
1904 new_space->type = *t_pTag->toInt();
1908 ntri = *t_pTag->toInt();
1911 ntri = *t_pTag->toInt();
1921 MatrixXi tmp_itris = t_pTag->toIntMatrix().transpose();
1922 tmp_itris.array() -= 1;
1923 new_space->itris = tmp_itris;
1924 new_space->ntri =
ntri;
1931 new_space->nuse = new_space->np;
1932 new_space->inuse = Eigen::VectorXi::Ones(new_space->nuse);
1933 new_space->vertno = Eigen::VectorXi::LinSpaced(new_space->nuse, 0, new_space->nuse - 1);
1940 new_space->nuse = 0;
1941 new_space->inuse = Eigen::VectorXi::Zero(new_space->np);
1942 new_space->vertno.resize(0);
1946 new_space->nuse = *t_pTag->toInt();
1951 qDebug() <<
"ToDo: Check whether new_space->inuse contains the right stuff!!! - use VectorXi instead";
1952 new_space->inuse = Eigen::VectorXi::Zero(new_space->np);
1953 if (new_space->nuse > 0) {
1954 new_space->vertno = Eigen::VectorXi::Zero(new_space->nuse);
1955 for (k = 0, p = 0; k < new_space->np; k++) {
1956 new_space->inuse[k] = t_pTag->toInt()[k];
1957 if (new_space->inuse[k])
1958 new_space->vertno[p++] = k;
1962 new_space->vertno.resize(0);
1969 ntri = *t_pTag->toInt();
1977 MatrixXi tmp_itris = t_pTag->toIntMatrix().transpose();
1978 tmp_itris.array() -= 1;
1979 new_space->use_itris = tmp_itris;
1980 new_space->nuse_tri =
ntri;
1987 new_space->nearest.resize(new_space->np);
1988 for (k = 0; k < new_space->np; k++) {
1989 new_space->nearest[k].vert = k;
1990 new_space->nearest[k].nearest =
nearest[k];
1991 new_space->nearest[k].patch =
nullptr;
1997 qDebug() <<
"ToDo: Check whether nearest_dist contains the right stuff!!! - use VectorXf instead";
1998 nearest_dist = t_pTag->toFloat();
1999 for (k = 0; k < new_space->np; k++) {
2000 new_space->nearest[k].dist = nearest_dist[k];
2009 new_space->dist_limit = *t_pTag->toFloat();
2016 auto dist_full = dist_lower->mne_add_upper_triangle_rcs();
2020 new_space->dist = std::move(*dist_full);
2023 new_space->dist_limit = 0.0;
2030 int ntot,nvert,ntot_count,nneigh;
2033 nneighbors = neighbors = NULL;
2036 qDebug() <<
"ToDo: Check whether neighbors contains the right stuff!!! - use VectorXi instead";
2037 neighbors = t_pTag->toInt();
2041 qDebug() <<
"ToDo: Check whether nneighbors contains the right stuff!!! - use VectorXi instead";
2042 nneighbors = t_pTag->toInt();
2045 if (neighbors && nneighbors) {
2046 if (nvert != new_space->np) {
2047 printf(
"Inconsistent neighborhood data in file.");
2050 for (k = 0, ntot_count = 0; k < nvert; k++)
2051 ntot_count += nneighbors[k];
2052 if (ntot_count != ntot) {
2053 printf(
"Inconsistent neighborhood data in file.");
2056 new_space->nneighbor_vert = Eigen::VectorXi::Zero(nvert);
2057 new_space->neighbor_vert.resize(nvert);
2058 for (k = 0, q = 0; k < nvert; k++) {
2059 new_space->nneighbor_vert[k] = nneigh = nneighbors[k];
2060 new_space->neighbor_vert[k] = Eigen::VectorXi(nneigh);
2061 for (p = 0; p < nneigh; p++,q++)
2062 new_space->neighbor_vert[k][p] = neighbors[q];
2067 nneighbors = neighbors = NULL;
2073 qDebug() <<
"ToDo: Check whether vol_dims contains the right stuff!!! - use VectorXi instead";
2081 if (mris.size() == 0) {
2084 qDebug() <<
"ToDo: Check whether new_space->MRI_volume contains the right stuff!!! - use QString instead";
2085 new_space->MRI_volume = (
char *)t_pTag->data();
2093 new_space->MRI_volume = (
char *)t_pTag->data();
2102 new_space->MRI_vol_dims[0] = *t_pTag->toInt();
2105 new_space->MRI_vol_dims[1] = *t_pTag->toInt();
2108 new_space->MRI_vol_dims[2] = *t_pTag->toInt();
2113 new_space->add_triangle_data();
2114 local_spaces.push_back(std::move(new_space));
2118 spaces = std::move(local_spaces);
2144 int nspace =
static_cast<int>(spaces.size());
2146 for (k = 0; k < nspace; k++) {
2147 s = spaces[k].get();
2161 printf(
"Could not transform a source space because of transformation incompatibility.");
2166 printf(
"Could not transform a source space because of missing coordinate transformation.");
2176#define LH_LABEL_TAG "-lh.label"
2177#define RH_LABEL_TAG "-rh.label"
2187 Eigen::VectorXi lh_inuse;
2188 Eigen::VectorXi rh_inuse;
2189 Eigen::VectorXi sel;
2190 Eigen::VectorXi *
inuse =
nullptr;
2192 int nspace =
static_cast<int>(spaces.size());
2197 for (k = 0; k < nspace; k++) {
2199 lh = spaces[k].get();
2200 lh_inuse = Eigen::VectorXi::Zero(lh->
np);
2203 rh = spaces[k].get();
2204 rh_inuse = Eigen::VectorXi::Zero(rh->
np);
2210 for (k = 0; k < nlabel; k++) {
2223 printf(
"\tWarning: cannot assign label file %s to a hemisphere.\n",labels[k].toUtf8().constData());
2229 for (p = 0; p < sel.size(); p++) {
2230 if (sel[p] >= 0 && sel[p] < sp->
np)
2231 (*inuse)[sel[p]] = sp->
inuse[sel[p]];
2233 printf(
"vertex number out of range in %s (%d vs %d)\n",
2234 labels[k].toUtf8().constData(),sel[p],sp->
np);
2236 printf(
"Processed label file %s\n",labels[k].toUtf8().constData());
2263 QFile inFile(label);
2264 if (!inFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
2265 qCritical() << label;
2270 qCritical(
"Label file does not start correctly.");
2276 while (inFile.getChar(&c) && c !=
'\n')
2279 QTextStream in(&inFile);
2281 if (in.status() != QTextStream::Ok) {
2282 qCritical(
"Could not read the number of labelled points.");
2286 for (k = 0; k < nlabel; k++) {
2287 in >> p >> fdum >> fdum >> fdum >> fdum;
2288 if (in.status() != QTextStream::Ok) {
2289 qCritical(
"Could not read label point # %d",k+1);
FiffTag class declaration, which provides fiff tag I/O and processing methods.
#define FIFFV_MNE_SURF_RIGHT_HEMI
#define FIFF_MNE_SOURCE_SPACE_ID
#define FIFF_MNE_SOURCE_SPACE_DIST_LIMIT
#define FIFF_MNE_SOURCE_SPACE_VOXEL_DIMS
#define FIFF_MNE_COORD_FRAME
#define FIFF_MNE_SOURCE_SPACE_TYPE
#define FIFFV_MNE_SURF_UNKNOWN
#define FIFF_MNE_SOURCE_SPACE_SELECTION
#define FIFFV_MNE_SURF_LEFT_HEMI
#define FIFF_MNE_SOURCE_SPACE_USE_TRIANGLES
#define FIFF_MNE_SOURCE_SPACE_NUSE_TRI
#define FIFF_MNE_SOURCE_SPACE_INTERPOLATOR
#define FIFF_MNE_SOURCE_SPACE_NORMALS
#define FIFFV_MNE_COORD_MRI_VOXEL
#define FIFF_MNE_SOURCE_SPACE_NEAREST_DIST
#define FIFF_MNE_SOURCE_SPACE_DIST
#define FIFF_MNE_SOURCE_SPACE_POINTS
#define FIFFV_MNE_SPACE_SURFACE
#define FIFF_MNE_SOURCE_SPACE_NTRI
#define FIFF_MNE_SOURCE_SPACE_MRI_FILE
#define FIFFB_MNE_SOURCE_SPACE
#define FIFF_MNE_SOURCE_SPACE_NPOINTS
#define FIFFV_MNE_SPACE_VOLUME
#define FIFF_MNE_SOURCE_SPACE_TRIANGLES
#define FIFF_MNE_SOURCE_SPACE_NUSE
#define FIFFV_MNE_COORD_RAS
#define FIFF_MNE_FILE_NAME
#define FIFF_MNE_SOURCE_SPACE_NEAREST
#define FIFFB_MNE_PARENT_MRI_FILE
FiffStream class declaration.
#define FIFF_BEM_SURF_TRIANGLES
#define FIFF_BEM_SURF_NTRI
#define FIFFV_BEM_SURF_ID_BRAIN
FiffSparseMatrix class declaration.
FiffCoordTrans class declaration.
IOUtils class declaration.
MNEMghTagGroup class declaration.
Filter Thread Argument (FilterThreadArg) class declaration.
MNE Patch Information (MNEPatchInfo) class declaration.
#define MNE_SOURCE_SPACE_VOLUME
MNESurface class declaration.
#define VEC_COPY_17(to, from)
#define VEC_DIFF_17(from, to, diff)
MNENearest class declaration.
MNESourceSpace class declaration.
#define TAG_OLD_USEREALRAS
#define TAG_OLD_MGH_XFORM
#define ALLOC_ICMATRIX_17(x, y)
#define TAG_OLD_COLORTABLE
#define CURVATURE_FILE_MAGIC_NUMBER
#define FREE_CMATRIX_17(m)
float ** mne_cmatrix_51(int nr, int nc)
#define FREE_ICMATRIX_17(m)
#define ALLOC_CMATRIX_17(x, y)
#define QUAD_FILE_MAGIC_NUMBER
#define NEW_QUAD_FILE_MAGIC_NUMBER
#define FIFFV_MNE_COORD_SURFACE_RAS
#define FIFF_MNE_SOURCE_SPACE_NEIGHBORS
#define FIFF_MNE_SOURCE_SPACE_NNEIGHBORS
#define TAG_OLD_SURF_GEOM
#define TRIANGLE_FILE_MAGIC_NUMBER
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
Coordinate transformation description.
static FiffCoordTrans readTransformFromNode(FiffStream::SPtr &stream, const FiffDirNode::SPtr &node, int from, int to)
FiffCoordTrans inverted() const
Eigen::MatrixX3f apply_inverse_trans(const Eigen::MatrixX3f &rr, bool do_move=true) const
Eigen::MatrixX3f apply_trans(const Eigen::MatrixX3f &rr, bool do_move=true) const
QSharedPointer< FiffDirNode > SPtr
FIFF sparse matrix storage.
static FiffSparseMatrix::UPtr fiff_get_float_sparse_matrix(FIFFLIB::FiffTag::SPtr &tag)
QSharedPointer< FiffStream > SPtr
QSharedPointer< FiffTag > SPtr
Thread-local arguments for parallel raw data filtering (channel range, filter kernel,...
QWeakPointer< MNESurface > surf
std::unique_ptr< FIFFLIB::FiffCoordTrans > mri_head_t
Single tag entry in a FreeSurfer MGH/MGZ file header.
Collection of MNEMghTag entries from a FreeSurfer MGH/MGZ file footer.
std::vector< std::unique_ptr< MNEMghTag > > tags
This is used in the patch definitions.
Patch information for a single source space point including vertex members and area.
~MNESourceSpace() override
virtual MNESourceSpace::SPtr clone() const
static std::unique_ptr< MNESourceSpace > load_surface_geom(const QString &surf_file, const QString &curv_file, int add_geometry, int check_too_many_neighbors)
static std::unique_ptr< MNESourceSpace > load_surface(const QString &surf_file, const QString &curv_file)
void rearrange_source_space()
qint32 find_source_space_hemi() const
std::shared_ptr< MNESourceSpace > SPtr
static int restrict_sources_to_labels(std::vector< std::unique_ptr< MNESourceSpace > > &spaces, const QStringList &labels, int nlabel)
static int filter_source_spaces(const MNESurface &surf, float limit, const FIFFLIB::FiffCoordTrans &mri_head_t, std::vector< std::unique_ptr< MNESourceSpace > > &spaces, QTextStream *filtered)
static int read_source_spaces(const QString &name, std::vector< std::unique_ptr< MNESourceSpace > > &spaces)
static std::unique_ptr< MNESourceSpace > create_source_space(int np)
static void filter_source_space(FilterThreadArg *arg)
static MNESourceSpace * make_volume_source_space(const MNESurface &surf, float grid, float exclude, float mindist)
int transform_source_space(const FIFFLIB::FiffCoordTrans &t)
static int read_label(const QString &label, Eigen::VectorXi &sel)
static int transform_source_spaces_to(int coord_frame, const FIFFLIB::FiffCoordTrans &t, std::vector< std::unique_ptr< MNESourceSpace > > &spaces)
void update_inuse(Eigen::VectorXi new_inuse)
void enable_all_sources()
double sum_solids(const Eigen::Vector3f &from) const
static MNESurface * read_bem_surface(const QString &name, int which, int add_geometry, float *sigmap)
std::vector< Eigen::VectorXi > neighbor_tri
int add_geometry_info(int do_normals, int check_too_many_neighbors)
std::vector< Eigen::VectorXi > neighbor_vert
std::optional< FIFFLIB::FiffCoordTrans > MRI_surf_RAS_RAS_t
FIFFLIB::FiffSparseMatrix dist
std::vector< MNENearest > nearest
std::optional< FIFFLIB::FiffSparseMatrix > interpolator
Eigen::Matrix< int, Eigen::Dynamic, 3, Eigen::RowMajor > TrianglesT
std::optional< MNEVolGeom > vol_geom
std::vector< std::optional< MNEPatchInfo > > patches
std::optional< FIFFLIB::FiffCoordTrans > MRI_voxel_surf_RAS_t
std::vector< MNETriangle > tris
std::optional< MNEMghTagGroup > mgh_tags
std::optional< FIFFLIB::FiffCoordTrans > voxel_surf_RAS_t
Eigen::Matrix< float, Eigen::Dynamic, 3, Eigen::RowMajor > PointsT
MRI data volume geometry information like FreeSurfer keeps it.
static qint32 swap_int(qint32 source)
static qint64 swap_long(qint64 source)
static float swap_float(float source)
static qint16 swap_short(qint16 source)