42#include <QtConcurrent>
48#define _USE_MATH_DEFINES
90int read_int3(QFile &in,
int &ival)
97 if (in.read(
reinterpret_cast<char*
>(&s), 3) != 3) {
98 qCritical(
"read_int3 could not read data");
102 ival = ((s >> 8) & 0xffffff);
106int read_int(QFile &in, qint32 &ival)
112 if (in.read(
reinterpret_cast<char*
>(&s),
sizeof(qint32)) !=
static_cast<qint64
>(
sizeof(qint32))) {
113 qCritical(
"read_int could not read data");
120int read_int2(QFile &in,
int &ival)
126 if (in.read(
reinterpret_cast<char*
>(&s),
sizeof(
short)) !=
static_cast<qint64
>(
sizeof(
short))) {
127 qCritical(
"read_int2 could not read data");
134int read_float(QFile &in,
float &fval)
140 if (in.read(
reinterpret_cast<char*
>(&f),
sizeof(
float)) !=
static_cast<qint64
>(
sizeof(
float))) {
141 qCritical(
"read_float could not read data");
148int read_long(QFile &in,
long long &lval)
154 if (in.read(
reinterpret_cast<char*
>(&s),
sizeof(
long long)) !=
static_cast<qint64
>(
sizeof(
long long))) {
155 qCritical(
"read_long could not read data");
166int check_vertex(
int no,
int maxno)
168 if (no < 0 || no > maxno-1) {
169 qCritical(
"Illegal vertex number %d (max %d).",no,maxno);
187std::unique_ptr<MNEVolGeom> read_vol_geom(QFile &fp)
199 auto vg = std::make_unique<MNEVolGeom>();
201 while (!fp.atEnd() && counter < 8)
203 QByteArray lineData = fp.readLine(256);
204 if (lineData.isEmpty())
206 const char *line = lineData.constData();
207 if (strlen(line) == 0)
209 sscanf(line,
"%s %s %*s", param, eq);
210 if (!strcmp(param,
"valid")) {
211 sscanf(line,
"%s %s %d", param, eq, &vg->valid);
215 else if (!strcmp(param,
"filename")) {
216 if (sscanf(line,
"%s %s %s", param, eq, buf) >= 3)
217 vg->filename = QString::fromUtf8(buf);
220 else if (!strcmp(param,
"volume")) {
221 sscanf(line,
"%s %s %d %d %d",
222 param, eq, &vg->width, &vg->height, &vg->depth);
225 else if (!strcmp(param,
"voxelsize")) {
226 sscanf(line,
"%s %s %f %f %f",
227 param, eq, &vg->xsize, &vg->ysize, &vg->zsize);
231 vg->xsize = vg->xsize/1000.0;
232 vg->ysize = vg->ysize/1000.0;
233 vg->zsize = vg->zsize/1000.0;
236 else if (!strcmp(param,
"xras")) {
237 sscanf(line,
"%s %s %f %f %f",
238 param, eq, vg->x_ras, vg->x_ras+1, vg->x_ras+2);
241 else if (!strcmp(param,
"yras")) {
242 sscanf(line,
"%s %s %f %f %f",
243 param, eq, vg->y_ras, vg->y_ras+1, vg->y_ras+2);
246 else if (!strcmp(param,
"zras")) {
247 sscanf(line,
"%s %s %f %f %f",
248 param, eq, vg->z_ras, vg->z_ras+1, vg->z_ras+2);
251 else if (!strcmp(param,
"cras")) {
252 sscanf(line,
"%s %s %f %f %f",
253 param, eq, vg->c_ras, vg->c_ras+1, vg->c_ras+2);
254 vg->c_ras[0] = vg->c_ras[0]/1000.0;
255 vg->c_ras[1] = vg->c_ras[1]/1000.0;
256 vg->c_ras[2] = vg->c_ras[2]/1000.0;
268 vg = std::make_unique<MNEVolGeom>();
277int read_tag_data(QFile &fp,
int tag,
long long nbytes,
unsigned char *&val,
long long &nbytesp)
282 size_t snbytes = nbytes;
286 auto dum = std::make_unique<unsigned char[]>(nbytes+1);
287 if (fp.read(
reinterpret_cast<char*
>(dum.get()), nbytes) !=
static_cast<qint64
>(snbytes)) {
288 qCritical(
"Failed to read %d bytes of tag data",
static_cast<int>(nbytes));
297 auto g = read_vol_geom(fp);
309 int width, height, depth;
310 float xsize, ysize, zsize;
311 float x_ras[3], y_ras[3], z_ras[3];
314 QByteArray fn = g->
filename.toUtf8();
315 size_t totalSize =
sizeof(VolGeomPOD) + fn.size() + 1;
316 auto buf = std::make_unique<unsigned char[]>(totalSize);
318 pod.valid = g->
valid;
321 std::memcpy(pod.x_ras, g->
x_ras, 3 *
sizeof(
float));
322 std::memcpy(pod.y_ras, g->
y_ras, 3 *
sizeof(
float));
323 std::memcpy(pod.z_ras, g->
z_ras, 3 *
sizeof(
float));
324 std::memcpy(pod.c_ras, g->
c_ras, 3 *
sizeof(
float));
325 std::memcpy(buf.get(), &pod,
sizeof(VolGeomPOD));
326 std::memcpy(buf.get() +
sizeof(VolGeomPOD), fn.constData(), fn.size() + 1);
328 nbytesp =
static_cast<long long>(totalSize);
331 auto vi = std::make_unique<int[]>(1);
332 if (read_int(fp, vi[0]) ==
FAIL)
334 val =
reinterpret_cast<unsigned char *
>(vi.release());
335 nbytesp =
sizeof(int);
338 qWarning(
"Encountered an unknown tag with no length specification : %d\n",tag);
350void add_mgh_tag_to_group(std::optional<MNEMghTagGroup>& g,
int tag,
long long len,
unsigned char *data)
354 auto new_tag = std::make_unique<MNEMghTag>();
357 new_tag->data = QByteArray(
reinterpret_cast<const char*
>(data),
static_cast<int>(len));
359 g->tags.push_back(std::move(new_tag));
366int read_next_tag(QFile &fp,
int &tagp,
long long &lenp,
unsigned char *&datap)
374 if (read_int(fp,tag) ==
FAIL) {
384 if (read_int(fp,ilen) ==
FAIL)
394 if (read_long(fp,len) ==
FAIL)
400 if (read_tag_data(fp,tag,len,datap,lenp) ==
FAIL)
409int read_mgh_tags(QFile &fp, std::optional<MNEMghTagGroup>& tagsp)
416 unsigned char *tag_data;
419 if (read_next_tag(fp,tag,len,tag_data) ==
FAIL)
423 add_mgh_tag_to_group(tagsp,tag,len,tag_data);
432int read_curvature_file(
const QString& fname,
433 Eigen::VectorXf& curv)
439 float curvmin,curvmax;
441 int nface,val_pervert;
445 if (!fp.open(QIODevice::ReadOnly)) {
446 qCritical() << fname;
447 curv.resize(0);
return FAIL;
449 if (read_int3(fp,magic) != 0) {
450 qCritical() <<
"Bad magic in" << fname;
451 curv.resize(0);
return FAIL;
457 if (read_int(fp,ncurv) != 0) {
458 curv.resize(0);
return FAIL;
460 if (read_int(fp,nface) != 0) {
461 curv.resize(0);
return FAIL;
464 qInfo(
"nvert = %d nface = %d\n",ncurv,nface);
466 if (read_int(fp,val_pervert) != 0) {
467 curv.resize(0);
return FAIL;
469 if (val_pervert != 1) {
470 qCritical(
"Values per vertex not equal to one.");
471 curv.resize(0);
return FAIL;
477 curvmin = curvmax = 0.0;
478 for (k = 0; k < ncurv; k++) {
479 if (read_float(fp,fval) != 0) {
480 curv.resize(0);
return FAIL;
483 if (curv[k] > curvmax)
485 if (curv[k] < curvmin)
494 if (read_int3(fp,nface) != 0) {
495 curv.resize(0);
return FAIL;
498 qInfo(
"nvert = %d nface = %d\n",ncurv,nface);
504 curvmin = curvmax = 0.0;
505 for (k = 0; k < ncurv; k++) {
506 if (read_int2(fp,val) != 0) {
507 curv.resize(0);
return FAIL;
509 curv[k] =
static_cast<float>(val)/100.0;
510 if (curv[k] > curvmax)
512 if (curv[k] < curvmin)
518 qInfo(
"Curvature range: %f...%f\n",curvmin,curvmax);
527int read_triangle_file(
const QString& fname,
529 TrianglesT& triangles,
530 std::optional<MNEMghTagGroup>* tagsp)
539 qint32 nvert,ntri,nquad;
547 if (!fp.open(QIODevice::ReadOnly)) {
548 qCritical() << fname;
551 if (read_int3(fp,magic) != 0) {
552 qCritical() <<
"Bad magic in" << fname;
558 qCritical() <<
"Bad magic in" << fname;
565 qInfo(
"Triangle file : ");
566 for (fp.getChar(&c); c !=
'\n'; fp.getChar(&c)) {
568 qCritical()<<
"Bad triangle file.";
577 if (read_int(fp,nvert) != 0)
579 if (read_int(fp,ntri) != 0)
581 qInfo(
" nvert = %d ntri = %d\n",nvert,ntri);
582 vert.resize(nvert, 3);
587 for (k = 0; k < nvert; k++) {
588 if (read_float(fp,vert(k,0)) != 0)
590 if (read_float(fp,vert(k,1)) != 0)
592 if (read_float(fp,vert(k,2)) != 0)
598 for (k = 0; k < ntri; k++) {
599 if (read_int(fp,tri(k,0)) != 0)
601 if (check_vertex(tri(k,0),nvert) !=
OK)
603 if (read_int(fp,tri(k,1)) != 0)
605 if (check_vertex(tri(k,1),nvert) !=
OK)
607 if (read_int(fp,tri(k,2)) != 0)
609 if (check_vertex(tri(k,2),nvert) !=
OK)
615 if (read_int3(fp,nvert) != 0)
617 if (read_int3(fp,nquad) != 0)
619 qInfo(
"%s file : nvert = %d nquad = %d\n",
622 vert.resize(nvert, 3);
624 for (k = 0; k < nvert; k++) {
625 if (read_int2(fp,val) != 0)
627 vert(k,0) = val/100.0;
628 if (read_int2(fp,val) != 0)
630 vert(k,1) = val/100.0;
631 if (read_int2(fp,val) != 0)
633 vert(k,2) = val/100.0;
637 for (k = 0; k < nvert; k++) {
638 if (read_float(fp,vert(k,0)) != 0)
640 if (read_float(fp,vert(k,1)) != 0)
642 if (read_float(fp,vert(k,2)) != 0)
648 for (k = 0, ntri = 0; k < nquad; k++) {
649 for (p = 0; p < 4; p++) {
650 if (read_int3(fp,quad[p]) != 0)
658#define EVEN(n) ((((n) / 2) * 2) == n)
660#define WHICH_FACE_SPLIT(vno0, vno1) \
661 (1*nearbyint(sqrt(1.9*vno0) + sqrt(3.5*vno1)))
663 which = WHICH_FACE_SPLIT(quad[0], quad[1]) ;
671 tri(ntri,0) = quad[0];
672 tri(ntri,1) = quad[1];
673 tri(ntri,2) = quad[3];
676 tri(ntri,0) = quad[2];
677 tri(ntri,1) = quad[3];
678 tri(ntri,2) = quad[1];
682 tri(ntri,0) = quad[0];
683 tri(ntri,1) = quad[1];
684 tri(ntri,2) = quad[2];
687 tri(ntri,0) = quad[0];
688 tri(ntri,1) = quad[2];
689 tri(ntri,2) = quad[3];
698 std::optional<MNEMghTagGroup> tags;
699 if (read_mgh_tags(fp, tags) ==
FAIL) {
702 *tagsp = std::move(tags);
708 vertices = std::move(vert);
709 triangles = std::move(tri);
717std::optional<MNEVolGeom> get_volume_geom_from_tag(
const MNEMghTagGroup *tagsp)
724 int width, height, depth;
725 float xsize, ysize, zsize;
726 float x_ras[3], y_ras[3], z_ras[3];
730 for (
const auto &t : tagsp->
tags) {
732 if (t->len <
static_cast<long long>(
sizeof(VolGeomPOD)))
735 const unsigned char *d =
reinterpret_cast<const unsigned char *
>(t->data.constData());
737 std::memcpy(&pod, d,
sizeof(VolGeomPOD));
740 result.
valid = pod.valid;
741 result.
width = pod.width; result.
height = pod.height; result.
depth = pod.depth;
742 result.
xsize = pod.xsize; result.
ysize = pod.ysize; result.
zsize = pod.zsize;
743 std::memcpy(result.
x_ras, pod.x_ras, 3 *
sizeof(
float));
744 std::memcpy(result.
y_ras, pod.y_ras, 3 *
sizeof(
float));
745 std::memcpy(result.
z_ras, pod.z_ras, 3 *
sizeof(
float));
746 std::memcpy(result.
c_ras, pod.c_ras, 3 *
sizeof(
float));
748 if (t->len >
static_cast<long long>(
sizeof(VolGeomPOD)))
749 result.
filename = QString::fromUtf8(
750 reinterpret_cast<const char *
>(d +
sizeof(VolGeomPOD)));
768 rr = PointsT::Zero(
np, 3);
769 nn = NormalsT::Zero(
np, 3);
808 cm[0] =
cm[1] =
cm[2] = 0.0;
823 auto copy = std::make_shared<MNESourceSpace>(this->
np);
824 copy->type = this->
type;
827 copy->ntri = this->
ntri;
831 copy->nuse = this->
nuse;
832 copy->inuse = this->
inuse;
833 copy->vertno = this->
vertno;
834 copy->itris = this->
itris;
838 copy->dist = this->
dist;
850 for (k = 0; k <
np; k++)
866 for (k = 0, xave = 0.0; k <
np; k++)
878 double xave =
rr.col(0).sum();
894 inuse = std::move(new_inuse);
896 for (k = 0, nuse_count = 0; k <
np; k++)
903 for (k = 0, p = 0; k <
np; k++)
924 qCritical(
"Coordinate transformation does not match with the source space coordinate system.");
927 for (k = 0; k <
np; k++) {
932 for (k = 0; k <
ntri; k++)
945 std::vector<std::optional<MNEPatchInfo>> pinfo(
nuse);
948 qInfo(
"Computing patch statistics...\n");
954 qCritical(
"The patch information is not available.");
964 qInfo(
"\tareas, average normals, and mean deviations...");
969 for (p = 1, q = 0; p <
np; p++) {
972 qCritical(
"No vertices belong to the patch of vertex %d",nearest_data[p-1].
nearest);
978 pinfo[q]->vert = nearest_data[p-1].
nearest;
979 this_patch = nearest_data+p-nave;
980 pinfo[q]->memb_vert.resize(nave);
981 for (k = 0; k < nave; k++) {
982 pinfo[q]->memb_vert[k] = this_patch[k].
vert;
983 this_patch[k].
patch = &(*pinfo[q]);
985 pinfo[q]->calculate_area(
this);
986 pinfo[q]->calculate_normal_stats(
this);
994 qCritical(
"No vertices belong to the patch of vertex %d",nearest_data[p-1].
nearest);
999 pinfo[q]->vert = nearest_data[p-1].
nearest;
1000 this_patch = nearest_data+p-nave;
1001 pinfo[q]->memb_vert.resize(nave);
1002 for (k = 0; k < nave; k++) {
1003 pinfo[q]->memb_vert[k] = this_patch[k].
vert;
1004 this_patch[k].
patch = &(*pinfo[q]);
1006 pinfo[q]->calculate_area(
this);
1007 pinfo[q]->calculate_normal_stats(
this);
1010 qInfo(
" %d/%d [done]\n",q,
nuse);
1023 for (k = 0,
nuse = 0; k <
np; k++)
1032 for (k = 0, p = 0; k <
np; k++)
1048 auto res = std::make_unique<MNESourceSpace>();
1051 res->rr = PointsT::Zero(
np, 3);
1052 res->nn = NormalsT::Zero(
np, 3);
1053 res->inuse = VectorXi::Zero(
np);
1054 res->vertno = VectorXi::Zero(
np);
1058 res->tot_area = 0.0;
1065 res->subject.clear();
1069 res->dist_limit = -1.0;
1071 res->voxel_surf_RAS_t.reset();
1072 res->vol_dims[0] = res->vol_dims[1] = res->vol_dims[2] = 0;
1074 res->MRI_volume.clear();
1075 res->MRI_surf_RAS_RAS_t.reset();
1076 res->MRI_voxel_surf_RAS_t.reset();
1077 res->MRI_vol_dims[0] = res->MRI_vol_dims[1] = res->MRI_vol_dims[2] = 0;
1078 res->interpolator.reset();
1080 res->vol_geom.reset();
1081 res->mgh_tags.reset();
1083 res->cm[0] = res->cm[1] = res->cm[2] = 0.0;
1091 const QString& curv_file)
1099 const QString& curv_file,
1101 bool check_too_many_neighbors)
1107 std::unique_ptr<MNESourceSpace> s;
1108 std::optional<MNEMghTagGroup> tags;
1109 Eigen::VectorXf curvs;
1113 if (read_triangle_file(surf_file,
1119 if (!curv_file.isEmpty()) {
1120 if (read_curvature_file(curv_file, curvs) == -1)
1122 if (curvs.size() != verts.rows()) {
1123 qCritical()<<
"Incorrect number of vertices in the curvature file.";
1128 s = std::make_unique<MNESourceSpace>(0);
1129 s->rr = std::move(verts);
1130 s->itris = std::move(
tris);
1131 s->ntri = s->itris.rows();
1132 s->np = s->rr.rows();
1133 if (curvs.size() > 0) {
1134 s->curv = std::move(curvs);
1136 s->val = Eigen::VectorXf::Zero(s->np);
1138 if (check_too_many_neighbors) {
1139 if (s->add_geometry_info(
true) !=
OK)
1143 if (s->add_geometry_info2(
true) !=
OK)
1147 else if (s->nn.rows() == 0) {
1148 if (s->add_vertex_normals() !=
OK)
1152 s->add_triangle_data();
1154 s->inuse = Eigen::VectorXi::Ones(s->np);
1155 s->vertno = Eigen::VectorXi::LinSpaced(s->np, 0, s->np - 1);
1156 s->mgh_tags = std::move(tags);
1157 s->vol_geom = get_volume_geom_from_tag(s->mgh_tags ? &(*s->mgh_tags) :
nullptr);
1164static std::optional<FiffCoordTrans> make_voxel_ras_trans(
const Eigen::Vector3f& r0,
1165 const Eigen::Vector3f& x_ras,
1166 const Eigen::Vector3f& y_ras,
1167 const Eigen::Vector3f& z_ras,
1168 const Eigen::Vector3f& voxel_size)
1170 Eigen::Matrix3f rot;
1171 rot.row(0) = x_ras.transpose() * voxel_size[0];
1172 rot.row(1) = y_ras.transpose() * voxel_size[1];
1173 rot.row(2) = z_ras.transpose() * voxel_size[2];
1183 Eigen::Vector3f minV, maxV,
cm;
1184 int minn[3],maxn[3];
1187 std::unique_ptr<MNESourceSpace> sp;
1195 minV = maxV = surf.
rr.row(0).transpose();
1197 for (k = 0; k < surf.
np; k++) {
1198 Eigen::Vector3f node = surf.
rr.row(k).transpose();
1200 minV = minV.cwiseMin(node);
1201 maxV = maxV.cwiseMax(node);
1203 cm /=
static_cast<float>(surf.
np);
1208 for (k = 0; k < surf.
np; k++) {
1209 dist = (surf.
rr.row(k).transpose() -
cm).norm();
1213 qInfo(
"FsSurface CM = (%6.1f %6.1f %6.1f) mm\n",
1215 qInfo(
"FsSurface fits inside a sphere with radius %6.1f mm\n",1000*maxdist);
1216 qInfo(
"FsSurface extent:\n"
1217 "\tx = %6.1f ... %6.1f mm\n"
1218 "\ty = %6.1f ... %6.1f mm\n"
1219 "\tz = %6.1f ... %6.1f mm\n",
1220 1000*minV[
X],1000*maxV[
X],
1221 1000*minV[
Y],1000*maxV[
Y],
1222 1000*minV[
Z],1000*maxV[
Z]);
1223 for (c = 0; c < 3; c++) {
1225 maxn[c] = floor(std::fabs(maxV[c])/grid)+1;
1227 maxn[c] = -floor(std::fabs(maxV[c])/grid)-1;
1229 minn[c] = floor(std::fabs(minV[c])/grid)+1;
1231 minn[c] = -floor(std::fabs(minV[c])/grid)-1;
1233 qInfo(
"Grid extent:\n"
1234 "\tx = %6.1f ... %6.1f mm\n"
1235 "\ty = %6.1f ... %6.1f mm\n"
1236 "\tz = %6.1f ... %6.1f mm\n",
1237 1000*(minn[0]*grid),1000*(maxn[0]*grid),
1238 1000*(minn[1]*grid),1000*(maxn[1]*grid),
1239 1000*(minn[2]*grid),1000*(maxn[2]*grid));
1244 for (c = 0; c < 3; c++)
1245 np =
np*(maxn[c]-minn[c]+1);
1246 nplane = (maxn[0]-minn[0]+1)*(maxn[1]-minn[1]+1);
1247 nrow = (maxn[0]-minn[0]+1);
1250 sp->nneighbor_vert = Eigen::VectorXi::Constant(sp->np,
NNEIGHBORS);
1251 sp->neighbor_vert.resize(sp->np);
1252 for (k = 0; k < sp->np; k++) {
1255 sp->nn(k,0) = sp->nn(k,1) = 0.0;
1257 sp->neighbor_vert[k] = Eigen::VectorXi::Constant(
NNEIGHBORS, -1);
1260 for (k = 0, z = minn[2]; z <= maxn[2]; z++) {
1261 for (y = minn[1]; y <= maxn[1]; y++) {
1262 for (x = minn[0]; x <= maxn[0]; x++, k++) {
1263 sp->rr(k,0) = x*grid;
1264 sp->rr(k,1) = y*grid;
1265 sp->rr(k,2) = z*grid;
1270 Eigen::VectorXi& neigh = sp->neighbor_vert[k];
1272 neigh[0] = k - nplane;
1276 neigh[2] = k + nrow;
1280 neigh[4] = k - nrow;
1282 neigh[5] = k + nplane;
1289 neigh[6] = k + 1 - nplane;
1291 neigh[7] = k + 1 + nrow - nplane;
1294 neigh[8] = k + nrow - nplane;
1297 neigh[9] = k - 1 + nrow - nplane;
1298 neigh[10] = k - 1 - nplane;
1300 neigh[11] = k - 1 - nrow - nplane;
1303 neigh[12] = k - nrow - nplane;
1305 neigh[13] = k + 1 - nrow - nplane;
1311 if (x < maxn[0] && y < maxn[1])
1312 neigh[14] = k + 1 + nrow;
1315 neigh[15] = k - 1 + nrow;
1317 neigh[16] = k - 1 - nrow;
1319 if (y > minn[1] && x < maxn[0])
1320 neigh[17] = k + 1 - nrow - nplane;
1326 neigh[18] = k + 1 + nplane;
1328 neigh[19] = k + 1 + nrow + nplane;
1331 neigh[20] = k + nrow + nplane;
1334 neigh[21] = k - 1 + nrow + nplane;
1335 neigh[22] = k - 1 + nplane;
1337 neigh[23] = k - 1 - nrow + nplane;
1340 neigh[24] = k - nrow + nplane;
1342 neigh[25] = k + 1 - nrow + nplane;
1348 qInfo(
"%d sources before omitting any.\n",sp->nuse);
1352 for (k = 0; k < sp->np; k++) {
1353 dist = (sp->rr.row(k).transpose() -
cm).norm();
1359 qInfo(
"%d sources after omitting infeasible sources.\n",sp->nuse);
1361 std::vector<std::unique_ptr<MNESourceSpace>> sp_vec;
1362 sp_vec.push_back(std::move(sp));
1366 sp = std::move(sp_vec[0]);
1368 qInfo(
"%d sources remaining after excluding the sources outside the surface and less than %6.1f mm inside.\n",sp->nuse,1000*mindist);
1372 qInfo(
"Adjusting the neighborhood info...");
1373 for (k = 0; k < sp->np; k++) {
1374 Eigen::VectorXi& neigh = sp->neighbor_vert[k];
1375 nneigh = sp->nneighbor_vert[k];
1377 for (c = 0; c < nneigh; c++)
1378 if (!sp->inuse[neigh[c]])
1382 for (c = 0; c < nneigh; c++)
1391 Eigen::Vector3f r0(minn[0]*grid, minn[1]*grid, minn[2]*grid);
1392 Eigen::Vector3f
voxel_size(grid, grid, grid);
1393 Eigen::Vector3f x_ras = Eigen::Vector3f::UnitX();
1394 Eigen::Vector3f y_ras = Eigen::Vector3f::UnitY();
1395 Eigen::Vector3f z_ras = Eigen::Vector3f::UnitZ();
1396 int width = (maxn[0]-minn[0]+1);
1397 int height = (maxn[1]-minn[1]+1);
1398 int depth = (maxn[2]-minn[2]+1);
1400 sp->voxel_surf_RAS_t = make_voxel_ras_trans(r0,x_ras,y_ras,z_ras,
voxel_size);
1401 if (!sp->voxel_surf_RAS_t || sp->voxel_surf_RAS_t->isEmpty())
1404 sp->vol_dims[0] = width;
1405 sp->vol_dims[1] = height;
1406 sp->vol_dims[2] = depth;
1407 Eigen::Map<Eigen::Vector3f>(sp->voxel_size) =
voxel_size;
1410 return sp.release();
1425 int omit,omit_outside;
1427 int nspace =
static_cast<int>(spaces.size());
1430 qCritical(
"Source spaces are in head coordinates and no coordinate transform was provided!");
1436 qInfo(
"Source spaces are in ");
1438 qInfo(
"head coordinates.\n");
1440 qInfo(
"MRI coordinates.\n");
1442 qWarning(
"unknown (%d) coordinates.\n",spaces[0]->
coord_frame);
1443 qInfo(
"Checking that the sources are inside the bounding surface ");
1445 qInfo(
"and at least %6.1f mm away",1000*limit);
1446 qInfo(
" (will take a few...)\n");
1449 for (k = 0; k < nspace; k++) {
1450 s = spaces[k].get();
1451 for (p1 = 0; p1 < s->
np; p1++)
1453 r1 = s->
rr.row(p1).transpose();
1460 if (std::fabs(tot_angle-1.0) > 1e-5) {
1465 *filtered << qSetFieldWidth(10) << qSetRealNumberPrecision(3) << Qt::fixed
1466 << 1000*r1[
X] <<
" " << 1000*r1[
Y] <<
" " << 1000*r1[
Z] <<
"\n" << qSetFieldWidth(0);
1468 else if (limit > 0.0) {
1474 for (p2 = 0; p2 < surf.
np; p2++) {
1475 dist = (surf.
rr.row(p2).transpose() - r1).norm();
1476 if (
dist < mindist) {
1481 if (mindist < limit) {
1486 *filtered << qSetFieldWidth(10) << qSetRealNumberPrecision(3) << Qt::fixed
1487 << 1000*r1[
X] <<
" " << 1000*r1[
Y] <<
" " << 1000*r1[
Z] <<
"\n" << qSetFieldWidth(0);
1493 if (omit_outside > 0)
1494 qInfo(
"%d source space points omitted because they are outside the inner skull surface.\n",
1497 qInfo(
"%d source space points omitted because of the %6.1f-mm distance limit.\n",
1499 qInfo(
"Thank you for waiting.\n");
1510 int omit,omit_outside;
1515 QSharedPointer<MNESurface> surf = a->
surf.toStrongRef();
1524 for (p1 = 0; p1 < a->
s->
np; p1++) {
1526 r1 = a->
s->
rr.row(p1).transpose();
1534 tot_angle = surf->sum_solids(r1)/(4*
M_PI);
1535 if (std::fabs(tot_angle-1.0) > 1e-5) {
1540 *a->
filtered << qSetFieldWidth(10) << qSetRealNumberPrecision(3) << Qt::fixed
1541 << 1000*r1[
X] <<
" " << 1000*r1[
Y] <<
" " << 1000*r1[
Z] <<
"\n" << qSetFieldWidth(0);
1543 else if (a->
limit > 0.0) {
1549 for (p2 = 0; p2 < surf->np; p2++) {
1550 dist = (surf->rr.row(p2).transpose() - r1).norm();
1551 if (
dist < mindist) {
1556 if (mindist < a->limit) {
1561 *a->
filtered << qSetFieldWidth(10) << qSetRealNumberPrecision(3) << Qt::fixed
1562 << 1000*r1[
X] <<
" " << 1000*r1[
Y] <<
" " << 1000*r1[
Z] <<
"\n" << qSetFieldWidth(0);
1568 if (omit_outside > 0)
1569 qInfo(
"%d source space points omitted because they are outside the inner skull surface.\n",
1572 qInfo(
"%d source space points omitted because of the %6.1f-mm distance limit.\n",
1573 omit,1000*a->
limit);
1585 QSharedPointer<MNESurface> surf;
1587 int nproc = QThread::idealThreadCount();
1588 int nspace =
static_cast<int>(spaces.size());
1590 if (bemfile.isEmpty())
1596 qCritical(
"BEM model does not have the inner skull triangulation!");
1599 surf.reset(rawSurf.release());
1604 qInfo(
"Source spaces are in ");
1606 qInfo(
"head coordinates.\n");
1608 qInfo(
"MRI coordinates.\n");
1610 qWarning(
"unknown (%d) coordinates.\n",spaces[0]->
coord_frame);
1611 qInfo(
"Checking that the sources are inside the inner skull ");
1613 qInfo(
"and at least %6.1f mm away",1000*limit);
1614 qInfo(
" (will take a few...)\n");
1615 if (nproc < 2 || nspace == 1 || !use_threads) {
1619 for (k = 0; k < nspace; k++) {
1620 auto a_ptr = std::make_unique<FilterThreadArg>();
1621 a_ptr->s = spaces[k].get();
1622 a_ptr->mri_head_t = std::make_unique<FiffCoordTrans>(mri_head_t);
1624 a_ptr->limit = limit;
1625 a_ptr->filtered = filtered;
1627 spaces[k]->rearrange_source_space();
1634 QList<FilterThreadArg*> args;
1636 std::vector<std::unique_ptr<FilterThreadArg>> arg_owners;
1637 for (k = 0; k < nspace; k++) {
1638 auto a_ptr = std::make_unique<FilterThreadArg>();
1639 a_ptr->s = spaces[k].get();
1640 a_ptr->mri_head_t = std::make_unique<FiffCoordTrans>(mri_head_t);
1642 a_ptr->limit = limit;
1643 a_ptr->filtered = filtered;
1644 args.append(a_ptr.get());
1645 arg_owners.push_back(std::move(a_ptr));
1652 for (k = 0; k < nspace; k++) {
1653 spaces[k]->rearrange_source_space();
1656 qInfo(
"Thank you for waiting.\n\n");
1671 std::vector<std::unique_ptr<MNESourceSpace>> local_spaces;
1672 std::unique_ptr<MNESourceSpace> new_space;
1673 QList<FiffDirNode::SPtr> sources;
1679 if(!stream->open()) {
1685 if (sources.size() == 0) {
1686 qCritical(
"No source spaces available here");
1690 for (j = 0; j < sources.size(); j++) {
1700 new_space->np = *t_pTag->toInt();
1701 if (new_space->np == 0) {
1702 qCritical(
"No points in this source space");
1710 MatrixXf tmp_rr = t_pTag->toFloatMatrix().transpose();
1711 new_space->rr = tmp_rr;
1716 MatrixXf tmp_nn = t_pTag->toFloatMatrix().transpose();
1717 new_space->nn = tmp_nn;
1722 new_space->coord_frame = *t_pTag->toInt();
1725 new_space->id = *t_pTag->toInt();
1728 new_space->subject = t_pTag->toString();
1731 new_space->type = *t_pTag->toInt();
1735 ntri = *t_pTag->toInt();
1738 ntri = *t_pTag->toInt();
1749 MatrixXi tmp_itris = t_pTag->toIntMatrix().transpose();
1750 tmp_itris.array() -= 1;
1751 new_space->itris = tmp_itris;
1752 new_space->ntri =
ntri;
1759 new_space->nuse = new_space->np;
1760 new_space->inuse = Eigen::VectorXi::Ones(new_space->nuse);
1761 new_space->vertno = Eigen::VectorXi::LinSpaced(new_space->nuse, 0, new_space->nuse - 1);
1768 new_space->nuse = 0;
1769 new_space->inuse = Eigen::VectorXi::Zero(new_space->np);
1770 new_space->vertno.resize(0);
1774 new_space->nuse = *t_pTag->toInt();
1781 Eigen::Map<Eigen::VectorXi> inuseMap(t_pTag->toInt(), new_space->np);
1782 new_space->inuse = inuseMap;
1784 if (new_space->nuse > 0) {
1785 new_space->vertno = Eigen::VectorXi::Zero(new_space->nuse);
1786 for (k = 0, p = 0; k < new_space->np; k++) {
1787 if (new_space->inuse[k])
1788 new_space->vertno[p++] = k;
1792 new_space->vertno.resize(0);
1799 ntri = *t_pTag->toInt();
1808 MatrixXi tmp_itris = t_pTag->toIntMatrix().transpose();
1809 tmp_itris.array() -= 1;
1810 new_space->use_itris = tmp_itris;
1811 new_space->nuse_tri =
ntri;
1817 Eigen::Map<Eigen::VectorXi> nearestMap(t_pTag->toInt(), new_space->np);
1818 new_space->nearest.resize(new_space->np);
1819 for (k = 0; k < new_space->np; k++) {
1820 new_space->nearest[k].vert = k;
1821 new_space->nearest[k].nearest = nearestMap[k];
1822 new_space->nearest[k].patch =
nullptr;
1829 Eigen::Map<const Eigen::VectorXf> nearestDistMap(t_pTag->toFloat(), new_space->np);
1830 for (k = 0; k < new_space->np; k++) {
1831 new_space->nearest[k].dist = nearestDistMap[k];
1838 new_space->dist_limit = *t_pTag->toFloat();
1846 auto dist_full = dist_lower->mne_add_upper_triangle_rcs();
1851 new_space->dist = std::move(*dist_full);
1854 new_space->dist_limit = 0.0;
1861 int ntot,nvert,ntot_count,nneigh;
1863 Eigen::VectorXi neighborsVec;
1864 Eigen::VectorXi nneighborsVec;
1867 ntot = t_pTag->size()/
sizeof(fiff_int_t);
1868 neighborsVec = Eigen::Map<Eigen::VectorXi>(t_pTag->toInt(), ntot);
1871 nvert = t_pTag->size()/
sizeof(fiff_int_t);
1872 nneighborsVec = Eigen::Map<Eigen::VectorXi>(t_pTag->toInt(), nvert);
1874 if (neighborsVec.size() > 0 && nneighborsVec.size() > 0) {
1875 if (nvert != new_space->np) {
1876 qCritical(
"Inconsistent neighborhood data in file.");
1880 for (k = 0, ntot_count = 0; k < nvert; k++)
1881 ntot_count += nneighborsVec[k];
1882 if (ntot_count != ntot) {
1883 qCritical(
"Inconsistent neighborhood data in file.");
1887 new_space->nneighbor_vert = Eigen::VectorXi::Zero(nvert);
1888 new_space->neighbor_vert.resize(nvert);
1889 for (k = 0, q = 0; k < nvert; k++) {
1890 new_space->nneighbor_vert[k] = nneigh = nneighborsVec[k];
1891 new_space->neighbor_vert[k] = Eigen::VectorXi(nneigh);
1892 for (p = 0; p < nneigh; p++,q++)
1893 new_space->neighbor_vert[k][p] = neighborsVec[q];
1901 Eigen::Map<Eigen::Vector3i> volDimsMap(t_pTag->toInt());
1902 Eigen::Map<Eigen::Vector3i>(new_space->vol_dims) = volDimsMap;
1907 if (mris.size() == 0) {
1910 new_space->MRI_volume = t_pTag->toString();
1918 new_space->MRI_volume = t_pTag->toString();
1927 new_space->MRI_vol_dims[0] = *t_pTag->toInt();
1930 new_space->MRI_vol_dims[1] = *t_pTag->toInt();
1933 new_space->MRI_vol_dims[2] = *t_pTag->toInt();
1938 new_space->add_triangle_data();
1939 local_spaces.push_back(std::move(new_space));
1943 spaces = std::move(local_spaces);
1957 int nspace =
static_cast<int>(spaces.size());
1959 for (k = 0; k < nspace; k++) {
1960 s = spaces[k].get();
1974 qCritical(
"Could not transform a source space because of transformation incompatibility.");
1979 qCritical(
"Could not transform a source space because of missing coordinate transformation.");
1989#define LH_LABEL_TAG "-lh.label"
1990#define RH_LABEL_TAG "-rh.label"
2000 Eigen::VectorXi lh_inuse;
2001 Eigen::VectorXi rh_inuse;
2002 Eigen::VectorXi sel;
2003 Eigen::VectorXi *
inuse =
nullptr;
2005 int nspace =
static_cast<int>(spaces.size());
2010 for (k = 0; k < nspace; k++) {
2012 lh = spaces[k].get();
2013 lh_inuse = Eigen::VectorXi::Zero(lh->
np);
2016 rh = spaces[k].get();
2017 rh_inuse = Eigen::VectorXi::Zero(rh->
np);
2023 for (k = 0; k < nlabel; k++) {
2036 qWarning(
"\tWarning: cannot assign label file %s to a hemisphere.\n",labels[k].toUtf8().constData());
2042 for (p = 0; p < sel.size(); p++) {
2043 if (sel[p] >= 0 && sel[p] < sp->
np)
2044 (*inuse)[sel[p]] = sp->
inuse[sel[p]];
2046 qWarning(
"vertex number out of range in %s (%d vs %d)\n",
2047 labels[k].toUtf8().constData(),sel[p],sp->
np);
2049 qInfo(
"Processed label file %s\n",labels[k].toUtf8().constData());
2070 QFile inFile(label);
2071 if (!inFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
2072 qCritical() << label;
2078 qCritical(
"FsLabel file does not start correctly.");
2085 while (inFile.getChar(&c) && c !=
'\n')
2088 QTextStream in(&inFile);
2090 if (in.status() != QTextStream::Ok) {
2091 qCritical(
"Could not read the number of labelled points.");
2096 for (k = 0; k < nlabel; k++) {
2097 in >> p >> fdum >> fdum >> fdum >> fdum;
2098 if (in.status() != QTextStream::Ok) {
2099 qCritical(
"Could not read label point # %d",k+1);
2112int MNESourceSpace::writeVolumeInfo(
FiffStream::SPtr& stream,
bool selected_only)
const
2123 Eigen::VectorXi nneighbors;
2124 Eigen::VectorXi neighbors;
2126 if (selected_only) {
2127 Eigen::VectorXi inuse_map = Eigen::VectorXi::Constant(
np, -1);
2128 for (k = 0,p = 0, ntot = 0; k <
np; k++) {
2134 nneighbors.resize(
nuse);
2135 neighbors.resize(ntot);
2136 for (k = 0, nvert = 0, ntot = 0; k <
np; k++) {
2140 nneighbors[nvert++] = nneigh;
2141 for (p = 0; p < nneigh; p++)
2142 neighbors[ntot++] = neigh[p] < 0 ? -1 : inuse_map[neigh[p]];
2147 for (k = 0, ntot = 0; k <
np; k++)
2149 nneighbors.resize(
np);
2150 neighbors.resize(ntot);
2152 for (k = 0, ntot = 0; k <
np; k++) {
2155 nneighbors[k] = nneigh;
2156 for (p = 0; p < nneigh; p++)
2157 neighbors[ntot++] = neigh[p];
2164 if (!selected_only) {
2189 qCritical(
"Cannot write the interpolator for selection yet");
2203 qCritical(
"No points in the source space being saved");
2220 if (selected_only) {
2222 qCritical(
"No vertices in use. Cannot write active-only vertices from this source space");
2226 Eigen::MatrixXf sel(
nuse, 3);
2229 for (p = 0, pp = 0; p <
np; p++) {
2231 sel.row(pp) =
rr.row(p);
2237 for (p = 0, pp = 0; p <
np; p++) {
2239 sel.row(pp) =
nn.row(p);
2257 Eigen::MatrixXi file_tris =
itris.array() + 1;
2263 Eigen::MatrixXi file_use_tris =
use_itris.array() + 1;
2268 Eigen::VectorXi nearest_v(
np);
2269 Eigen::VectorXf nearest_dist_v(
np);
2271 std::sort(
const_cast<std::vector<MNENearest>&
>(
nearest).begin(),
2272 const_cast<std::vector<MNENearest>&
>(
nearest).end(),
2274 for (p = 0; p <
np; p++) {
2275 nearest_v[p] =
nearest[p].nearest;
2276 nearest_dist_v[p] =
nearest[p].dist;
2283 if (!
dist.is_empty()) {
2284 auto m =
dist.pickLowerTriangleRcs();
2292 if (writeVolumeInfo(stream, selected_only) !=
OK)
2305static Eigen::MatrixX3f generateIcoVertices(
int grade)
2308 const float t = (1.0f + std::sqrt(5.0f)) / 2.0f;
2309 std::vector<Eigen::Vector3f> verts = {
2310 {-1, t, 0}, { 1, t, 0}, {-1, -t, 0}, { 1, -t, 0},
2311 { 0, -1, t}, { 0, 1, t}, { 0, -1, -t}, { 0, 1, -t},
2312 { t, 0, -1}, { t, 0, 1}, {-t, 0, -1}, {-t, 0, 1}
2315 for (
auto& v : verts)
2319 std::vector<std::array<int,3>> faces = {
2320 {0,11,5}, {0,5,1}, {0,1,7}, {0,7,10}, {0,10,11},
2321 {1,5,9}, {5,11,4}, {11,10,2}, {10,7,6}, {7,1,8},
2322 {3,9,4}, {3,4,2}, {3,2,6}, {3,6,8}, {3,8,9},
2323 {4,9,5}, {2,4,11}, {6,2,10}, {8,6,7}, {9,8,1}
2327 for (
int g = 0; g < grade; ++g) {
2328 std::map<std::pair<int,int>,
int> midpointCache;
2329 std::vector<std::array<int,3>> newFaces;
2331 auto getMidpoint = [&](
int i1,
int i2) ->
int {
2332 auto key = std::make_pair(std::min(i1, i2), std::max(i1, i2));
2333 auto it = midpointCache.find(key);
2334 if (it != midpointCache.end())
2336 Eigen::Vector3f mid = (verts[i1] + verts[i2]).normalized();
2337 int idx =
static_cast<int>(verts.size());
2338 verts.push_back(mid);
2339 midpointCache[key] = idx;
2343 for (
const auto& f : faces) {
2344 int a = getMidpoint(f[0], f[1]);
2345 int b = getMidpoint(f[1], f[2]);
2346 int c = getMidpoint(f[2], f[0]);
2347 newFaces.push_back({f[0], a, c});
2348 newFaces.push_back({f[1], b, a});
2349 newFaces.push_back({f[2], c, b});
2350 newFaces.push_back({a, b, c});
2355 Eigen::MatrixX3f result(
static_cast<int>(verts.size()), 3);
2356 for (
int i = 0; i < static_cast<int>(verts.size()); ++i)
2357 result.row(i) = verts[i];
2367 if (hemi.
np <= 0 || hemi.
rr.rows() == 0) {
2368 qWarning(
"MNESourceSpace::icoDownsample - Hemisphere has no vertices.");
2373 Eigen::MatrixX3f icoVerts = generateIcoVertices(icoGrade);
2376 Eigen::MatrixX3f hemiNorm(hemi.
np, 3);
2377 for (
int i = 0; i < hemi.
np; ++i) {
2378 Eigen::Vector3f v = hemi.
rr.row(i);
2379 float len = v.norm();
2381 hemiNorm.row(i) = (v / len).transpose();
2383 hemiNorm.row(i) = v.transpose();
2387 result.
inuse = Eigen::VectorXi::Zero(result.
np);
2390 for (
int i = 0; i < icoVerts.rows(); ++i) {
2391 Eigen::Vector3f icoV = icoVerts.row(i);
2392 float bestDist = std::numeric_limits<float>::max();
2394 for (
int j = 0; j < hemi.
np; ++j) {
2395 float d = (hemiNorm.row(j).transpose() - icoV).squaredNorm();
2402 result.
inuse[bestIdx] = 1;
2409 for (
int i = 0; i < result.
np; ++i) {
2410 if (result.
inuse[i])
#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
Ordered group of MNELIB::MNEMghTag entries appended to an MGH/MGZ file.
Lightweight triangulated surface (vertices, triangles, normals) used by surface-based routines.
Single-hemisphere source space (cortical surface or volume grid) loaded from FIFF.
#define MNE_SOURCE_SPACE_VOLUME
Patch information (cluster of cortex vertices around each decimated source) used by orientation prior...
Argument record passed to a background raw-data filter worker.
constexpr int CURVATURE_FILE_MAGIC_NUMBER
constexpr int TAG_USEREALRAS
constexpr int TAG_OLD_MGH_XFORM
constexpr int TAG_OLD_USEREALRAS
constexpr int TAG_OLD_COLORTABLE
Per-hemisphere cortical surface bundle with decimation, patch info and rendering buffers.
Per-source-space-vertex nearest-cortex-vertex mapping.
FIFF sparse matrix: column / row-compressed sparse storage backed by Eigen::SparseMatrix.
return FiffCoordTrans(from_frame, to_frame, R, moveVec)
Symbolic FIFF tag, block, value, unit and channel-type constants shared across FIFFLIB.
#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 FIFFV_MNE_SPACE_UNKNOWN
#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
#define FIFF_BEM_SURF_TRIANGLES
#define FIFF_BEM_SURF_NTRI
#define FIFFV_BEM_SURF_ID_BRAIN
FIFF tag: the 16-byte tag header (kind, type, size, next) plus its decoded payload.
4x4 affine FIFF coordinate transform (FIFF_COORD_TRANS) annotated with source/destination coordinate-...
FIFF binary tag-stream layer: wraps a QIODevice to read and write FIFF tags, directories,...
Endianness swap helpers for the FIFF binary tag I/O layer (FIFF is always written big-endian on disk)...
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O, in-memory data structures and high-level readers/writers.
float swap_float(float source)
qint32 swap_int(qint32 source)
qint64 swap_long(qint64 source)
qint16 swap_short(qint16 source)
Labelled 4x4 FIFF affine: source frame, destination frame, rotation, translation and cached inverse.
static FiffCoordTrans readTransformFromNode(FiffStream::SPtr &stream, const FiffDirNode::SPtr &node, int from, int to)
Eigen::MatrixX3f apply_inverse_trans(const Eigen::MatrixX3f &rr, bool do_move=true) const
FiffCoordTrans inverted() const
Eigen::MatrixX3f apply_trans(const Eigen::MatrixX3f &rr, bool do_move=true) const
QSharedPointer< FiffDirNode > SPtr
Sparse FIFF matrix: CCS or RCS storage with the value / index / pointer triple as written by FiffStre...
static FiffSparseMatrix::UPtr fiff_get_float_sparse_matrix(const FIFFLIB::FiffTag::UPtr &tag)
FIFF tag-stream reader/writer: wraps a QIODevice and exposes typed read_* / write_* methods for every...
QSharedPointer< FiffStream > SPtr
std::unique_ptr< FiffTag > UPtr
Thread-local arguments for parallel raw data filtering (channel range, filter kernel,...
QWeakPointer< MNESurface > surf
std::unique_ptr< FIFFLIB::FiffCoordTrans > mri_head_t
Hemisphere provides geometry information.
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(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)
bool is_left_hemi() const
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 std::unique_ptr< MNESourceSpace > load_surface_geom(const QString &surf_file, const QString &curv_file, bool add_geometry, bool check_too_many_neighbors)
static MNEHemisphere icoDownsample(const MNEHemisphere &hemi, int icoGrade)
static void filter_source_space(FilterThreadArg *arg)
int writeToStream(FIFFLIB::FiffStream::SPtr &stream, bool selected_only) const
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()
Lightweight triangulated surface (vertices, triangles, normals).
double sum_solids(const Eigen::Vector3f &from) const
static std::unique_ptr< MNESurface > read_bem_surface(const QString &name, int which, bool add_geometry)
std::vector< Eigen::VectorXi > neighbor_tri
std::vector< Eigen::VectorXi > neighbor_vert
std::optional< FIFFLIB::FiffCoordTrans > MRI_surf_RAS_RAS_t
int add_geometry_info(bool do_normals, bool check_too_many_neighbors)
FIFFLIB::FiffSparseMatrix dist
std::vector< MNENearest > nearest
Eigen::VectorXi nneighbor_vert
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.