12 #include <unordered_set> 13 #include <unordered_map> 19 #define LIBFS_VERSION "0.4.0" 20 #define LIBFS_VERISION_MAJOR 0 21 #define LIBFS_VERISION_MINOR 4 22 #define LIBFS_VERISION_PATCH 0 89 #define LIBFS_APPTAG "[libfs] " 93 #define LIBFS_DBG_WARNING 97 #undef LIBFS_DBG_WARNING 100 #ifdef LIBFS_DBG_CRITICAL 101 #undef LIBFS_DBG_WARNING 104 #ifdef LIBFS_DBG_ERROR 105 #undef LIBFS_DBG_WARNING 110 #ifdef LIBFS_DBG_EXCESSIVE 111 #define LIBFS_DBG_VERBOSE 114 #ifdef LIBFS_DBG_VERBOSE 115 #define LIBFS_DBG_INFO 118 #ifdef LIBFS_DBG_INFO 119 #define LIBFS_DBG_WARNING 122 #ifdef LIBFS_DBG_WARNING 123 #define LIBFS_DBG_ERROR 126 #ifdef LIBFS_DBG_ERROR 127 #define LIBFS_DBG_CRITICAL 141 tm _localtime(
const std::time_t &time)
144 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) 145 ::localtime_s(&tm_snapshot, &time);
147 ::localtime_r(&time, &tm_snapshot);
160 std::string
time_tag(std::chrono::system_clock::time_point t)
162 auto as_time_t = std::chrono::system_clock::to_time_t(t);
164 char time_buffer[64];
166 tm = _localtime(as_time_t);
167 if (std::strftime(time_buffer,
sizeof(time_buffer),
"%F %T", &tm))
169 return std::string{time_buffer};
171 throw std::runtime_error(
"Failed to get current date as string");
195 inline void log(std::string
const &message, std::string
const loglevel =
"INFO")
197 std::cout << LIBFS_APPTAG <<
"[" << loglevel <<
"] [" <<
fs::util::time_tag(std::chrono::system_clock::now()) <<
"] " << message <<
"\n";
208 inline bool ends_with(std::string
const &value, std::string
const &suffix)
210 if (suffix.size() > value.size())
212 return std::equal(suffix.rbegin(), suffix.rend(), value.rbegin());
223 inline bool ends_with(std::string
const &value, std::initializer_list<std::string> suffixes)
225 for (
auto suffix : suffixes)
227 if (ends_with(value, suffix))
247 template <
typename T>
248 std::vector<std::vector<T>> v2d(std::vector<T> values,
size_t num_cols)
250 std::vector<std::vector<T>> result;
251 for (std::size_t i = 0; i < values.size(); ++i)
253 if (i % num_cols == 0)
255 result.resize(result.size() + 1);
257 result[i / num_cols].push_back(values[i]);
272 template <
typename T>
273 std::vector<T>
vflatten(std::vector<std::vector<T>> values)
275 size_t total_size = 0;
276 for (std::size_t i = 0; i < values.size(); i++)
278 total_size += values[i].size();
281 std::vector<T> result = std::vector<T>(total_size);
283 for (std::size_t i = 0; i < values.size(); i++)
285 for (std::size_t j = 0; j < values[i].size(); j++)
287 result[cur_idx] = values[i][j];
304 inline bool starts_with(std::string
const &value, std::string
const &prefix)
306 if (prefix.length() > value.length())
308 return value.rfind(prefix, 0) == 0;
321 inline bool starts_with(std::string
const &value, std::initializer_list<std::string> prefixes)
323 for (
auto prefix : prefixes)
325 if (starts_with(value, prefix))
346 if (FILE *file = fopen(name.c_str(),
"r"))
372 std::string
fullpath(std::initializer_list<std::string> path_components, std::string path_sep = std::string(
"/"))
375 if (path_components.size() == 0)
377 throw std::invalid_argument(
"The 'path_components' must not be empty.");
381 std::string comp_mod;
383 for (
auto comp : path_components)
388 if (starts_with(comp, path_sep))
390 comp_mod = comp.substr(1, comp.size() - 1);
394 if (ends_with(comp_mod, path_sep))
396 comp_mod = comp_mod.substr(0, comp_mod.size() - 1);
400 if (idx < path_components.size() - 1)
419 void str_to_file(
const std::string &filename,
const std::string rep)
422 ofs.open(filename, std::ofstream::out);
423 #ifdef LIBFS_DBG_VERBOSE 424 std::cout << LIBFS_APPTAG <<
"Opening file '" << filename <<
"' for writing.\n";
433 throw std::runtime_error(
"Unable to open file '" + filename +
"' for writing.\n");
475 std::vector<uint8_t>
viridis(
const std::vector<float> &data,
float vmin = NAN,
float vmax = NAN, uint8_t nan_r = 255, uint8_t nan_g = 255, uint8_t nan_b = 255)
477 std::vector<uint8_t> colors;
482 colors.reserve(data.size() * 3);
486 static const float lut[768] = {
487 0.267004, 0.004874, 0.329415, 0.26851, 0.009605, 0.335427, 0.269944, 0.014625,
488 0.341379, 0.271305, 0.019942, 0.347269, 0.272594, 0.025563, 0.353093, 0.273809,
489 0.031497, 0.358853, 0.274952, 0.037752, 0.364543, 0.276022, 0.044167, 0.370164,
490 0.277018, 0.050344, 0.375715, 0.277941, 0.056324, 0.381191, 0.278791, 0.062145,
491 0.386592, 0.279566, 0.067836, 0.391917, 0.280267, 0.073417, 0.397163, 0.280894,
492 0.078907, 0.402329, 0.281446, 0.08432, 0.407414, 0.281924, 0.089666, 0.412415,
493 0.282327, 0.094955, 0.417331, 0.282656, 0.100196, 0.42216, 0.28291, 0.105393,
494 0.426902, 0.283091, 0.110553, 0.431554, 0.283197, 0.11568, 0.436115, 0.283229,
495 0.120777, 0.440584, 0.283187, 0.125848, 0.44496, 0.283072, 0.130895, 0.449241,
496 0.282884, 0.13592, 0.453427, 0.282623, 0.140926, 0.457517, 0.28229, 0.145912,
497 0.46151, 0.281887, 0.150881, 0.465405, 0.281412, 0.155834, 0.469201, 0.280868,
498 0.160771, 0.472899, 0.280255, 0.165693, 0.476498, 0.279574, 0.170599, 0.479997,
499 0.278826, 0.17549, 0.483397, 0.278012, 0.180367, 0.486697, 0.277134, 0.185228,
500 0.489898, 0.276194, 0.190074, 0.493001, 0.275191, 0.194905, 0.496005, 0.274128,
501 0.199721, 0.498911, 0.273006, 0.20452, 0.501721, 0.271828, 0.209303, 0.504434,
502 0.270595, 0.214069, 0.507052, 0.269308, 0.218818, 0.509577, 0.267968, 0.223549,
503 0.512008, 0.26658, 0.228262, 0.514349, 0.265145, 0.232956, 0.516599, 0.263663,
504 0.237631, 0.518762, 0.262138, 0.242286, 0.520837, 0.260571, 0.246922, 0.522828,
505 0.258965, 0.251537, 0.524736, 0.257322, 0.25613, 0.526563, 0.255645, 0.260703,
506 0.528312, 0.253935, 0.265254, 0.529983, 0.252194, 0.269783, 0.531579, 0.250425,
507 0.27429, 0.533103, 0.248629, 0.278775, 0.534556, 0.246811, 0.283237, 0.535941,
508 0.244972, 0.287675, 0.53726, 0.243113, 0.292092, 0.538516, 0.241237, 0.296485,
509 0.539709, 0.239346, 0.300855, 0.540844, 0.237441, 0.305202, 0.541921, 0.235526,
510 0.309527, 0.542944, 0.233603, 0.313828, 0.543914, 0.231674, 0.318106, 0.544834,
511 0.229739, 0.322361, 0.545706, 0.227802, 0.326594, 0.546532, 0.225863, 0.330805,
512 0.547314, 0.223925, 0.334994, 0.548053, 0.221989, 0.339161, 0.548752, 0.220057,
513 0.343307, 0.549413, 0.21813, 0.347432, 0.550038, 0.21621, 0.351535, 0.550627,
514 0.214298, 0.355619, 0.551184, 0.212395, 0.359683, 0.55171, 0.210503, 0.363727,
515 0.552206, 0.208623, 0.367752, 0.552675, 0.206756, 0.371758, 0.553117, 0.204903,
516 0.375746, 0.553533, 0.203063, 0.379716, 0.553925, 0.201239, 0.38367, 0.554294,
517 0.19943, 0.387607, 0.554642, 0.197636, 0.391528, 0.554969, 0.19586, 0.395433,
518 0.555276, 0.1941, 0.399323, 0.555565, 0.192357, 0.403199, 0.555836, 0.190631,
519 0.407061, 0.556089, 0.188923, 0.41091, 0.556326, 0.187231, 0.414746, 0.556547,
520 0.185556, 0.41857, 0.556753, 0.183898, 0.422383, 0.556944, 0.182256, 0.426184,
521 0.55712, 0.180629, 0.429975, 0.557282, 0.179019, 0.433756, 0.55743, 0.177423,
522 0.437527, 0.557565, 0.175841, 0.44129, 0.557685, 0.174274, 0.445044, 0.557792,
523 0.172719, 0.448791, 0.557885, 0.171176, 0.45253, 0.557965, 0.169646, 0.456262,
524 0.55803, 0.168126, 0.459988, 0.558082, 0.166617, 0.463708, 0.558119, 0.165117,
525 0.467423, 0.558141, 0.163625, 0.471133, 0.558148, 0.162142, 0.474838, 0.55814,
526 0.160665, 0.47854, 0.558115, 0.159194, 0.482237, 0.558073, 0.157729, 0.485932,
527 0.558013, 0.15627, 0.489624, 0.557936, 0.154815, 0.493313, 0.55784, 0.153364,
528 0.497, 0.557724, 0.151918, 0.500685, 0.557587, 0.150476, 0.504369, 0.55743,
529 0.149039, 0.508051, 0.55725, 0.147607, 0.511733, 0.557049, 0.14618, 0.515413,
530 0.556823, 0.144759, 0.519093, 0.556572, 0.143343, 0.522773, 0.556295, 0.141935,
531 0.526453, 0.555991, 0.140536, 0.530132, 0.555659, 0.139147, 0.533812, 0.555298,
532 0.13777, 0.537492, 0.554906, 0.136408, 0.541173, 0.554483, 0.135066, 0.544853,
533 0.554029, 0.133743, 0.548535, 0.553541, 0.132444, 0.552216, 0.553018, 0.131172,
534 0.555899, 0.552459, 0.129933, 0.559582, 0.551864, 0.128729, 0.563265, 0.551229,
535 0.127568, 0.566949, 0.550556, 0.126453, 0.570633, 0.549841, 0.125394, 0.574318,
536 0.549086, 0.124395, 0.578002, 0.548287, 0.123463, 0.581687, 0.547445, 0.122606,
537 0.585371, 0.546557, 0.121831, 0.589055, 0.545623, 0.121148, 0.592739, 0.544641,
538 0.120565, 0.596422, 0.543611, 0.120092, 0.600104, 0.54253, 0.119738, 0.603785,
539 0.5414, 0.119512, 0.607464, 0.540218, 0.119423, 0.611141, 0.538982, 0.119483,
540 0.614817, 0.537692, 0.119699, 0.61849, 0.536347, 0.120081, 0.622161, 0.534946,
541 0.120638, 0.625828, 0.533488, 0.12138, 0.629492, 0.531973, 0.122312, 0.633153,
542 0.530398, 0.123444, 0.636809, 0.528763, 0.12478, 0.640461, 0.527068, 0.126326,
543 0.644107, 0.525311, 0.128087, 0.647749, 0.523491, 0.130067, 0.651384, 0.521608,
544 0.132268, 0.655014, 0.519661, 0.134692, 0.658636, 0.517649, 0.137339, 0.662252,
545 0.515571, 0.14021, 0.665859, 0.513427, 0.143303, 0.669459, 0.511215, 0.146616,
546 0.67305, 0.508936, 0.150148, 0.676631, 0.506589, 0.153894, 0.680203, 0.504172,
547 0.157851, 0.683765, 0.501686, 0.162016, 0.687316, 0.499129, 0.166383, 0.690856,
548 0.496502, 0.170948, 0.694384, 0.493803, 0.175707, 0.6979, 0.491033, 0.180653,
549 0.701402, 0.488189, 0.185783, 0.704891, 0.485273, 0.19109, 0.708366, 0.482284,
550 0.196571, 0.711827, 0.479221, 0.202219, 0.715272, 0.476084, 0.20803, 0.718701,
551 0.472873, 0.214, 0.722114, 0.469588, 0.220124, 0.725509, 0.466226, 0.226397,
552 0.728888, 0.462789, 0.232815, 0.732247, 0.459277, 0.239374, 0.735588, 0.455688,
553 0.24607, 0.73891, 0.452024, 0.252899, 0.742211, 0.448284, 0.259857, 0.745492,
554 0.444467, 0.266941, 0.748751, 0.440573, 0.274149, 0.751988, 0.436601, 0.281477,
555 0.755203, 0.432552, 0.288921, 0.758394, 0.428426, 0.296479, 0.761561, 0.424223,
556 0.304148, 0.764704, 0.419943, 0.311925, 0.767822, 0.415586, 0.319809, 0.770914,
557 0.411152, 0.327796, 0.77398, 0.40664, 0.335885, 0.777018, 0.402049, 0.344074,
558 0.780029, 0.397381, 0.35236, 0.783011, 0.392636, 0.360741, 0.785964, 0.387814,
559 0.369214, 0.788888, 0.382914, 0.377779, 0.791781, 0.377939, 0.386433, 0.794644,
560 0.372886, 0.395174, 0.797475, 0.367757, 0.404001, 0.800275, 0.362552, 0.412913,
561 0.803041, 0.357269, 0.421908, 0.805774, 0.35191, 0.430983, 0.808473, 0.346476,
562 0.440137, 0.811138, 0.340967, 0.449368, 0.813768, 0.335384, 0.458674, 0.816363,
563 0.329727, 0.468053, 0.818921, 0.323998, 0.477504, 0.821444, 0.318195, 0.487026,
564 0.823929, 0.312321, 0.496615, 0.826376, 0.306377, 0.506271, 0.828786, 0.300362,
565 0.515992, 0.831158, 0.294279, 0.525776, 0.833491, 0.288127, 0.535621, 0.835785,
566 0.281908, 0.545524, 0.838039, 0.275626, 0.555484, 0.840254, 0.269281, 0.565498,
567 0.84243, 0.262877, 0.575563, 0.844566, 0.256415, 0.585678, 0.846661, 0.249897,
568 0.595839, 0.848717, 0.243329, 0.606045, 0.850733, 0.236712, 0.616293, 0.852709,
569 0.230052, 0.626579, 0.854645, 0.223353, 0.636902, 0.856542, 0.21662, 0.647257,
570 0.8584, 0.209861, 0.657642, 0.860219, 0.203082, 0.668054, 0.861999, 0.196293,
571 0.678489, 0.863742, 0.189503, 0.688944, 0.865448, 0.182725, 0.699415, 0.867117,
572 0.175971, 0.709898, 0.868751, 0.169257, 0.720391, 0.87035, 0.162603, 0.730889,
573 0.871916, 0.156029, 0.741388, 0.873449, 0.149561, 0.751884, 0.874951, 0.143228,
574 0.762373, 0.876424, 0.137064, 0.772852, 0.877868, 0.131109, 0.783315, 0.879285,
575 0.125405, 0.79376, 0.880678, 0.120005, 0.804182, 0.882046, 0.114965, 0.814576,
576 0.883393, 0.110347, 0.82494, 0.88472, 0.106217, 0.83527, 0.886029, 0.102646,
577 0.845561, 0.887322, 0.099702, 0.85581, 0.888601, 0.097452, 0.866013, 0.889868,
578 0.095953, 0.876168, 0.891125, 0.09525, 0.886271, 0.892374, 0.095374, 0.89632,
579 0.893616, 0.096335, 0.906311, 0.894855, 0.098125, 0.916242, 0.896091, 0.100717,
580 0.926106, 0.89733, 0.104071, 0.935904, 0.89857, 0.108131, 0.945636, 0.899815,
581 0.112838, 0.9553, 0.901065, 0.118128, 0.964894, 0.902323, 0.123941, 0.974417,
582 0.90359, 0.130215, 0.983868, 0.904867, 0.136897, 0.993248, 0.906157, 0.143936,
587 bool auto_min = std::isnan(vmin);
588 bool auto_max = std::isnan(vmax);
591 float data_min = NAN;
592 float data_max = NAN;
593 bool have_finite =
false;
594 for (
size_t i = 0; i < data.size(); i++)
596 if (std::isnan(data[i]))
608 if (data[i] < data_min)
612 if (data[i] > data_max)
619 float lo = auto_min ? data_min : vmin;
620 float hi = auto_max ? data_max : vmax;
622 if (!auto_min && !auto_max)
626 throw std::invalid_argument(
"In viridis(): 'vmin' must not be greater than 'vmax'.");
633 for (
size_t i = 0; i < data.size(); i++)
635 colors.push_back(nan_r);
636 colors.push_back(nan_g);
637 colors.push_back(nan_b);
642 bool constant = (hi <= lo);
644 for (
size_t i = 0; i < data.size(); i++)
646 if (std::isnan(data[i]))
648 colors.push_back(nan_r);
649 colors.push_back(nan_g);
650 colors.push_back(nan_b);
661 t = (data[i] - lo) / (hi - lo);
662 if (t < 0.0f) { t = 0.0f; }
663 if (t > 1.0f) { t = 1.0f; }
666 float pos = t * (n - 1);
667 int idx0 =
static_cast<int>(pos);
668 if (idx0 < 0) { idx0 = 0; }
669 if (idx0 > n - 2) { idx0 = n - 2; }
671 float frac = pos -
static_cast<float>(idx0);
673 for (
int c = 0; c < 3; c++)
675 float val = lut[idx0 * 3 + c] * (1.0f - frac) + lut[idx1 * 3 + c] * frac;
676 int iv =
static_cast<int>(val * 255.0f + 0.5f);
677 if (iv < 0) { iv = 0; }
678 if (iv > 255) { iv = 255; }
679 colors.push_back(static_cast<uint8_t>(iv));
701 int _fread3(std::istream &);
702 template <
typename T>
703 T _freadt(std::istream &);
704 std::string _freadstringnewline(std::istream &);
705 std::string _freadfixedlengthstring(std::istream &,
size_t,
bool);
706 bool _ends_with(std::string
const &fullString, std::string
const &ending);
707 size_t _vidx_2d(
size_t,
size_t,
size_t);
731 Mesh(std::vector<float> cvertices, std::vector<int32_t> cfaces)
733 vertices = cvertices;
738 Mesh(std::vector<std::vector<float>> cvertices, std::vector<std::vector<int32_t>> cfaces)
740 vertices = util::vflatten(cvertices);
741 faces = util::vflatten(cfaces);
771 mesh.
faces = {0, 2, 3,
805 mesh.
faces = {0, 2, 1,
830 static fs::Mesh construct_grid(
const size_t nx = 4,
const size_t ny = 5,
const float distx = 1.0,
const float disty = 1.0)
832 if (nx < 2 || ny < 2)
834 throw std::runtime_error(
"Parameters nx and ny must be at least 2.");
837 size_t num_vertices = nx * ny;
838 size_t num_faces = ((nx - 1) * (ny - 1)) * 2;
839 std::vector<float> vertices;
840 vertices.reserve(num_vertices * 3);
841 std::vector<int> faces;
842 faces.reserve(num_faces * 3);
845 float cur_x, cur_y, cur_z;
846 cur_x = cur_y = cur_z = 0.0;
847 for (
size_t i = 0; i < nx; i++)
849 for (
size_t j = 0; j < ny; j++)
851 vertices.push_back(cur_x);
852 vertices.push_back(cur_y);
853 vertices.push_back(cur_z);
860 for (
size_t i = 0; i < num_vertices; i++)
862 if ((i + 1) % ny == 0 || i >= num_vertices - ny)
868 faces.push_back(
int(i));
869 faces.push_back(
int(i + ny + 1));
870 faces.push_back(
int(i + 1));
872 faces.push_back(
int(i));
873 faces.push_back(
int(i + ny + 1));
874 faces.push_back(
int(i + ny));
894 std::stringstream objs;
895 for (
size_t vidx = 0; vidx < this->vertices.size(); vidx += 3)
897 objs <<
"v " << vertices[vidx] <<
" " << vertices[vidx + 1] <<
" " << vertices[vidx + 2] <<
"\n";
899 for (
size_t fidx = 0; fidx < this->faces.size(); fidx += 3)
901 objs <<
"f " << faces[fidx] + 1 <<
" " << faces[fidx + 1] + 1 <<
" " << faces[fidx + 2] + 1 <<
"\n";
919 std::vector<std::vector<bool>> adjm = std::vector<std::vector<bool>>(this->num_vertices(), std::vector<bool>(this->num_vertices(),
false));
920 for (
size_t fidx = 0; fidx < this->faces.size(); fidx += 3)
922 adjm[faces[fidx]][faces[fidx + 1]] =
true;
923 adjm[faces[fidx + 1]][faces[fidx]] =
true;
924 adjm[faces[fidx + 1]][faces[fidx + 2]] =
true;
925 adjm[faces[fidx + 2]][faces[fidx + 1]] =
true;
926 adjm[faces[fidx + 2]][faces[fidx]] =
true;
927 adjm[faces[fidx]][faces[fidx + 2]] =
true;
933 struct _tupleHashFunction
935 size_t operator()(
const std::tuple<size_t, size_t> &x)
const 937 return std::get<0>(x) ^ std::get<1>(x);
943 typedef std::unordered_set<std::tuple<size_t, size_t>, _tupleHashFunction>
edge_set;
959 for (
size_t fidx = 0; fidx < this->faces.size(); fidx += 3)
961 edges.insert(std::make_tuple(faces[fidx], faces[fidx + 1]));
962 edges.insert(std::make_tuple(faces[fidx + 1], faces[fidx]));
964 edges.insert(std::make_tuple(faces[fidx + 1], faces[fidx + 2]));
965 edges.insert(std::make_tuple(faces[fidx + 2], faces[fidx + 1]));
967 edges.insert(std::make_tuple(faces[fidx], faces[fidx + 2]));
968 edges.insert(std::make_tuple(faces[fidx + 2], faces[fidx]));
985 std::vector<std::vector<size_t>>
as_adjlist(
const bool via_matrix =
true)
const 989 return (this->_as_adjlist_via_edgeset());
991 std::vector<std::vector<bool>> adjm = this->as_adjmatrix();
992 std::vector<std::vector<size_t>> adjl = std::vector<std::vector<size_t>>(this->num_vertices(), std::vector<size_t>());
993 size_t nv = adjm.size();
994 for (
size_t i = 0; i < nv; i++)
996 for (
size_t j = i + 1; j < nv; j++)
998 if (adjm[i][j] ==
true)
1000 adjl[i].push_back(j);
1001 adjl[j].push_back(i);
1018 std::vector<std::vector<size_t>> _as_adjlist_via_edgeset()
const 1020 edge_set edges = this->as_edgelist();
1021 std::vector<std::vector<size_t>> adjl = std::vector<std::vector<size_t>>(this->num_vertices(), std::vector<size_t>());
1022 for (
const std::tuple<size_t, size_t> &e : edges)
1024 adjl[std::get<0>(e)].push_back(std::get<1>(e));
1044 std::vector<float>
smooth_pvd_nn(
const std::vector<float> pvd,
const size_t num_iter = 1,
const bool via_matrix =
true,
const bool with_nan =
true,
const bool detect_nan =
true)
const 1047 const std::vector<std::vector<size_t>> adjlist = this->as_adjlist(via_matrix);
1067 static std::vector<float>
smooth_pvd_nn(
const std::vector<std::vector<size_t>> mesh_adj,
const std::vector<float> pvd,
const size_t num_iter = 1,
const bool with_nan =
true,
const bool detect_nan =
true)
1069 assert(pvd.size() == mesh_adj.size());
1070 bool final_with_nan = with_nan;
1073 final_with_nan =
false;
1074 for (
size_t i = 0; i < pvd.size(); i++)
1076 if (std::isnan(pvd[i]))
1078 final_with_nan =
true;
1085 return fs::Mesh::_smooth_pvd_nn_nan(mesh_adj, pvd, num_iter);
1087 std::vector<float> current_pvd_source;
1088 std::vector<float> current_pvd_smoothed = std::vector<float>(pvd.size());
1092 for (
size_t i = 0; i < num_iter; i++)
1096 current_pvd_source = pvd;
1100 current_pvd_source = current_pvd_smoothed;
1102 for (
size_t v_idx = 0; v_idx < mesh_adj.size(); v_idx++)
1104 num_neigh = mesh_adj[v_idx].size();
1105 val_sum = current_pvd_source[v_idx] / (num_neigh + 1);
1106 for (
size_t neigh_rel_idx = 0; neigh_rel_idx < num_neigh; neigh_rel_idx++)
1108 val_sum += current_pvd_source[mesh_adj[v_idx][neigh_rel_idx]] / (num_neigh + 1);
1110 current_pvd_smoothed[v_idx] = val_sum;
1113 return current_pvd_smoothed;
1132 static std::vector<float> _smooth_pvd_nn_nan(
const std::vector<std::vector<size_t>> mesh_adj,
const std::vector<float> pvd,
const size_t num_iter = 1)
1134 std::vector<float> current_pvd_source;
1135 std::vector<float> current_pvd_smoothed = std::vector<float>(pvd.size());
1139 size_t num_non_nan_values;
1141 for (
size_t i = 0; i < num_iter; i++)
1146 current_pvd_source = pvd;
1150 current_pvd_source = current_pvd_smoothed;
1153 for (
size_t v_idx = 0; v_idx < mesh_adj.size(); v_idx++)
1155 if (std::isnan(current_pvd_source[v_idx]))
1157 current_pvd_smoothed[v_idx] = NAN;
1160 val_sum = current_pvd_source[v_idx];
1161 num_non_nan_values = 1;
1162 num_neigh = mesh_adj[v_idx].size();
1163 for (
size_t neigh_rel_idx = 0; neigh_rel_idx < num_neigh; neigh_rel_idx++)
1165 neigh_val = current_pvd_source[mesh_adj[v_idx][neigh_rel_idx]];
1166 if (std::isnan(neigh_val))
1172 val_sum += neigh_val;
1173 num_non_nan_values++;
1176 current_pvd_smoothed[v_idx] = val_sum / (float)num_non_nan_values;
1179 return current_pvd_smoothed;
1188 static std::vector<std::vector<size_t>>
extend_adj(
const std::vector<std::vector<size_t>> mesh_adj,
const size_t extend_by = 1, std::vector<std::vector<size_t>> mesh_adj_ext = std::vector<std::vector<size_t>>())
1190 size_t num_vertices = mesh_adj.size();
1191 if (mesh_adj_ext.size() == 0)
1193 mesh_adj_ext = mesh_adj;
1195 std::vector<size_t> neighborhood;
1196 std::vector<size_t> ext_neighborhood;
1197 for (
size_t ext_idx = 0; ext_idx < extend_by; ext_idx++)
1199 for (
size_t source_vert_idx = 0; source_vert_idx < num_vertices; source_vert_idx++)
1201 neighborhood = mesh_adj_ext[source_vert_idx];
1203 for (
size_t neigh_vert_rel_idx = 0; neigh_vert_rel_idx < neighborhood.size(); neigh_vert_rel_idx++)
1205 for (
size_t canidate_rel_idx = 0; canidate_rel_idx < mesh_adj[neighborhood[neigh_vert_rel_idx]].size(); canidate_rel_idx++)
1207 if (mesh_adj[neighborhood[neigh_vert_rel_idx]][canidate_rel_idx] != source_vert_idx)
1209 mesh_adj_ext[source_vert_idx].push_back(mesh_adj[neighborhood[neigh_vert_rel_idx]][canidate_rel_idx]);
1214 std::sort(mesh_adj_ext[source_vert_idx].begin(), mesh_adj_ext[source_vert_idx].end());
1215 mesh_adj_ext[source_vert_idx].erase(std::unique(mesh_adj_ext[source_vert_idx].begin(), mesh_adj_ext[source_vert_idx].end()), mesh_adj_ext[source_vert_idx].end());
1218 return mesh_adj_ext;
1235 fs::util::str_to_file(filename, this->to_obj());
1254 std::pair<std::unordered_map<int32_t, int32_t>,
fs::Mesh>
submesh_vertex(
const std::vector<int32_t> &old_vertex_indices,
const bool mapdir_fulltosubmesh =
false)
const 1257 std::vector<float> new_vertices;
1258 std::vector<int> new_faces;
1259 std::unordered_map<int32_t, int32_t> vertex_index_map_full2submesh;
1260 int32_t new_vertex_idx = 0;
1261 for (
size_t i = 0; i < old_vertex_indices.size(); i++)
1263 vertex_index_map_full2submesh[old_vertex_indices[i]] = new_vertex_idx;
1264 new_vertices.push_back(this->vertices[
size_t(old_vertex_indices[i]) * 3]);
1265 new_vertices.push_back(this->vertices[
size_t(old_vertex_indices[i]) * 3 + 1]);
1266 new_vertices.push_back(this->vertices[
size_t(old_vertex_indices[i]) * 3 + 2]);
1272 for (
size_t i = 0; i < this->num_faces(); i++)
1274 face_v0 = this->faces[i * 3];
1275 face_v1 = this->faces[i * 3 + 1];
1276 face_v2 = this->faces[i * 3 + 2];
1277 if ((vertex_index_map_full2submesh.find(face_v0) != vertex_index_map_full2submesh.end()) && (vertex_index_map_full2submesh.find(face_v1) != vertex_index_map_full2submesh.end()) && (vertex_index_map_full2submesh.find(face_v2) != vertex_index_map_full2submesh.end()))
1279 new_faces.push_back(vertex_index_map_full2submesh[face_v0]);
1280 new_faces.push_back(vertex_index_map_full2submesh[face_v1]);
1281 new_faces.push_back(vertex_index_map_full2submesh[face_v2]);
1285 submesh.
faces = new_faces;
1287 std::pair<std::unordered_map<int32_t, int32_t>,
fs::Mesh> result;
1288 if (!mapdir_fulltosubmesh)
1290 std::unordered_map<int32_t, int32_t> vertex_index_map_submesh2full;
1291 for (
auto const &pair : vertex_index_map_full2submesh)
1293 vertex_index_map_submesh2full[pair.second] = pair.first;
1295 result = std::pair<std::unordered_map<int32_t, int32_t>,
fs::Mesh>(vertex_index_map_submesh2full, submesh);
1299 result = std::pair<std::unordered_map<int32_t, int32_t>,
fs::Mesh>(vertex_index_map_full2submesh, submesh);
1311 static std::vector<float>
curv_data_for_orig_mesh(
const std::vector<float> data_submesh,
const std::unordered_map<int32_t, int32_t> submesh_to_orig_mapping,
const int32_t orig_mesh_num_vertices,
const float fill_value = std::numeric_limits<float>::quiet_NaN())
1314 if (submesh_to_orig_mapping.size() != data_submesh.size())
1316 throw std::domain_error(
"The number of vertices of the submesh and the number of values in the submesh_to_orig_mapping do not match: got " + std::to_string(data_submesh.size()) +
" and " + std::to_string(submesh_to_orig_mapping.size()) +
".");
1319 std::vector<float> data_orig_mesh(orig_mesh_num_vertices, fill_value);
1320 for (
size_t i = 0; i < data_submesh.size(); i++)
1322 auto got = submesh_to_orig_mapping.find(
int(i));
1323 if (got != submesh_to_orig_mapping.end())
1325 data_orig_mesh[got->second] = data_submesh[i];
1328 return (data_orig_mesh);
1350 std::vector<float> vertices;
1351 std::vector<int> faces;
1353 #ifdef LIBFS_DBG_INFO 1354 size_t num_lines_ignored = 0;
1357 while (std::getline(*is, line))
1360 std::istringstream iss(line);
1361 if (fs::util::starts_with(line,
"#"))
1367 if (fs::util::starts_with(line,
"v "))
1369 std::string elem_type_identifier;
1371 if (!(iss >> elem_type_identifier >> x >> y >> z))
1373 throw std::domain_error(
"Could not parse vertex line " + std::to_string(line_idx + 1) +
" of OBJ data, invalid format.\n");
1375 assert(elem_type_identifier ==
"v");
1376 vertices.push_back(x);
1377 vertices.push_back(y);
1378 vertices.push_back(z);
1380 else if (fs::util::starts_with(line,
"f "))
1382 std::string elem_type_identifier, v0raw, v1raw, v2raw;
1384 if (!(iss >> elem_type_identifier >> v0raw >> v1raw >> v2raw))
1386 throw std::domain_error(
"Could not parse face line " + std::to_string(line_idx + 1) +
" of OBJ data, invalid format.\n");
1388 assert(elem_type_identifier ==
"f");
1393 std::size_t found_v0 = v0raw.find(
"/");
1394 std::size_t found_v1 = v1raw.find(
"/");
1395 std::size_t found_v2 = v2raw.find(
"/");
1396 if (found_v0 != std::string::npos)
1398 v0raw = v0raw.substr(0, found_v0);
1400 if (found_v1 != std::string::npos)
1402 v1raw = v1raw.substr(0, found_v1);
1404 if (found_v2 != std::string::npos)
1406 v2raw = v0raw.substr(0, found_v2);
1408 v0 = std::stoi(v0raw);
1409 v1 = std::stoi(v1raw);
1410 v2 = std::stoi(v2raw);
1413 faces.push_back(v0 - 1);
1414 faces.push_back(v1 - 1);
1415 faces.push_back(v2 - 1);
1419 #ifdef LIBFS_DBG_INFO 1420 num_lines_ignored++;
1427 #ifdef LIBFS_DBG_INFO 1428 if (num_lines_ignored > 0)
1430 std::cout << LIBFS_APPTAG <<
"Ignored " << num_lines_ignored <<
" lines in Wavefront OBJ format mesh file.\n";
1434 mesh->
faces = faces;
1453 #ifdef LIBFS_DBG_INFO 1454 std::cout << LIBFS_APPTAG <<
"Reading brain mesh from Wavefront object format file " << filename <<
".\n";
1456 std::ifstream input(filename, std::fstream::in);
1457 if (input.is_open())
1464 throw std::runtime_error(
"Could not open Wavefront object format mesh file '" + filename +
"' for reading.\n");
1474 static void from_off(
Mesh *mesh, std::istream *is,
const std::string &source_filename =
"")
1477 std::string msg_source_file_part = source_filename.empty() ?
"" :
"'" + source_filename +
"'";
1481 int noncomment_line_idx = -1;
1483 std::vector<float> vertices;
1484 std::vector<int> faces;
1485 size_t num_vertices = 0;
1486 size_t num_faces = 0;
1487 size_t num_edges = 0;
1488 size_t num_verts_parsed = 0;
1489 size_t num_faces_parsed = 0;
1493 int num_verts_this_face, v0, v1, v2;
1495 while (std::getline(*is, line))
1498 std::istringstream iss(line);
1499 if (fs::util::starts_with(line,
"#"))
1505 noncomment_line_idx++;
1506 if (noncomment_line_idx == 0)
1508 std::string off_header_magic;
1509 if (!(iss >> off_header_magic))
1511 throw std::domain_error(
"Could not parse first header line " + std::to_string(line_idx + 1) +
" of OFF data, invalid format.\n");
1513 if (!(off_header_magic ==
"OFF" || off_header_magic ==
"COFF"))
1515 throw std::domain_error(
"OFF magic string invalid, file " + msg_source_file_part +
" not in OFF format.\n");
1519 else if (noncomment_line_idx == 1)
1521 if (!(iss >> num_vertices >> num_faces >> num_edges))
1523 throw std::domain_error(
"Could not parse element count header line " + std::to_string(line_idx + 1) +
" of OFF data " + msg_source_file_part +
", invalid format.\n");
1529 if (num_verts_parsed < num_vertices)
1531 if (!(iss >> x >> y >> z))
1533 throw std::domain_error(
"Could not parse vertex coordinate line " + std::to_string(line_idx + 1) +
" of OFF data " + msg_source_file_part +
", invalid format.\n");
1535 vertices.push_back(x);
1536 vertices.push_back(y);
1537 vertices.push_back(z);
1542 if (num_faces_parsed < num_faces)
1544 if (!(iss >> num_verts_this_face >> v0 >> v1 >> v2))
1546 throw std::domain_error(
"Could not parse face line " + std::to_string(line_idx + 1) +
" of OFF data " + msg_source_file_part +
", invalid format.\n");
1548 if (num_verts_this_face != 3)
1550 throw std::domain_error(
"At OFF data " + msg_source_file_part +
" line " + std::to_string(line_idx + 1) +
": only triangular meshes supported.\n");
1552 faces.push_back(v0);
1553 faces.push_back(v1);
1554 faces.push_back(v2);
1561 if (num_verts_parsed < num_vertices)
1563 throw std::domain_error(
"Vertex count mismatch between OFF data " + msg_source_file_part +
" header (" + std::to_string(num_vertices) +
") and data (" + std::to_string(num_verts_parsed) +
").\n");
1565 if (num_faces_parsed < num_faces)
1567 throw std::domain_error(
"Face count mismatch between OFF data " + msg_source_file_part +
" header (" + std::to_string(num_faces) +
") and data (" + std::to_string(num_faces_parsed) +
").\n");
1570 mesh->
faces = faces;
1589 #ifdef LIBFS_DBG_INFO 1590 std::cout << LIBFS_APPTAG <<
"Reading brain mesh from OFF format file " << filename <<
".\n";
1592 std::ifstream input(filename, std::fstream::in);
1593 if (input.is_open())
1600 throw std::runtime_error(
"Could not open Object file format (OFF) mesh file '" + filename +
"' for reading.\n");
1613 int noncomment_line_idx = -1;
1615 std::vector<float> vertices;
1616 std::vector<int> faces;
1618 bool in_header =
true;
1621 while (std::getline(*is, line))
1624 std::istringstream iss(line);
1625 if (fs::util::starts_with(line,
"comment"))
1631 noncomment_line_idx++;
1634 if (noncomment_line_idx == 0)
1637 throw std::domain_error(
"Invalid PLY file");
1639 else if (noncomment_line_idx == 1)
1641 if (line !=
"format ascii 1.0")
1642 throw std::domain_error(
"Unsupported PLY file format, only format 'format ascii 1.0' is supported.");
1645 if (line ==
"end_header")
1649 else if (fs::util::starts_with(line,
"element vertex"))
1651 std::string elem, elem_type_identifier;
1652 if (!(iss >> elem >> elem_type_identifier >> num_verts))
1654 throw std::domain_error(
"Could not parse element vertex line of PLY header, invalid format.\n");
1657 else if (fs::util::starts_with(line,
"element face"))
1659 std::string elem, elem_type_identifier;
1660 if (!(iss >> elem >> elem_type_identifier >> num_faces))
1662 throw std::domain_error(
"Could not parse element face line of PLY header, invalid format.\n");
1668 if (num_verts < 1 || num_faces < 1)
1670 throw std::domain_error(
"Invalid PLY file: missing element count lines of header.");
1673 if (vertices.size() < (size_t)num_verts * 3)
1676 if (!(iss >> x >> y >> z))
1678 throw std::domain_error(
"Could not parse vertex line " + std::to_string(line_idx) +
" of PLY data, invalid format.\n");
1680 vertices.push_back(x);
1681 vertices.push_back(y);
1682 vertices.push_back(z);
1686 if (faces.size() < (size_t)num_faces * 3)
1688 int verts_per_face, v0, v1, v2;
1689 if (!(iss >> verts_per_face >> v0 >> v1 >> v2))
1691 throw std::domain_error(
"Could not parse face line " + std::to_string(line_idx) +
" of PLY data, invalid format.\n");
1693 if (verts_per_face != 3)
1695 throw std::domain_error(
"Only triangular meshes are supported: PLY faces lines must contain exactly 3 vertex indices.\n");
1697 faces.push_back(v0);
1698 faces.push_back(v1);
1699 faces.push_back(v2);
1705 if (vertices.size() != (size_t)num_verts * 3)
1707 std::cerr <<
"PLY header mentions " << num_verts <<
" vertices, but found " << vertices.size() / 3 <<
".\n";
1709 if (faces.size() != (size_t)num_faces * 3)
1711 std::cerr <<
"PLY header mentions " << num_faces <<
" faces, but found " << faces.size() / 3 <<
".\n";
1714 mesh->
faces = faces;
1732 #ifdef LIBFS_DBG_INFO 1733 std::cout << LIBFS_APPTAG <<
"Reading brain mesh from PLY format file " << filename <<
".\n";
1735 std::ifstream input(filename, std::fstream::in);
1736 if (input.is_open())
1743 throw std::runtime_error(
"Could not open Stanford PLY format mesh file '" + filename +
"' for reading.\n");
1758 return (this->vertices.size() / 3);
1772 return (this->faces.size() / 3);
1787 const int32_t &
fm_at(
const size_t i,
const size_t j)
const 1789 size_t idx = _vidx_2d(i, j, 3);
1790 if (idx > this->faces.size() - 1)
1792 throw std::range_error(
"Indices (" + std::to_string(i) +
"," + std::to_string(j) +
") into Mesh.faces out of bounds. Hit " + std::to_string(idx) +
" with max valid index " + std::to_string(this->faces.size() - 1) +
".\n");
1794 return (this->faces[idx]);
1810 if (face > this->num_faces() - 1)
1812 throw std::range_error(
"Index " + std::to_string(face) +
" into Mesh.faces out of bounds, max valid index is " + std::to_string(this->num_faces() - 1) +
".\n");
1814 std::vector<int32_t> fv(3);
1815 fv[0] = this->fm_at(face, 0);
1816 fv[1] = this->fm_at(face, 1);
1817 fv[2] = this->fm_at(face, 2);
1834 if (vertex > this->num_vertices() - 1)
1836 throw std::range_error(
"Index " + std::to_string(vertex) +
" into Mesh.vertices out of bounds, max valid index is " + std::to_string(this->num_vertices() - 1) +
".\n");
1838 std::vector<float> vc(3);
1839 vc[0] = this->vm_at(vertex, 0);
1840 vc[1] = this->vm_at(vertex, 1);
1841 vc[2] = this->vm_at(vertex, 2);
1858 const float &
vm_at(
const size_t i,
const size_t j)
const 1860 size_t idx = _vidx_2d(i, j, 3);
1861 if (idx > this->vertices.size() - 1)
1863 throw std::range_error(
"Indices (" + std::to_string(i) +
"," + std::to_string(j) +
") into Mesh.vertices out of bounds. Hit " + std::to_string(idx) +
" with max valid index " + std::to_string(this->vertices.size() - 1) +
".\n");
1865 return (this->vertices[idx]);
1878 std::vector<uint8_t> empty_col;
1879 return (this->to_ply(empty_col));
1892 std::string
to_ply(
const std::vector<uint8_t> col)
const 1894 bool use_vertex_colors = col.size() != 0;
1895 std::stringstream plys;
1896 plys <<
"ply\nformat ascii 1.0\n";
1897 plys <<
"element vertex " << this->num_vertices() <<
"\n";
1898 plys <<
"property float x\nproperty float y\nproperty float z\n";
1899 if (use_vertex_colors)
1901 if (col.size() != this->vertices.size())
1903 throw std::invalid_argument(
"Number of vertex coordinates and vertex colors must match when writing PLY file, but got " + std::to_string(this->vertices.size()) +
" and " + std::to_string(col.size()) +
".");
1905 plys <<
"property uchar red\nproperty uchar green\nproperty uchar blue\n";
1907 plys <<
"element face " << this->num_faces() <<
"\n";
1908 plys <<
"property list uchar int vertex_index\n";
1909 plys <<
"end_header\n";
1911 #ifdef LIBFS_DBG_DEBUG 1912 fs::util::log(
"Writing " + std::to_string(this->vertices.size() / 3) +
" PLY format vertices.",
"INFO");
1915 for (
size_t vidx = 0; vidx < this->vertices.size(); vidx += 3)
1917 plys << vertices[vidx] <<
" " << vertices[vidx + 1] <<
" " << vertices[vidx + 2];
1918 if (use_vertex_colors)
1920 plys <<
" " << (int)col[vidx] <<
" " << (
int)col[vidx + 1] <<
" " << (int)col[vidx + 2];
1925 #ifdef LIBFS_DBG_DEBUG 1926 fs::util::log(
"Writing " + std::to_string(this->faces.size() / 3) +
" PLY format faces.",
"INFO");
1929 const int num_vertices_per_face = 3;
1930 for (
size_t fidx = 0; fidx < this->faces.size(); fidx += 3)
1932 plys << num_vertices_per_face <<
" " << faces[fidx] <<
" " << faces[fidx + 1] <<
" " << faces[fidx + 2] <<
"\n";
1934 return (plys.str());
1948 #ifdef LIBFS_DBG_INFO 1949 fs::util::log(
"Writing mesh to PLY file '" + filename +
"'.",
"INFO");
1951 fs::util::str_to_file(filename, this->to_ply());
1956 void to_ply_file(
const std::string &filename,
const std::vector<uint8_t> col)
const 1958 fs::util::str_to_file(filename, this->to_ply(col));
1971 std::vector<uint8_t> empty_col;
1972 return (this->to_off(empty_col));
1978 std::string
to_off(
const std::vector<uint8_t> col)
const 1980 bool use_vertex_colors = col.size() != 0;
1981 std::stringstream offs;
1982 if (use_vertex_colors)
1984 #ifdef LIBFS_DBG_INFO 1985 fs::util::log(
"Writing OFF representation of mesh with vertex colors.",
"INFO");
1987 if (col.size() != this->vertices.size())
1989 throw std::invalid_argument(
"Number of vertex coordinates and vertex colors must match when writing OFF file but got " + std::to_string(this->vertices.size()) +
" and " + std::to_string(col.size()) +
".");
1995 #ifdef LIBFS_DBG_INFO 1996 fs::util::log(
"Writing OFF representation of mesh without vertex colors.",
"INFO");
2000 offs << this->num_vertices() <<
" " << this->num_faces() <<
" 0\n";
2002 for (
size_t vidx = 0; vidx < this->vertices.size(); vidx += 3)
2004 offs << vertices[vidx] <<
" " << vertices[vidx + 1] <<
" " << vertices[vidx + 2];
2005 if (use_vertex_colors)
2007 offs <<
" " << (int)col[vidx] <<
" " << (
int)col[vidx + 1] <<
" " << (int)col[vidx + 2] <<
" 255";
2012 const int num_vertices_per_face = 3;
2013 for (
size_t fidx = 0; fidx < this->faces.size(); fidx += 3)
2015 offs << num_vertices_per_face <<
" " << faces[fidx] <<
" " << faces[fidx + 1] <<
" " << faces[fidx + 2] <<
"\n";
2017 return (offs.str());
2031 fs::util::str_to_file(filename, this->to_off());
2036 void to_off_file(
const std::string &filename,
const std::vector<uint8_t> col)
const 2038 fs::util::str_to_file(filename, this->to_off(col));
2047 Curv(std::vector<float> curv_data) : num_faces(100000), num_vertices(0), num_values_per_vertex(1)
2050 num_vertices = int(data.size());
2054 Curv() : num_faces(100000), num_vertices(0), num_values_per_vertex(1) {}
2074 std::vector<int32_t>
r;
2075 std::vector<int32_t>
g;
2076 std::vector<int32_t>
b;
2077 std::vector<int32_t>
a;
2083 size_t num_ids = this->
id.size();
2084 if (this->name.size() != num_ids || this->r.size() != num_ids || this->g.size() != num_ids || this->b.size() != num_ids || this->a.size() != num_ids || this->label.size() != num_ids)
2086 std::cerr <<
"Inconsistent Colortable, vector sizes do not match.\n";
2094 for (
size_t i = 0; i < this->num_entries(); i++)
2096 if (this->name[i] == query_name)
2107 for (
size_t i = 0; i < this->num_entries(); i++)
2109 if (this->label[i] == query_label)
2128 int32_t region_idx = this->colortable.
get_region_idx(region_name);
2129 if (region_idx >= 0)
2131 return (this->region_vertices(this->colortable.
label[region_idx]));
2135 std::cerr <<
"No such region in annot, returning empty vector.\n";
2136 std::vector<int32_t> empty;
2144 std::vector<int32_t> reg_verts;
2145 for (
size_t i = 0; i < this->vertex_labels.size(); i++)
2147 if (this->vertex_labels[i] == region_label)
2149 reg_verts.push_back(
int(i));
2159 int num_channels = alpha ? 4 : 3;
2160 std::vector<uint8_t> col;
2161 col.reserve(this->num_vertices() * num_channels);
2162 std::vector<size_t> vertex_region_indices = this->vertex_regions();
2163 for (
size_t i = 0; i < this->num_vertices(); i++)
2165 col.push_back(this->colortable.
r[vertex_region_indices[i]]);
2166 col.push_back(this->colortable.
g[vertex_region_indices[i]]);
2167 col.push_back(this->colortable.
b[vertex_region_indices[i]]);
2170 col.push_back(this->colortable.
a[vertex_region_indices[i]]);
2180 size_t nv = this->vertex_indices.size();
2181 if (this->vertex_labels.size() != nv)
2183 throw std::runtime_error(
"Inconsistent annot, number of vertex indices and labels does not match.\n");
2192 std::vector<size_t> vert_reg;
2193 for (
size_t i = 0; i < this->num_vertices(); i++)
2195 vert_reg.push_back(0);
2197 for (
size_t region_idx = 0; region_idx < this->colortable.
num_entries(); region_idx++)
2199 std::vector<int32_t> reg_vertices = this->region_vertices(this->colortable.
label[region_idx]);
2200 for (
size_t region_vert_local_idx = 0; region_vert_local_idx < reg_vertices.size(); region_vert_local_idx++)
2202 int32_t region_vert_idx = reg_vertices[region_vert_local_idx];
2203 vert_reg[region_vert_idx] = region_idx;
2212 std::vector<std::string> region_names;
2213 std::vector<size_t> vertex_region_indices = this->vertex_regions();
2214 for (
size_t i = 0; i < this->num_vertices(); i++)
2216 region_names.push_back(this->colortable.
name[vertex_region_indices[i]]);
2218 return (region_names);
2228 dim1length = curv.
data.size();
2236 dim1length = curv_data.size();
2242 int32_t dim1length = 0;
2243 int32_t dim2length = 0;
2244 int32_t dim3length = 0;
2245 int32_t dim4length = 0;
2249 int16_t ras_good_flag = 0;
2254 return ((
size_t)dim1length * dim2length * dim3length * dim4length);
2268 MghData(std::vector<int32_t> curv_data) { data_mri_int = curv_data; }
2269 explicit MghData(std::vector<uint8_t> curv_data) { data_mri_uchar = curv_data; }
2270 explicit MghData(std::vector<short> curv_data) { data_mri_short = curv_data; }
2271 MghData(std::vector<float> curv_data) { data_mri_float = curv_data; }
2290 Mgh(std::vector<float> curv_data)
2303 Array4D(
unsigned int d1,
unsigned int d2,
unsigned int d3,
unsigned int d4) : d1(d1), d2(d2), d3(d3), d4(d4), data(d1 * d2 * d3 * d4) {}
2306 Array4D(
MghHeader *mgh_header) : d1(mgh_header->dim1length), d2(mgh_header->dim2length), d3(mgh_header->dim3length), d4(mgh_header->dim4length), data(d1 * d2 * d3 * d4) {}
2310 d1(mgh->header.dim1length), d2(mgh->header.dim2length), d3(mgh->header.dim3length), d4(mgh->header.dim4length), data(d1 * d2 * d3 * d4)
2315 const T &
at(
const unsigned int i1,
const unsigned int i2,
const unsigned int i3,
const unsigned int i4)
const 2317 return data[get_index(i1, i2, i3, i4)];
2321 unsigned int get_index(
const unsigned int i1,
const unsigned int i2,
const unsigned int i3,
const unsigned int i4)
const 2323 assert(i1 >= 0 && i1 < d1);
2324 assert(i2 >= 0 && i2 < d2);
2325 assert(i3 >= 0 && i3 < d3);
2326 assert(i4 >= 0 && i4 < d4);
2327 return (((i1 * d2 + i2) * d3 + i3) * d4 + i4);
2333 return (d1 * d2 * d3 * d4);
2346 template <
typename T>
2347 std::vector<T> _read_mgh_data(
MghHeader *,
const std::string &);
2348 template <
typename T>
2349 std::vector<T> _read_mgh_data(
MghHeader *, std::istream *);
2350 std::vector<int32_t> _read_mgh_data_int(
MghHeader *,
const std::string &);
2351 std::vector<int32_t> _read_mgh_data_int(
MghHeader *, std::istream *);
2352 std::vector<uint8_t> _read_mgh_data_uchar(
MghHeader *,
const std::string &);
2353 std::vector<uint8_t> _read_mgh_data_uchar(
MghHeader *, std::istream *);
2354 std::vector<short> _read_mgh_data_short(
MghHeader *,
const std::string &);
2355 std::vector<short> _read_mgh_data_short(
MghHeader *, std::istream *);
2356 std::vector<float> _read_mgh_data_float(
MghHeader *,
const std::string &);
2357 std::vector<float> _read_mgh_data_float(
MghHeader *, std::istream *);
2375 mgh->
header = mgh_header;
2378 std::vector<int32_t> data = _read_mgh_data_int(&mgh_header, filename);
2383 std::vector<uint8_t> data = _read_mgh_data_uchar(&mgh_header, filename);
2388 std::vector<float> data = _read_mgh_data_float(&mgh_header, filename);
2393 std::vector<short> data = _read_mgh_data_short(&mgh_header, filename);
2398 #ifdef LIBFS_DBG_INFO 2399 if (fs::util::ends_with(filename,
".mgz"))
2401 std::cout << LIBFS_APPTAG <<
"Note: your MGH filename ends with '.mgz'. Keep in mind that MGZ format is not supported directly. You can ignore this message if you wrapped a gz stream.\n";
2404 throw std::runtime_error(
"Not reading MGH data from file '" + filename +
"', data type " + std::to_string(mgh->
header.
dtype) +
" not supported yet.\n");
2419 std::vector<std::string> subjects;
2420 std::ifstream input(filename, std::fstream::in);
2423 if (!input.is_open())
2425 throw std::runtime_error(
"Could not open subjects file '" + filename +
"'.\n");
2428 while (std::getline(input, line))
2430 subjects.push_back(line);
2444 mgh->
header = mgh_header;
2447 std::vector<int32_t> data = _read_mgh_data_int(&mgh_header, is);
2452 std::vector<uint8_t> data = _read_mgh_data_uchar(&mgh_header, is);
2457 std::vector<float> data = _read_mgh_data_float(&mgh_header, is);
2462 std::vector<short> data = _read_mgh_data_short(&mgh_header, is);
2467 throw std::runtime_error(
"Not reading data from MGH stream, data type " + std::to_string(mgh->
header.
dtype) +
" not supported yet.\n");
2478 const int MGH_VERSION = 1;
2480 int format_version = _freadt<int32_t>(*is);
2481 if (format_version != MGH_VERSION)
2483 throw std::runtime_error(
"Invalid MGH file or unsupported file format version: expected version " + std::to_string(MGH_VERSION) +
", found " + std::to_string(format_version) +
".\n");
2485 mgh_header->
dim1length = _freadt<int32_t>(*is);
2486 mgh_header->
dim2length = _freadt<int32_t>(*is);
2487 mgh_header->
dim3length = _freadt<int32_t>(*is);
2488 mgh_header->
dim4length = _freadt<int32_t>(*is);
2490 mgh_header->
dtype = _freadt<int32_t>(*is);
2491 mgh_header->
dof = _freadt<int32_t>(*is);
2493 int unused_header_space_size_left = 256;
2495 unused_header_space_size_left -= 2;
2500 mgh_header->
xsize = _freadt<float>(*is);
2501 mgh_header->
ysize = _freadt<float>(*is);
2502 mgh_header->
zsize = _freadt<float>(*is);
2504 for (
int i = 0; i < 9; i++)
2506 mgh_header->
Mdc.push_back(_freadt<float>(*is));
2508 for (
int i = 0; i < 3; i++)
2510 mgh_header->
Pxyz_c.push_back(_freadt<float>(*is));
2512 unused_header_space_size_left -= 60;
2518 while (unused_header_space_size_left > 0)
2520 discarded = _freadt<uint8_t>(*is);
2521 unused_header_space_size_left -= 1;
2530 std::vector<int32_t> _read_mgh_data_int(
MghHeader *mgh_header,
const std::string &filename)
2532 if (mgh_header->
dtype != MRI_INT)
2534 std::cerr <<
"Expected MRI data type " << MRI_INT <<
", but found " << mgh_header->
dtype <<
".\n";
2536 return (_read_mgh_data<int32_t>(mgh_header, filename));
2543 std::vector<int32_t> _read_mgh_data_int(
MghHeader *mgh_header, std::istream *is)
2545 if (mgh_header->
dtype != MRI_INT)
2547 std::cerr <<
"Expected MRI data type " << MRI_INT <<
", but found " << mgh_header->
dtype <<
".\n";
2549 return (_read_mgh_data<int32_t>(mgh_header, is));
2556 std::vector<short> _read_mgh_data_short(
MghHeader *mgh_header,
const std::string &filename)
2558 if (mgh_header->
dtype != MRI_SHORT)
2560 std::cerr <<
"Expected MRI data type " << MRI_SHORT <<
", but found " << mgh_header->
dtype <<
".\n";
2562 return (_read_mgh_data<short>(mgh_header, filename));
2569 std::vector<short> _read_mgh_data_short(
MghHeader *mgh_header, std::istream *is)
2571 if (mgh_header->
dtype != MRI_SHORT)
2573 std::cerr <<
"Expected MRI data type " << MRI_SHORT <<
", but found " << mgh_header->
dtype <<
".\n";
2575 return (_read_mgh_data<short>(mgh_header, is));
2587 ifs.open(filename, std::ios_base::in | std::ios::binary);
2595 throw std::runtime_error(
"Unable to open MGH file '" + filename +
"'.\n");
2604 template <
typename T>
2605 std::vector<T> _read_mgh_data(
MghHeader *mgh_header,
const std::string &filename)
2608 ifs.open(filename, std::ios_base::in | std::ios::binary);
2611 ifs.seekg(284, ifs.beg);
2613 int num_values = int(mgh_header->
num_values());
2614 std::vector<T> data;
2615 for (
int i = 0; i < num_values; i++)
2617 data.push_back(_freadt<T>(ifs));
2624 throw std::runtime_error(
"Unable to open MGH file '" + filename +
"'.\n");
2632 template <
typename T>
2633 std::vector<T> _read_mgh_data(
MghHeader *mgh_header, std::istream *is)
2635 int num_values = int(mgh_header->
num_values());
2636 std::vector<T> data;
2637 for (
int i = 0; i < num_values; i++)
2639 data.push_back(_freadt<T>(*is));
2648 std::vector<float> _read_mgh_data_float(
MghHeader *mgh_header,
const std::string &filename)
2650 if (mgh_header->
dtype != MRI_FLOAT)
2652 std::cerr <<
"Expected MRI data type " << MRI_FLOAT <<
", but found " << mgh_header->
dtype <<
".\n";
2654 return (_read_mgh_data<float>(mgh_header, filename));
2661 std::vector<float> _read_mgh_data_float(
MghHeader *mgh_header, std::istream *is)
2663 if (mgh_header->
dtype != MRI_FLOAT)
2665 std::cerr <<
"Expected MRI data type " << MRI_FLOAT <<
", but found " << mgh_header->
dtype <<
".\n";
2667 return (_read_mgh_data<float>(mgh_header, is));
2674 std::vector<uint8_t> _read_mgh_data_uchar(
MghHeader *mgh_header,
const std::string &filename)
2676 if (mgh_header->
dtype != MRI_UCHAR)
2678 std::cerr <<
"Expected MRI data type " << MRI_UCHAR <<
", but found " << mgh_header->
dtype <<
".\n";
2680 return (_read_mgh_data<uint8_t>(mgh_header, filename));
2687 std::vector<uint8_t> _read_mgh_data_uchar(
MghHeader *mgh_header, std::istream *is)
2689 if (mgh_header->
dtype != MRI_UCHAR)
2691 std::cerr <<
"Expected MRI data type " << MRI_UCHAR <<
", but found " << mgh_header->
dtype <<
".\n";
2693 return (_read_mgh_data<uint8_t>(mgh_header, is));
2711 const int SURF_TRIS_MAGIC = 16777214;
2713 is.open(filename, std::ios_base::in | std::ios::binary);
2716 int magic = _fread3(is);
2717 if (magic != SURF_TRIS_MAGIC)
2719 throw std::domain_error(
"Surf file '" + filename +
"' magic code in header did not match: expected " + std::to_string(SURF_TRIS_MAGIC) +
", found " + std::to_string(magic) +
".\n");
2721 std::string created_line = _freadstringnewline(is);
2722 std::string comment_line = _freadstringnewline(is);
2723 int num_verts = _freadt<int32_t>(is);
2724 int num_faces = _freadt<int32_t>(is);
2725 #ifdef LIBFS_DBG_INFO 2726 std::cout << LIBFS_APPTAG <<
"Read surface file with " << num_verts <<
" vertices, " << num_faces <<
" faces.\n";
2728 std::vector<float> vdata;
2729 for (
int i = 0; i < (num_verts * 3); i++)
2731 vdata.push_back(_freadt<float>(is));
2733 std::vector<int> fdata;
2734 for (
int i = 0; i < (num_faces * 3); i++)
2736 fdata.push_back(_freadt<int32_t>(is));
2740 surface->
faces = fdata;
2744 throw std::runtime_error(
"Unable to open surface file '" + filename +
"'.\n");
2762 if (fs::util::ends_with(filename,
".obj"))
2766 else if (fs::util::ends_with(filename,
".ply"))
2770 else if (fs::util::ends_with(filename,
".off"))
2785 bool _is_bigendian()
2787 short int number = 0x1;
2788 char *numPtr = (
char *)&number;
2790 return (numPtr[0] != 1);
2798 void read_curv(
Curv *curv, std::istream *is,
const std::string &source_filename =
"")
2800 const std::string msg_source_file_part = source_filename.empty() ?
"" :
"'" + source_filename +
"' ";
2801 const int CURV_MAGIC = 16777215;
2802 int magic = _fread3(*is);
2803 if (magic != CURV_MAGIC)
2805 throw std::domain_error(
"Curv file " + msg_source_file_part +
"header magic did not match: expected " + std::to_string(CURV_MAGIC) +
", found " + std::to_string(magic) +
".\n");
2808 curv->
num_faces = _freadt<int32_t>(*is);
2810 #ifdef LIBFS_DBG_INFO 2815 throw std::domain_error(
"Curv file " + msg_source_file_part +
"must contain exactly 1 value per vertex, found " + std::to_string(curv->
num_values_per_vertex) +
".\n");
2817 std::vector<float> data;
2820 data.push_back(_freadt<float>(*is));
2839 std::ifstream is(filename, std::fstream::in | std::fstream::binary);
2847 throw std::runtime_error(
"Could not open curv file '" + filename +
"' for reading.\n");
2853 void _read_annot_colortable(
Colortable *colortable, std::istream *is, int32_t num_entries)
2855 int32_t num_chars_orig_filename = _freadt<int32_t>(*is);
2859 for (int32_t i = 0; i < num_chars_orig_filename; i++)
2861 discarded = _freadt<uint8_t>(*is);
2865 int32_t num_entries_duplicated = _freadt<int32_t>(*is);
2866 if (num_entries != num_entries_duplicated)
2868 std::cerr <<
"Warning: the two num_entries header fields of this annotation do not match. Use with care.\n";
2871 int32_t entry_num_chars;
2872 for (int32_t i = 0; i < num_entries; i++)
2874 colortable->
id.push_back(_freadt<int32_t>(*is));
2875 entry_num_chars = _freadt<int32_t>(*is);
2876 colortable->
name.push_back(_freadfixedlengthstring(*is, entry_num_chars,
true));
2877 colortable->
r.push_back(_freadt<int32_t>(*is));
2878 colortable->
g.push_back(_freadt<int32_t>(*is));
2879 colortable->
b.push_back(_freadt<int32_t>(*is));
2880 colortable->
a.push_back(_freadt<int32_t>(*is));
2881 colortable->
label.push_back(colortable->
r[i] + colortable->
g[i] * 256 + colortable->
b[i] * 65536 + colortable->
a[i] * 16777216);
2887 size_t _vidx_2d(
size_t row,
size_t column,
size_t row_length = 3)
2889 return (row + 1) * row_length - row_length + column;
2900 int32_t num_vertices = _freadt<int32_t>(*is);
2901 std::vector<int32_t> vertices;
2902 std::vector<int32_t> labels;
2903 for (int32_t i = 0; i < (num_vertices * 2); i++)
2907 vertices.push_back(_freadt<int32_t>(*is));
2911 labels.push_back(_freadt<int32_t>(*is));
2916 int32_t has_colortable = _freadt<int32_t>(*is);
2917 if (has_colortable == 1)
2919 int32_t num_colortable_entries_old_format = _freadt<int32_t>(*is);
2920 if (num_colortable_entries_old_format > 0)
2922 throw std::domain_error(
"Reading annotation in old format not supported. Please open an issue and supply an example file if you need this.\n");
2926 int32_t colortable_format_version = -num_colortable_entries_old_format;
2927 if (colortable_format_version == 2)
2929 int32_t num_colortable_entries = _freadt<int32_t>(*is);
2930 _read_annot_colortable(&annot->
colortable, is, num_colortable_entries);
2934 throw std::domain_error(
"Reading annotation in new format version !=2 not supported. Please open an issue and supply an example file if you need this.\n");
2940 throw std::domain_error(
"Reading annotation without colortable not supported. Maybe invalid annotation file?\n");
2959 std::ifstream is(filename, std::fstream::in | std::fstream::binary);
2967 throw std::runtime_error(
"Could not open annot file '" + filename +
"' for reading.\n");
3005 if (fs::util::ends_with(filename, {
".MGH",
".mgh"}))
3012 for (
size_t i = 0; i < dims.size(); i++)
3021 std::cerr <<
"MGH file '" << filename <<
"' contains more than one non-empty dimension. Returning concatinated data.\n";
3037 template <
typename T>
3041 static_assert(CHAR_BIT == 8,
"CHAR_BIT != 8");
3046 unsigned char u8[
sizeof(T)];
3051 for (
size_t k = 0; k <
sizeof(T); k++)
3052 dest.u8[k] = source.u8[
sizeof(T) - k - 1];
3061 template <
typename T>
3062 T _freadt(std::istream &is)
3065 is.read(reinterpret_cast<char *>(&t),
sizeof(t));
3066 if (!_is_bigendian())
3068 t = _swap_endian<T>(t);
3077 int _fread3(std::istream &is)
3080 is.read(reinterpret_cast<char *>(&i), 3);
3081 if (!_is_bigendian())
3083 i = _swap_endian<std::uint32_t>(i);
3085 i = ((i >> 8) & 0xffffff);
3093 template <
typename T>
3094 void _fwritet(std::ostream &os, T t)
3096 if (!_is_bigendian())
3098 t = _swap_endian<T>(t);
3100 os.write(reinterpret_cast<const char *>(&t),
sizeof(t));
3107 void _fwritei3(std::ostream &os, uint32_t i)
3109 unsigned char b1 = (i >> 16) & 255;
3110 unsigned char b2 = (i >> 8) & 255;
3111 unsigned char b3 = i & 255;
3113 if (!_is_bigendian())
3115 b1 = _swap_endian<unsigned char>(b1);
3116 b2 = _swap_endian<unsigned char>(b2);
3117 b3 = _swap_endian<unsigned char>(b3);
3120 os.write(reinterpret_cast<const char *>(&b1),
sizeof(b1));
3121 os.write(reinterpret_cast<const char *>(&b2),
sizeof(b2));
3122 os.write(reinterpret_cast<const char *>(&b3),
sizeof(b3));
3129 std::string _freadstringnewline(std::istream &is)
3132 std::getline(is, s,
'\n');
3139 std::string _freadfixedlengthstring(std::istream &is,
size_t length,
bool strip_last_char =
true)
3143 is.read(&str[0], length);
3144 if (strip_last_char)
3146 str = str.substr(0, length - 1);
3156 void write_curv(std::ostream &os, std::vector<float> curv_data, int32_t num_faces = 100000)
3158 const uint32_t CURV_MAGIC = 16777215;
3159 _fwritei3(os, CURV_MAGIC);
3160 _fwritet<int32_t>(os, int(curv_data.size()));
3161 _fwritet<int32_t>(os, num_faces);
3162 _fwritet<int32_t>(os, 1);
3163 for (
size_t i = 0; i < curv_data.size(); i++)
3165 _fwritet<float>(os, curv_data[i]);
3183 void write_curv(
const std::string &filename, std::vector<float> curv_data,
const int32_t num_faces = 100000)
3186 ofs.open(filename, std::ofstream::out | std::ofstream::binary);
3194 throw std::runtime_error(
"Unable to open curvature file '" + filename +
"' for writing.\n");
3205 _fwritet<int32_t>(os, 1);
3214 size_t unused_header_space_size_left = 256;
3216 unused_header_space_size_left -= 2;
3225 for (
int i = 0; i < 9; i++)
3229 for (
int i = 0; i < 3; i++)
3234 unused_header_space_size_left -= 60;
3237 for (
size_t i = 0; i < unused_header_space_size_left; i++)
3239 _fwritet<uint8_t>(os, 0);
3248 throw std::logic_error(
"Detected mismatch of MRI_INT data size and MGH header dim length values.\n");
3250 for (
size_t i = 0; i < num_values; i++)
3259 throw std::logic_error(
"Detected mismatch of MRI_FLOAT data size and MGH header dim length values.\n");
3261 for (
size_t i = 0; i < num_values; i++)
3270 throw std::logic_error(
"Detected mismatch of MRI_UCHAR data size and MGH header dim length values.\n");
3272 for (
size_t i = 0; i < num_values; i++)
3281 throw std::logic_error(
"Detected mismatch of MRI_SHORT data size and MGH header dim length values.\n");
3283 for (
size_t i = 0; i < num_values; i++)
3290 throw std::domain_error(
"Unsupported MRI data type " + std::to_string(mgh.
header.
dtype) +
", cannot write MGH data.\n");
3312 ofs.open(filename, std::ofstream::out | std::ofstream::binary);
3320 throw std::runtime_error(
"Unable to open MGH file '" + filename +
"' for writing.\n");
3337 Label(std::vector<int> vertices, std::vector<float> values)
3339 assert(vertices.size() == values.size());
3342 coord_x = std::vector<float>(vertices.size(), 0.0f);
3343 coord_y = std::vector<float>(vertices.size(), 0.0f);
3344 coord_z = std::vector<float>(vertices.size(), 0.0f);
3351 value = std::vector<float>(vertices.size(), 0.0f);
3352 coord_x = std::vector<float>(vertices.size(), 0.0f);
3353 coord_y = std::vector<float>(vertices.size(), 0.0f);
3354 coord_z = std::vector<float>(vertices.size(), 0.0f);
3366 if (surface_num_verts < this->vertex.size())
3368 std::cerr <<
"Invalid number of vertices for surface, must be at least " << this->vertex.size() <<
"\n";
3370 std::vector<bool> is_in = std::vector<bool>(surface_num_verts,
false);
3372 for (
size_t i = 0; i < this->vertex.size(); i++)
3374 is_in[this->vertex[i]] =
true;
3382 size_t num_ent = this->vertex.size();
3383 if (this->coord_x.size() != num_ent || this->coord_y.size() != num_ent || this->coord_z.size() != num_ent || this->value.size() != num_ent)
3385 std::cerr <<
"Inconsistent label: sizes of property vectors do not match.\n";
3397 void write_surf(std::vector<float> vertices, std::vector<int32_t> faces, std::ostream &os)
3399 const uint32_t SURF_TRIS_MAGIC = 16777214;
3400 _fwritei3(os, SURF_TRIS_MAGIC);
3401 std::string created_and_comment_lines =
"Created by fslib\n\n";
3402 os << created_and_comment_lines;
3403 _fwritet<int32_t>(os, int(vertices.size() / 3));
3404 _fwritet<int32_t>(os, int(faces.size() / 3));
3405 for (
size_t i = 0; i < vertices.size(); i++)
3407 _fwritet<float>(os, vertices[i]);
3409 for (
size_t i = 0; i < faces.size(); i++)
3411 _fwritet<int32_t>(os, faces[i]);
3428 void write_surf(std::vector<float> vertices, std::vector<int32_t> faces,
const std::string &filename)
3431 ofs.open(filename, std::ofstream::out | std::ofstream::binary);
3439 throw std::runtime_error(
"Unable to open surf file '" + filename +
"' for writing.\n");
3458 ofs.open(filename, std::ofstream::out | std::ofstream::binary);
3466 throw std::runtime_error(
"Unable to open surf file '" + filename +
"' for writing.\n");
3480 size_t num_entries_header = 0;
3481 size_t num_entries = 0;
3482 while (std::getline(*is, line))
3485 std::istringstream iss(line);
3494 if (!(iss >> num_entries_header))
3496 throw std::domain_error(
"Could not parse entry count from label file, invalid format.\n");
3502 float x, y, z, value;
3503 if (!(iss >> vertex >> x >> y >> z >> value))
3505 throw std::domain_error(
"Could not parse line " + std::to_string(line_idx + 1) +
" of label file, invalid format.\n");
3507 label->
vertex.push_back(vertex);
3511 label->
value.push_back(value);
3516 if (num_entries != num_entries_header)
3518 throw std::domain_error(
"Expected " + std::to_string(num_entries_header) +
" entries from label file header, but found " + std::to_string(num_entries) +
" in file, invalid label file.\n");
3520 if (label->
vertex.size() != num_entries || label->
coord_x.size() != num_entries || label->
coord_y.size() != num_entries || label->
coord_z.size() != num_entries || label->
value.size() != num_entries)
3522 throw std::domain_error(
"Expected " + std::to_string(num_entries) +
" entries in all Label vectors, but some did not match.\n");
3541 std::ifstream infile(filename, std::fstream::in);
3542 if (infile.is_open())
3549 throw std::runtime_error(
"Could not open label file '" + filename +
"' for reading.\n");
3560 os <<
"#!ascii label from subject anonymous\n" 3561 << num_entries <<
"\n";
3562 for (
size_t i = 0; i < num_entries; i++)
3584 ofs.open(filename, std::ofstream::out);
3592 throw std::runtime_error(
"Unable to open label file '" + filename +
"' for writing.\n");
3613 if (fs::util::ends_with(filename, {
".ply",
".PLY"}))
3617 else if (fs::util::ends_with(filename, {
".obj",
".OBJ"}))
3621 else if (fs::util::ends_with(filename, {
".off",
".OFF"}))
void write_curv(std::ostream &os, std::vector< float > curv_data, int32_t num_faces=100000)
Write curv data to a stream.
Definition: libfs.h:3156
std::vector< float > vertices
n x 3 vector of the x,y,z coordinates for the n vertices. The x,y,z coordinates for a single vertex f...
Definition: libfs.h:747
std::vector< int32_t > vertex_indices
Indices of the vertices, these always go from 0 to N-1 (where N is the number of vertices in the resp...
Definition: libfs.h:2121
size_t num_entries() const
Get the number of enties (regions) in this Colortable.
Definition: libfs.h:2081
Mgh(Curv curv)
Definition: libfs.h:2285
std::vector< float > coord_x
x coordinates of the vertices in case of a surface label, or voxels coordinates for a volume label...
Definition: libfs.h:3358
std::string to_off(const std::vector< uint8_t > col) const
Return string representing the mesh in PLY format.
Definition: libfs.h:1978
Models a FreeSurfer curv file that contains per-vertex float data.
Definition: libfs.h:2043
const int MRI_SHORT
MRI data type representing a 16 bit signed integer.
Definition: libfs.h:698
std::vector< float > coord_y
y coordinates of the vertices in case of a surface label, or voxels coordinates for a volume label...
Definition: libfs.h:3359
unsigned int d2
size of data along 2nd dimension
Definition: libfs.h:2337
const std::string LOGTAG_EXCESSIVE
Logging threshold for warning messages.
Definition: libfs.h:190
An annotation, also known as a brain surface parcellation. Assigns to each vertex a region...
Definition: libfs.h:2119
const std::string LOGTAG_VERBOSE
Logging threshold for warning messages.
Definition: libfs.h:187
void read_curv(Curv *curv, std::istream *is, const std::string &source_filename="")
Read per-vertex brain morphometry data from a FreeSurfer curv stream.
Definition: libfs.h:2798
edge_set as_edgelist() const
Return edge list representation of this mesh.
Definition: libfs.h:956
std::vector< int32_t > label
label integer computed from rgba values. Maps to the Annot.vertex_label field.
Definition: libfs.h:2078
Array4D(MghHeader *mgh_header)
Constructor for creating an empty 4D array based on dimensions specified in an fs::MghHeader.
Definition: libfs.h:2306
std::string to_obj() const
Return string representing the mesh in Wavefront Object (.obj) format.
Definition: libfs.h:892
std::string time_tag(std::chrono::system_clock::time_point t)
Get current time as string, e.g. for log messages.
Definition: libfs.h:160
static void from_obj(Mesh *mesh, const std::string &filename)
Read a brainmesh from a Wavefront object format mesh file.
Definition: libfs.h:1451
const std::string LOGTAG_WARNING
Logging threshold for warning messages.
Definition: libfs.h:181
static std::vector< float > smooth_pvd_nn(const std::vector< std::vector< size_t >> mesh_adj, const std::vector< float > pvd, const size_t num_iter=1, const bool with_nan=true, const bool detect_nan=true)
Smooth given per-vertex data using nearest neighbor smoothing based on adjacency list mesh represenat...
Definition: libfs.h:1067
std::vector< uint8_t > viridis(const std::vector< float > &data, float vmin=NAN, float vmax=NAN, uint8_t nan_r=255, uint8_t nan_g=255, uint8_t nan_b=255)
Map per-vertex numeric data to RGB colors using the Viridis perceptually-uniform colormap.
Definition: libfs.h:475
bool file_exists(const std::string &name)
Check whether a file exists (can be read) at given path.
Definition: libfs.h:344
const std::string LOGTAG_INFO
Logging threshold for warning messages.
Definition: libfs.h:184
A simple 4D array datastructure, useful for representing volume data.
Definition: libfs.h:2300
std::vector< float > data
The curvature data, one value per vertex. Something like the cortical thickness at each vertex...
Definition: libfs.h:2060
static void from_ply(Mesh *mesh, std::istream *is)
Read a brainmesh from a Stanford PLY format stream.
Definition: libfs.h:1609
const int32_t & fm_at(const size_t i, const size_t j) const
Retrieve a vertex index of a face, treating the faces vector as an nx3 matrix.
Definition: libfs.h:1787
std::vector< T > data
the data, as a 1D vector. Use fs::Array4D::at for easy access in 4D.
Definition: libfs.h:2340
std::vector< int32_t > b
green channel of RGBA color
Definition: libfs.h:2076
static void from_ply(Mesh *mesh, const std::string &filename)
Read a brainmesh from a Stanford PLY format mesh file.
Definition: libfs.h:1730
std::vector< int32_t > g
blue channel of RGBA color
Definition: libfs.h:2075
std::vector< float > read_curv_data(const std::string &filename)
Read per-vertex brain morphometry data from a FreeSurfer curv format file.
Definition: libfs.h:2983
void write_mgh(const Mgh &mgh, std::ostream &os)
Write MGH data to a stream.
Definition: libfs.h:3203
static void from_off(Mesh *mesh, const std::string &filename)
Read a brainmesh from an OFF format mesh file.
Definition: libfs.h:1587
std::vector< bool > vert_in_label(size_t surface_num_verts) const
Compute for each vertex of the surface whether it is inside the label.
Definition: libfs.h:3364
static std::vector< float > curv_data_for_orig_mesh(const std::vector< float > data_submesh, const std::unordered_map< int32_t, int32_t > submesh_to_orig_mapping, const int32_t orig_mesh_num_vertices, const float fill_value=std::numeric_limits< float >::quiet_NaN())
Given per-vertex data for a submesh, add NAN values inbetween to restore the original mesh size...
Definition: libfs.h:1311
Models a triangular mesh, used for brain surface meshes.
Definition: libfs.h:727
const int MRI_UCHAR
MRI data type representing an 8 bit unsigned integer.
Definition: libfs.h:689
size_t num_entries() const
Return the number of entries (vertices/voxels) in this label.
Definition: libfs.h:3380
unsigned int get_index(const unsigned int i1, const unsigned int i2, const unsigned int i3, const unsigned int i4) const
Get the index in the vector for the given 4D position.
Definition: libfs.h:2321
Models the data of an MGH file. Currently these are 1D vectors, but one can compute the 4D array usin...
Definition: libfs.h:2265
void read_label(Label *label, std::istream *is)
Read a FreeSurfer ASCII label from a stream.
Definition: libfs.h:3476
void to_ply_file(const std::string &filename) const
Export this mesh to a file in Stanford PLY format.
Definition: libfs.h:1946
MghData(std::vector< uint8_t > curv_data)
constructor to create MghData from MRI_UCHAR (uint8_t) data.
Definition: libfs.h:2269
Mesh(std::vector< float > cvertices, std::vector< int32_t > cfaces)
Construct a Mesh from the given vertices and faces.
Definition: libfs.h:731
std::vector< size_t > vertex_regions() const
Compute the region indices in the Colortable for all vertices in this brain surface parcellation...
Definition: libfs.h:2190
std::vector< std::vector< bool > > as_adjmatrix() const
Return adjacency matrix representation of this mesh.
Definition: libfs.h:917
const T & at(const unsigned int i1, const unsigned int i2, const unsigned int i3, const unsigned int i4) const
Get the value at the given 4D position.
Definition: libfs.h:2315
Array4D(Mgh *mgh)
Constructor for creating an empty 4D array based on dimensions specified in the header of an fs::Mgh...
Definition: libfs.h:2309
unsigned int d1
size of data along 1st dimension
Definition: libfs.h:2336
std::string to_ply() const
Return string representing the mesh in PLY format. Overload that works without passing a color vector...
Definition: libfs.h:1876
The colortable from an Annot file, can be used for parcellations and integer labels. Typically each index (in all fields) describes a brain region.
Definition: libfs.h:2070
const int MRI_FLOAT
MRI data type representing a 32 bit float.
Definition: libfs.h:695
void write_surf(std::vector< float > vertices, std::vector< int32_t > faces, std::ostream &os)
Write a mesh to a stream in FreeSurfer surf format.
Definition: libfs.h:3397
std::vector< std::vector< size_t > > as_adjlist(const bool via_matrix=true) const
Return adjacency list representation of this mesh.
Definition: libfs.h:985
static fs::Mesh construct_pyramid()
Construct and return a simple pyramidal mesh.
Definition: libfs.h:797
std::vector< float > smooth_pvd_nn(const std::vector< float > pvd, const size_t num_iter=1, const bool via_matrix=true, const bool with_nan=true, const bool detect_nan=true) const
Smooth given per-vertex data using nearest neighbor smoothing.
Definition: libfs.h:1044
std::vector< int32_t > id
internal region index
Definition: libfs.h:2072
void write_mesh(const Mesh &mesh, const std::string &filename)
Write a mesh to a file in different formats.
Definition: libfs.h:3611
std::vector< int32_t > region_vertices(int32_t region_label) const
Get all vertices of a region given by label in the brain surface parcellation. Returns an integer vec...
Definition: libfs.h:2142
std::vector< short > data_mri_short
data of type MRI_SHORT, check the dtype to see whether this is relevant for this instance.
Definition: libfs.h:2276
const int MRI_INT
MRI data type representing a 32 bit signed integer.
Definition: libfs.h:692
static void from_obj(Mesh *mesh, std::istream *is)
Read a brainmesh from a Wavefront object format stream.
Definition: libfs.h:1345
Curv(std::vector< float > curv_data)
Construct a Curv instance from the given per-vertex data.
Definition: libfs.h:2047
unsigned int d3
size of data along 3rd dimension
Definition: libfs.h:2338
Models a whole MGH file.
Definition: libfs.h:2280
size_t num_vertices() const
Get the number of vertices of this parcellation (or the associated surface).
Definition: libfs.h:2178
int32_t num_values_per_vertex
The number of values per vertex, stored in this file. Almost all apps (including FreeSurfer itself) o...
Definition: libfs.h:2066
void write_surf(const Mesh &mesh, const std::string &filename)
Write a mesh to a binary file in FreeSurfer surf format.
Definition: libfs.h:3455
void str_to_file(const std::string &filename, const std::string rep)
Write the given text representation (any string) to a file.
Definition: libfs.h:419
void read_annot(Annot *annot, std::istream *is)
Read a FreeSurfer annotation or brain surface parcellation from an annot stream.
Definition: libfs.h:2897
int32_t num_vertices
The number of vertices of the mesh to which this belongs. Can be deduced from length of 'data'...
Definition: libfs.h:2063
std::vector< float > vertex_coords(const size_t vertex) const
Get all coordinates of the vertex, given by its index.
Definition: libfs.h:1832
static void from_off(Mesh *mesh, std::istream *is, const std::string &source_filename="")
Read a brainmesh from an Object File format (OFF) stream.
Definition: libfs.h:1474
std::vector< int32_t > face_vertices(const size_t face) const
Get all vertex indices of the face, given by its index.
Definition: libfs.h:1808
Mgh(std::vector< float > curv_data)
Definition: libfs.h:2290
std::vector< std::string > read_subjectsfile(const std::string &filename)
Read a vector of subject identifiers from a FreeSurfer subjects file.
Definition: libfs.h:2417
std::vector< float > value
the value of the label, can represent continuous data like a p-value, or sometimes simply 1...
Definition: libfs.h:3361
std::vector< int32_t > r
red channel of RGBA color
Definition: libfs.h:2074
void read_mgh(Mgh *mgh, const std::string &filename)
Read a FreeSurfer volume file in MGH format into the given Mgh struct.
Definition: libfs.h:2371
void to_ply_file(const std::string &filename, const std::vector< uint8_t > col) const
Export this mesh to a file in Stanford PLY format with vertex colors.
Definition: libfs.h:1956
std::unordered_set< std::tuple< size_t, size_t >, _tupleHashFunction > edge_set
Datastructure for storing, and quickly querying the existence of, mesh edges.
Definition: libfs.h:943
size_t num_faces() const
Return the number of faces in this mesh.
Definition: libfs.h:1770
void write_label(const Label &label, std::ostream &os)
Write label data to a stream.
Definition: libfs.h:3557
std::vector< int > vertex
vertex indices for the data in this label if it is a surface label. These are indices into the vertic...
Definition: libfs.h:3357
std::string to_ply(const std::vector< uint8_t > col) const
Return string representing the mesh in PLY format.
Definition: libfs.h:1892
std::vector< std::string > vertex_region_names() const
Compute the region names in the Colortable for all vertices in this brain surface parcellation...
Definition: libfs.h:2210
std::vector< uint8_t > vertex_colors(bool alpha=false) const
Get the vertex colors as an array of uchar values, 3 consecutive values are the red, green and blue channel values for a single vertex.
Definition: libfs.h:2157
static fs::Mesh construct_cube()
Construct and return a simple cube mesh.
Definition: libfs.h:760
std::vector< int32_t > data_mri_int
data of type MRI_INT, check the dtype to see whether this is relevant for this instance.
Definition: libfs.h:2273
void read_mgh(Mgh *mgh, std::istream *is)
Read MGH data from a stream.
Definition: libfs.h:2440
MghData(std::vector< float > curv_data)
constructor to create MghData from MRI_FLOAT (float) data.
Definition: libfs.h:2271
MghData(std::vector< short > curv_data)
constructor to create MghData from MRI_SHORT (short) data.
Definition: libfs.h:2270
const std::string LOGTAG_ERROR
Logging threshold for error messages.
Definition: libfs.h:178
Mesh()
Construct an empty Mesh.
Definition: libfs.h:745
std::pair< std::unordered_map< int32_t, int32_t >, fs::Mesh > submesh_vertex(const std::vector< int32_t > &old_vertex_indices, const bool mapdir_fulltosubmesh=false) const
Compute a new mesh that is a submesh of this mesh, based on a subset of the vertices of this mesh...
Definition: libfs.h:1254
std::vector< uint8_t > data_mri_uchar
data of type MRI_UCHAR, check the dtype to see whether this is relevant for this instance.
Definition: libfs.h:2274
Label(std::vector< int > vertices)
Construct a Label from the given vertices / voxel numbers.
Definition: libfs.h:3348
static std::vector< std::vector< size_t > > extend_adj(const std::vector< std::vector< size_t >> mesh_adj, const size_t extend_by=1, std::vector< std::vector< size_t >> mesh_adj_ext=std::vector< std::vector< size_t >>())
Extend mesh neighborhoods based on mesh adjacency representation.
Definition: libfs.h:1188
void to_obj_file(const std::string &filename) const
Export this mesh to a file in Wavefront OBJ format.
Definition: libfs.h:1233
void read_surf(Mesh *surface, const std::string &filename)
Read a brain mesh from a file in binary FreeSurfer 'surf' format into the given Mesh instance...
Definition: libfs.h:2709
Curv()
Construct an empty Curv instance.
Definition: libfs.h:2054
std::string fullpath(std::initializer_list< std::string > path_components, std::string path_sep=std::string("/"))
Construct a UNIX file system path from the given path_components.
Definition: libfs.h:372
std::vector< int32_t > region_vertices(const std::string ®ion_name) const
Get all vertices of a region given by name in the brain surface parcellation. Returns an integer vect...
Definition: libfs.h:2126
void to_off_file(const std::string &filename, const std::vector< uint8_t > col) const
Export this mesh to a file in OFF format with vertex colors (COFF).
Definition: libfs.h:2036
void read_mesh(Mesh *surface, const std::string &filename)
Read a triangular mesh from a surf, obj, or ply file into the given Mesh instance.
Definition: libfs.h:2760
int32_t get_region_idx(const std::string &query_name) const
Get the index of a region in the Colortable by region name. Returns a negative value if the region is...
Definition: libfs.h:2092
int32_t num_faces
The number of faces of the mesh to which this belongs, typically irrelevant and ignored.
Definition: libfs.h:2057
std::vector< float > data_mri_float
data of type MRI_FLOAT, check the dtype to see whether this is relevant for this instance.
Definition: libfs.h:2275
unsigned int num_values() const
Get number of values/voxels.
Definition: libfs.h:2331
Colortable colortable
A Colortable defining the regions (most importantly, the region name and visualization color)...
Definition: libfs.h:2123
MghHeader header
Header for this MGH instance.
Definition: libfs.h:2282
void log(std::string const &message, std::string const loglevel="INFO")
Log a message, goes to stdout.
Definition: libfs.h:195
const float & vm_at(const size_t i, const size_t j) const
Retrieve a single (x, y, or z) coordinate of a vertex, treating the vertices vector as an nx3 matrix...
Definition: libfs.h:1858
std::vector< T > vflatten(std::vector< std::vector< T >> values)
Flatten 2D vector.
Definition: libfs.h:273
Label(std::vector< int > vertices, std::vector< float > values)
Construct a Label from the given vertices / voxel numbers and values.
Definition: libfs.h:3337
std::vector< int32_t > a
alpha channel of RGBA color
Definition: libfs.h:2077
const std::string LOGTAG_CRITICAL
Logging threshold for critical messages.
Definition: libfs.h:175
int32_t get_region_idx(int32_t query_label) const
Get the index of a region in the Colortable by label. Returns a negative value if the region is not f...
Definition: libfs.h:2105
Label()
Default constructor for a label.
Definition: libfs.h:3334
static fs::Mesh construct_grid(const size_t nx=4, const size_t ny=5, const float distx=1.0, const float disty=1.0)
Construct and return a simple planar grid mesh.
Definition: libfs.h:830
std::vector< int32_t > faces
n x 3 vector of the 3 vertex indices for the n triangles or faces. The 3 vertices of a single face fo...
Definition: libfs.h:748
void to_off_file(const std::string &filename) const
Export this mesh to a file in OFF format.
Definition: libfs.h:2029
std::vector< int32_t > vertex_labels
The label code for each vertex, defining the region it belongs to. Check in the Colortable for a regi...
Definition: libfs.h:2122
MghData(Curv curv)
constructor to create MghData from a Curv instance
Definition: libfs.h:2272
std::vector< float > coord_z
z coordinates of the vertices in case of a surface label, or voxels coordinates for a volume label...
Definition: libfs.h:3360
Array4D(unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4)
Constructor for creating an empty 4D array of the given dimensions.
Definition: libfs.h:2303
MghData(std::vector< int32_t > curv_data)
constructor to create MghData from MRI_INT (int32_t) data.
Definition: libfs.h:2268
std::vector< float > read_desc_data(const std::string &filename)
Read per-vertex brain morphometry data from a FreeSurfer curv format or MGH format file...
Definition: libfs.h:3003
Mgh()
Empty default constuctor.
Definition: libfs.h:2284
std::string to_off() const
Return string representing the mesh in OFF format. Overload that works without passing a color vector...
Definition: libfs.h:1969
std::vector< std::string > name
region name
Definition: libfs.h:2073
MghData data
4D data for this MGH instance.
Definition: libfs.h:2283
unsigned int d4
size of data along 4th dimension
Definition: libfs.h:2339
size_t num_vertices() const
Return the number of vertices in this mesh.
Definition: libfs.h:1756
void read_mgh_header(MghHeader *, const std::string &)
Read the header of a FreeSurfer volume file in MGH format into the given MghHeader struct...
Definition: libfs.h:2584