12 #include <unordered_set> 13 #include <unordered_map> 20 #define LIBFS_VERSION "0.4.1" 21 #define LIBFS_VERISION_MAJOR 0 # deprecated, use LIBFS_VERSION_MAJOR instead 22 #define LIBFS_VERISION_MINOR 4 # deprecated, use LIBFS_VERSION_MINOR instead 23 #define LIBFS_VERISION_PATCH 1 # deprecated, use LIBFS_VERSION_PATCH instead 24 #define LIBFS_VERSION_MAJOR 0 25 #define LIBFS_VERSION_MINOR 4 26 #define LIBFS_VERSION_PATCH 1 33 #define LIBFS_MAX_ALLOC_BYTES_DEFAULT (2ULL * 1024ULL * 1024ULL * 1024ULL) 36 #ifndef LIBFS_MAX_ALLOC_BYTES 37 #define LIBFS_MAX_ALLOC_BYTES LIBFS_MAX_ALLOC_BYTES_DEFAULT 41 #ifndef LIBFS_MAX_STRING_LENGTH 42 #define LIBFS_MAX_STRING_LENGTH 4096 46 #ifndef LIBFS_MAX_COLORTABLE_ENTRIES 47 #define LIBFS_MAX_COLORTABLE_ENTRIES 10000 116 #define LIBFS_APPTAG "[libfs] " 120 #define LIBFS_DBG_WARNING 123 #ifdef LIBFS_DBG_NONE 124 #undef LIBFS_DBG_WARNING 127 #ifdef LIBFS_DBG_CRITICAL 128 #undef LIBFS_DBG_WARNING 131 #ifdef LIBFS_DBG_ERROR 132 #undef LIBFS_DBG_WARNING 137 #ifdef LIBFS_DBG_EXCESSIVE 138 #define LIBFS_DBG_VERBOSE 141 #ifdef LIBFS_DBG_VERBOSE 142 #define LIBFS_DBG_INFO 145 #ifdef LIBFS_DBG_INFO 146 #define LIBFS_DBG_WARNING 149 #ifdef LIBFS_DBG_WARNING 150 #define LIBFS_DBG_ERROR 153 #ifdef LIBFS_DBG_ERROR 154 #define LIBFS_DBG_CRITICAL 168 tm _localtime(
const std::time_t &time)
171 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) 172 ::localtime_s(&tm_snapshot, &time);
174 ::localtime_r(&time, &tm_snapshot);
187 std::string
time_tag(std::chrono::system_clock::time_point t)
189 auto as_time_t = std::chrono::system_clock::to_time_t(t);
191 char time_buffer[64];
193 tm = _localtime(as_time_t);
194 if (std::strftime(time_buffer,
sizeof(time_buffer),
"%F %T", &tm))
196 return std::string{time_buffer};
198 throw std::runtime_error(
"Failed to get current date as string");
222 inline void log(std::string
const &message, std::string
const loglevel =
"INFO")
224 std::cout << LIBFS_APPTAG <<
"[" << loglevel <<
"] [" <<
fs::util::time_tag(std::chrono::system_clock::now()) <<
"] " << message <<
"\n";
231 inline bool safe_multiply(
size_t a,
size_t b,
size_t &result)
233 if (a == 0 || b == 0)
238 if (a > std::numeric_limits<size_t>::max() / b)
250 inline bool check_alloc(
size_t num_elements,
size_t bytes_per_element)
252 size_t total_bytes = 0;
253 if (!safe_multiply(num_elements, bytes_per_element, total_bytes))
266 inline size_t get_file_size(
const std::string &filename)
268 std::ifstream ifs(filename, std::ios::binary | std::ios::ate);
273 std::streampos end = ifs.tellg();
278 return static_cast<size_t>(end);
283 inline bool is_finite_float(
float value)
285 return !std::isnan(value) && !std::isinf(value);
298 inline bool ends_with(std::string
const &value, std::string
const &suffix)
300 if (suffix.size() > value.size())
302 return std::equal(suffix.rbegin(), suffix.rend(), value.rbegin());
313 inline bool ends_with(std::string
const &value, std::initializer_list<std::string> suffixes)
315 for (
auto suffix : suffixes)
317 if (ends_with(value, suffix))
337 template <
typename T>
338 std::vector<std::vector<T>> v2d(std::vector<T> values,
size_t num_cols)
340 std::vector<std::vector<T>> result;
341 for (std::size_t i = 0; i < values.size(); ++i)
343 if (i % num_cols == 0)
345 result.resize(result.size() + 1);
347 result[i / num_cols].push_back(values[i]);
362 template <
typename T>
363 std::vector<T>
vflatten(std::vector<std::vector<T>> values)
365 size_t total_size = 0;
366 for (std::size_t i = 0; i < values.size(); i++)
368 total_size += values[i].size();
371 std::vector<T> result = std::vector<T>(total_size);
373 for (std::size_t i = 0; i < values.size(); i++)
375 for (std::size_t j = 0; j < values[i].size(); j++)
377 result[cur_idx] = values[i][j];
394 inline bool starts_with(std::string
const &value, std::string
const &prefix)
396 if (prefix.length() > value.length())
398 return value.rfind(prefix, 0) == 0;
411 inline bool starts_with(std::string
const &value, std::initializer_list<std::string> prefixes)
413 for (
auto prefix : prefixes)
415 if (starts_with(value, prefix))
436 if (FILE *file = fopen(name.c_str(),
"r"))
462 std::string
fullpath(std::initializer_list<std::string> path_components, std::string path_sep = std::string(
"/"))
465 if (path_components.size() == 0)
467 throw std::invalid_argument(
"The 'path_components' must not be empty.");
471 std::string comp_mod;
473 for (
auto comp : path_components)
478 if (starts_with(comp, path_sep))
480 comp_mod = comp.substr(1, comp.size() - 1);
484 if (ends_with(comp_mod, path_sep))
486 comp_mod = comp_mod.substr(0, comp_mod.size() - 1);
490 if (idx < path_components.size() - 1)
509 void str_to_file(
const std::string &filename,
const std::string rep)
512 ofs.open(filename, std::ofstream::out);
513 #ifdef LIBFS_DBG_VERBOSE 514 std::cout << LIBFS_APPTAG <<
"Opening file '" << filename <<
"' for writing.\n";
523 throw std::runtime_error(
"Unable to open file '" + filename +
"' for writing.\n");
565 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)
567 std::vector<uint8_t> colors;
572 colors.reserve(data.size() * 3);
576 static const float lut[768] = {
577 0.267004, 0.004874, 0.329415, 0.26851, 0.009605, 0.335427, 0.269944, 0.014625,
578 0.341379, 0.271305, 0.019942, 0.347269, 0.272594, 0.025563, 0.353093, 0.273809,
579 0.031497, 0.358853, 0.274952, 0.037752, 0.364543, 0.276022, 0.044167, 0.370164,
580 0.277018, 0.050344, 0.375715, 0.277941, 0.056324, 0.381191, 0.278791, 0.062145,
581 0.386592, 0.279566, 0.067836, 0.391917, 0.280267, 0.073417, 0.397163, 0.280894,
582 0.078907, 0.402329, 0.281446, 0.08432, 0.407414, 0.281924, 0.089666, 0.412415,
583 0.282327, 0.094955, 0.417331, 0.282656, 0.100196, 0.42216, 0.28291, 0.105393,
584 0.426902, 0.283091, 0.110553, 0.431554, 0.283197, 0.11568, 0.436115, 0.283229,
585 0.120777, 0.440584, 0.283187, 0.125848, 0.44496, 0.283072, 0.130895, 0.449241,
586 0.282884, 0.13592, 0.453427, 0.282623, 0.140926, 0.457517, 0.28229, 0.145912,
587 0.46151, 0.281887, 0.150881, 0.465405, 0.281412, 0.155834, 0.469201, 0.280868,
588 0.160771, 0.472899, 0.280255, 0.165693, 0.476498, 0.279574, 0.170599, 0.479997,
589 0.278826, 0.17549, 0.483397, 0.278012, 0.180367, 0.486697, 0.277134, 0.185228,
590 0.489898, 0.276194, 0.190074, 0.493001, 0.275191, 0.194905, 0.496005, 0.274128,
591 0.199721, 0.498911, 0.273006, 0.20452, 0.501721, 0.271828, 0.209303, 0.504434,
592 0.270595, 0.214069, 0.507052, 0.269308, 0.218818, 0.509577, 0.267968, 0.223549,
593 0.512008, 0.26658, 0.228262, 0.514349, 0.265145, 0.232956, 0.516599, 0.263663,
594 0.237631, 0.518762, 0.262138, 0.242286, 0.520837, 0.260571, 0.246922, 0.522828,
595 0.258965, 0.251537, 0.524736, 0.257322, 0.25613, 0.526563, 0.255645, 0.260703,
596 0.528312, 0.253935, 0.265254, 0.529983, 0.252194, 0.269783, 0.531579, 0.250425,
597 0.27429, 0.533103, 0.248629, 0.278775, 0.534556, 0.246811, 0.283237, 0.535941,
598 0.244972, 0.287675, 0.53726, 0.243113, 0.292092, 0.538516, 0.241237, 0.296485,
599 0.539709, 0.239346, 0.300855, 0.540844, 0.237441, 0.305202, 0.541921, 0.235526,
600 0.309527, 0.542944, 0.233603, 0.313828, 0.543914, 0.231674, 0.318106, 0.544834,
601 0.229739, 0.322361, 0.545706, 0.227802, 0.326594, 0.546532, 0.225863, 0.330805,
602 0.547314, 0.223925, 0.334994, 0.548053, 0.221989, 0.339161, 0.548752, 0.220057,
603 0.343307, 0.549413, 0.21813, 0.347432, 0.550038, 0.21621, 0.351535, 0.550627,
604 0.214298, 0.355619, 0.551184, 0.212395, 0.359683, 0.55171, 0.210503, 0.363727,
605 0.552206, 0.208623, 0.367752, 0.552675, 0.206756, 0.371758, 0.553117, 0.204903,
606 0.375746, 0.553533, 0.203063, 0.379716, 0.553925, 0.201239, 0.38367, 0.554294,
607 0.19943, 0.387607, 0.554642, 0.197636, 0.391528, 0.554969, 0.19586, 0.395433,
608 0.555276, 0.1941, 0.399323, 0.555565, 0.192357, 0.403199, 0.555836, 0.190631,
609 0.407061, 0.556089, 0.188923, 0.41091, 0.556326, 0.187231, 0.414746, 0.556547,
610 0.185556, 0.41857, 0.556753, 0.183898, 0.422383, 0.556944, 0.182256, 0.426184,
611 0.55712, 0.180629, 0.429975, 0.557282, 0.179019, 0.433756, 0.55743, 0.177423,
612 0.437527, 0.557565, 0.175841, 0.44129, 0.557685, 0.174274, 0.445044, 0.557792,
613 0.172719, 0.448791, 0.557885, 0.171176, 0.45253, 0.557965, 0.169646, 0.456262,
614 0.55803, 0.168126, 0.459988, 0.558082, 0.166617, 0.463708, 0.558119, 0.165117,
615 0.467423, 0.558141, 0.163625, 0.471133, 0.558148, 0.162142, 0.474838, 0.55814,
616 0.160665, 0.47854, 0.558115, 0.159194, 0.482237, 0.558073, 0.157729, 0.485932,
617 0.558013, 0.15627, 0.489624, 0.557936, 0.154815, 0.493313, 0.55784, 0.153364,
618 0.497, 0.557724, 0.151918, 0.500685, 0.557587, 0.150476, 0.504369, 0.55743,
619 0.149039, 0.508051, 0.55725, 0.147607, 0.511733, 0.557049, 0.14618, 0.515413,
620 0.556823, 0.144759, 0.519093, 0.556572, 0.143343, 0.522773, 0.556295, 0.141935,
621 0.526453, 0.555991, 0.140536, 0.530132, 0.555659, 0.139147, 0.533812, 0.555298,
622 0.13777, 0.537492, 0.554906, 0.136408, 0.541173, 0.554483, 0.135066, 0.544853,
623 0.554029, 0.133743, 0.548535, 0.553541, 0.132444, 0.552216, 0.553018, 0.131172,
624 0.555899, 0.552459, 0.129933, 0.559582, 0.551864, 0.128729, 0.563265, 0.551229,
625 0.127568, 0.566949, 0.550556, 0.126453, 0.570633, 0.549841, 0.125394, 0.574318,
626 0.549086, 0.124395, 0.578002, 0.548287, 0.123463, 0.581687, 0.547445, 0.122606,
627 0.585371, 0.546557, 0.121831, 0.589055, 0.545623, 0.121148, 0.592739, 0.544641,
628 0.120565, 0.596422, 0.543611, 0.120092, 0.600104, 0.54253, 0.119738, 0.603785,
629 0.5414, 0.119512, 0.607464, 0.540218, 0.119423, 0.611141, 0.538982, 0.119483,
630 0.614817, 0.537692, 0.119699, 0.61849, 0.536347, 0.120081, 0.622161, 0.534946,
631 0.120638, 0.625828, 0.533488, 0.12138, 0.629492, 0.531973, 0.122312, 0.633153,
632 0.530398, 0.123444, 0.636809, 0.528763, 0.12478, 0.640461, 0.527068, 0.126326,
633 0.644107, 0.525311, 0.128087, 0.647749, 0.523491, 0.130067, 0.651384, 0.521608,
634 0.132268, 0.655014, 0.519661, 0.134692, 0.658636, 0.517649, 0.137339, 0.662252,
635 0.515571, 0.14021, 0.665859, 0.513427, 0.143303, 0.669459, 0.511215, 0.146616,
636 0.67305, 0.508936, 0.150148, 0.676631, 0.506589, 0.153894, 0.680203, 0.504172,
637 0.157851, 0.683765, 0.501686, 0.162016, 0.687316, 0.499129, 0.166383, 0.690856,
638 0.496502, 0.170948, 0.694384, 0.493803, 0.175707, 0.6979, 0.491033, 0.180653,
639 0.701402, 0.488189, 0.185783, 0.704891, 0.485273, 0.19109, 0.708366, 0.482284,
640 0.196571, 0.711827, 0.479221, 0.202219, 0.715272, 0.476084, 0.20803, 0.718701,
641 0.472873, 0.214, 0.722114, 0.469588, 0.220124, 0.725509, 0.466226, 0.226397,
642 0.728888, 0.462789, 0.232815, 0.732247, 0.459277, 0.239374, 0.735588, 0.455688,
643 0.24607, 0.73891, 0.452024, 0.252899, 0.742211, 0.448284, 0.259857, 0.745492,
644 0.444467, 0.266941, 0.748751, 0.440573, 0.274149, 0.751988, 0.436601, 0.281477,
645 0.755203, 0.432552, 0.288921, 0.758394, 0.428426, 0.296479, 0.761561, 0.424223,
646 0.304148, 0.764704, 0.419943, 0.311925, 0.767822, 0.415586, 0.319809, 0.770914,
647 0.411152, 0.327796, 0.77398, 0.40664, 0.335885, 0.777018, 0.402049, 0.344074,
648 0.780029, 0.397381, 0.35236, 0.783011, 0.392636, 0.360741, 0.785964, 0.387814,
649 0.369214, 0.788888, 0.382914, 0.377779, 0.791781, 0.377939, 0.386433, 0.794644,
650 0.372886, 0.395174, 0.797475, 0.367757, 0.404001, 0.800275, 0.362552, 0.412913,
651 0.803041, 0.357269, 0.421908, 0.805774, 0.35191, 0.430983, 0.808473, 0.346476,
652 0.440137, 0.811138, 0.340967, 0.449368, 0.813768, 0.335384, 0.458674, 0.816363,
653 0.329727, 0.468053, 0.818921, 0.323998, 0.477504, 0.821444, 0.318195, 0.487026,
654 0.823929, 0.312321, 0.496615, 0.826376, 0.306377, 0.506271, 0.828786, 0.300362,
655 0.515992, 0.831158, 0.294279, 0.525776, 0.833491, 0.288127, 0.535621, 0.835785,
656 0.281908, 0.545524, 0.838039, 0.275626, 0.555484, 0.840254, 0.269281, 0.565498,
657 0.84243, 0.262877, 0.575563, 0.844566, 0.256415, 0.585678, 0.846661, 0.249897,
658 0.595839, 0.848717, 0.243329, 0.606045, 0.850733, 0.236712, 0.616293, 0.852709,
659 0.230052, 0.626579, 0.854645, 0.223353, 0.636902, 0.856542, 0.21662, 0.647257,
660 0.8584, 0.209861, 0.657642, 0.860219, 0.203082, 0.668054, 0.861999, 0.196293,
661 0.678489, 0.863742, 0.189503, 0.688944, 0.865448, 0.182725, 0.699415, 0.867117,
662 0.175971, 0.709898, 0.868751, 0.169257, 0.720391, 0.87035, 0.162603, 0.730889,
663 0.871916, 0.156029, 0.741388, 0.873449, 0.149561, 0.751884, 0.874951, 0.143228,
664 0.762373, 0.876424, 0.137064, 0.772852, 0.877868, 0.131109, 0.783315, 0.879285,
665 0.125405, 0.79376, 0.880678, 0.120005, 0.804182, 0.882046, 0.114965, 0.814576,
666 0.883393, 0.110347, 0.82494, 0.88472, 0.106217, 0.83527, 0.886029, 0.102646,
667 0.845561, 0.887322, 0.099702, 0.85581, 0.888601, 0.097452, 0.866013, 0.889868,
668 0.095953, 0.876168, 0.891125, 0.09525, 0.886271, 0.892374, 0.095374, 0.89632,
669 0.893616, 0.096335, 0.906311, 0.894855, 0.098125, 0.916242, 0.896091, 0.100717,
670 0.926106, 0.89733, 0.104071, 0.935904, 0.89857, 0.108131, 0.945636, 0.899815,
671 0.112838, 0.9553, 0.901065, 0.118128, 0.964894, 0.902323, 0.123941, 0.974417,
672 0.90359, 0.130215, 0.983868, 0.904867, 0.136897, 0.993248, 0.906157, 0.143936,
677 bool auto_min = std::isnan(vmin);
678 bool auto_max = std::isnan(vmax);
681 float data_min = NAN;
682 float data_max = NAN;
683 bool have_finite =
false;
684 for (
size_t i = 0; i < data.size(); i++)
686 if (std::isnan(data[i]))
698 if (data[i] < data_min)
702 if (data[i] > data_max)
709 float lo = auto_min ? data_min : vmin;
710 float hi = auto_max ? data_max : vmax;
712 if (!auto_min && !auto_max)
716 throw std::invalid_argument(
"In viridis(): 'vmin' must not be greater than 'vmax'.");
723 for (
size_t i = 0; i < data.size(); i++)
725 colors.push_back(nan_r);
726 colors.push_back(nan_g);
727 colors.push_back(nan_b);
732 bool constant = (hi <= lo);
734 for (
size_t i = 0; i < data.size(); i++)
736 if (std::isnan(data[i]))
738 colors.push_back(nan_r);
739 colors.push_back(nan_g);
740 colors.push_back(nan_b);
751 t = (data[i] - lo) / (hi - lo);
752 if (t < 0.0f) { t = 0.0f; }
753 if (t > 1.0f) { t = 1.0f; }
756 float pos = t * (n - 1);
757 int idx0 =
static_cast<int>(pos);
758 if (idx0 < 0) { idx0 = 0; }
759 if (idx0 > n - 2) { idx0 = n - 2; }
761 float frac = pos -
static_cast<float>(idx0);
763 for (
int c = 0; c < 3; c++)
765 float val = lut[idx0 * 3 + c] * (1.0f - frac) + lut[idx1 * 3 + c] * frac;
766 int iv =
static_cast<int>(val * 255.0f + 0.5f);
767 if (iv < 0) { iv = 0; }
768 if (iv > 255) { iv = 255; }
769 colors.push_back(static_cast<uint8_t>(iv));
791 int _fread3(std::istream &);
792 template <
typename T>
793 T _freadt(std::istream &);
794 std::string _freadstringnewline(std::istream &);
795 std::string _freadfixedlengthstring(std::istream &,
size_t,
bool,
size_t);
796 bool _ends_with(std::string
const &fullString, std::string
const &ending);
797 size_t _vidx_2d(
size_t,
size_t,
size_t);
821 Mesh(std::vector<float> cvertices, std::vector<int32_t> cfaces)
823 vertices = cvertices;
828 Mesh(std::vector<std::vector<float>> cvertices, std::vector<std::vector<int32_t>> cfaces)
830 vertices = util::vflatten(cvertices);
831 faces = util::vflatten(cfaces);
861 mesh.
faces = {0, 2, 3,
895 mesh.
faces = {0, 2, 1,
920 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)
922 if (nx < 2 || ny < 2)
924 throw std::runtime_error(
"Parameters nx and ny must be at least 2.");
927 size_t num_vertices = nx * ny;
928 size_t num_faces = ((nx - 1) * (ny - 1)) * 2;
929 std::vector<float> vertices;
930 vertices.reserve(num_vertices * 3);
931 std::vector<int> faces;
932 faces.reserve(num_faces * 3);
935 float cur_x, cur_y, cur_z;
936 cur_x = cur_y = cur_z = 0.0;
937 for (
size_t i = 0; i < nx; i++)
939 for (
size_t j = 0; j < ny; j++)
941 vertices.push_back(cur_x);
942 vertices.push_back(cur_y);
943 vertices.push_back(cur_z);
950 for (
size_t i = 0; i < num_vertices; i++)
952 if ((i + 1) % ny == 0 || i >= num_vertices - ny)
958 faces.push_back(
int(i));
959 faces.push_back(
int(i + ny + 1));
960 faces.push_back(
int(i + 1));
962 faces.push_back(
int(i));
963 faces.push_back(
int(i + ny + 1));
964 faces.push_back(
int(i + ny));
984 std::stringstream objs;
985 for (
size_t vidx = 0; vidx < this->vertices.size(); vidx += 3)
987 objs <<
"v " << vertices[vidx] <<
" " << vertices[vidx + 1] <<
" " << vertices[vidx + 2] <<
"\n";
989 for (
size_t fidx = 0; fidx < this->faces.size(); fidx += 3)
991 objs <<
"f " << faces[fidx] + 1 <<
" " << faces[fidx + 1] + 1 <<
" " << faces[fidx + 2] + 1 <<
"\n";
1009 std::vector<std::vector<bool>> adjm = std::vector<std::vector<bool>>(this->num_vertices(), std::vector<bool>(this->num_vertices(),
false));
1010 for (
size_t fidx = 0; fidx < this->faces.size(); fidx += 3)
1012 adjm[faces[fidx]][faces[fidx + 1]] =
true;
1013 adjm[faces[fidx + 1]][faces[fidx]] =
true;
1014 adjm[faces[fidx + 1]][faces[fidx + 2]] =
true;
1015 adjm[faces[fidx + 2]][faces[fidx + 1]] =
true;
1016 adjm[faces[fidx + 2]][faces[fidx]] =
true;
1017 adjm[faces[fidx]][faces[fidx + 2]] =
true;
1023 struct _tupleHashFunction
1025 size_t operator()(
const std::tuple<size_t, size_t> &x)
const 1027 return std::get<0>(x) ^ std::get<1>(x);
1033 typedef std::unordered_set<std::tuple<size_t, size_t>, _tupleHashFunction>
edge_set;
1049 for (
size_t fidx = 0; fidx < this->faces.size(); fidx += 3)
1051 edges.insert(std::make_tuple(faces[fidx], faces[fidx + 1]));
1052 edges.insert(std::make_tuple(faces[fidx + 1], faces[fidx]));
1054 edges.insert(std::make_tuple(faces[fidx + 1], faces[fidx + 2]));
1055 edges.insert(std::make_tuple(faces[fidx + 2], faces[fidx + 1]));
1057 edges.insert(std::make_tuple(faces[fidx], faces[fidx + 2]));
1058 edges.insert(std::make_tuple(faces[fidx + 2], faces[fidx]));
1075 std::vector<std::vector<size_t>>
as_adjlist(
const bool via_matrix =
true)
const 1079 return (this->_as_adjlist_via_edgeset());
1081 std::vector<std::vector<bool>> adjm = this->as_adjmatrix();
1082 std::vector<std::vector<size_t>> adjl = std::vector<std::vector<size_t>>(this->num_vertices(), std::vector<size_t>());
1083 size_t nv = adjm.size();
1084 for (
size_t i = 0; i < nv; i++)
1086 for (
size_t j = i + 1; j < nv; j++)
1088 if (adjm[i][j] ==
true)
1090 adjl[i].push_back(j);
1091 adjl[j].push_back(i);
1108 std::vector<std::vector<size_t>> _as_adjlist_via_edgeset()
const 1110 edge_set edges = this->as_edgelist();
1111 std::vector<std::vector<size_t>> adjl = std::vector<std::vector<size_t>>(this->num_vertices(), std::vector<size_t>());
1112 for (
const std::tuple<size_t, size_t> &e : edges)
1114 adjl[std::get<0>(e)].push_back(std::get<1>(e));
1134 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 1137 const std::vector<std::vector<size_t>> adjlist = this->as_adjlist(via_matrix);
1157 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)
1159 assert(pvd.size() == mesh_adj.size());
1160 bool final_with_nan = with_nan;
1163 final_with_nan =
false;
1164 for (
size_t i = 0; i < pvd.size(); i++)
1166 if (std::isnan(pvd[i]))
1168 final_with_nan =
true;
1175 return fs::Mesh::_smooth_pvd_nn_nan(mesh_adj, pvd, num_iter);
1177 std::vector<float> current_pvd_source;
1178 std::vector<float> current_pvd_smoothed = std::vector<float>(pvd.size());
1182 for (
size_t i = 0; i < num_iter; i++)
1186 current_pvd_source = pvd;
1190 current_pvd_source = current_pvd_smoothed;
1192 for (
size_t v_idx = 0; v_idx < mesh_adj.size(); v_idx++)
1194 num_neigh = mesh_adj[v_idx].size();
1195 val_sum = current_pvd_source[v_idx] / (num_neigh + 1);
1196 for (
size_t neigh_rel_idx = 0; neigh_rel_idx < num_neigh; neigh_rel_idx++)
1198 val_sum += current_pvd_source[mesh_adj[v_idx][neigh_rel_idx]] / (num_neigh + 1);
1200 current_pvd_smoothed[v_idx] = val_sum;
1203 return current_pvd_smoothed;
1222 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)
1224 std::vector<float> current_pvd_source;
1225 std::vector<float> current_pvd_smoothed = std::vector<float>(pvd.size());
1229 size_t num_non_nan_values;
1231 for (
size_t i = 0; i < num_iter; i++)
1236 current_pvd_source = pvd;
1240 current_pvd_source = current_pvd_smoothed;
1243 for (
size_t v_idx = 0; v_idx < mesh_adj.size(); v_idx++)
1245 if (std::isnan(current_pvd_source[v_idx]))
1247 current_pvd_smoothed[v_idx] = NAN;
1250 val_sum = current_pvd_source[v_idx];
1251 num_non_nan_values = 1;
1252 num_neigh = mesh_adj[v_idx].size();
1253 for (
size_t neigh_rel_idx = 0; neigh_rel_idx < num_neigh; neigh_rel_idx++)
1255 neigh_val = current_pvd_source[mesh_adj[v_idx][neigh_rel_idx]];
1256 if (std::isnan(neigh_val))
1262 val_sum += neigh_val;
1263 num_non_nan_values++;
1266 current_pvd_smoothed[v_idx] = val_sum / (float)num_non_nan_values;
1269 return current_pvd_smoothed;
1278 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>>())
1280 size_t num_vertices = mesh_adj.size();
1281 if (mesh_adj_ext.size() == 0)
1283 mesh_adj_ext = mesh_adj;
1285 std::vector<size_t> neighborhood;
1286 std::vector<size_t> ext_neighborhood;
1287 for (
size_t ext_idx = 0; ext_idx < extend_by; ext_idx++)
1289 for (
size_t source_vert_idx = 0; source_vert_idx < num_vertices; source_vert_idx++)
1291 neighborhood = mesh_adj_ext[source_vert_idx];
1293 for (
size_t neigh_vert_rel_idx = 0; neigh_vert_rel_idx < neighborhood.size(); neigh_vert_rel_idx++)
1295 for (
size_t canidate_rel_idx = 0; canidate_rel_idx < mesh_adj[neighborhood[neigh_vert_rel_idx]].size(); canidate_rel_idx++)
1297 if (mesh_adj[neighborhood[neigh_vert_rel_idx]][canidate_rel_idx] != source_vert_idx)
1299 mesh_adj_ext[source_vert_idx].push_back(mesh_adj[neighborhood[neigh_vert_rel_idx]][canidate_rel_idx]);
1304 std::sort(mesh_adj_ext[source_vert_idx].begin(), mesh_adj_ext[source_vert_idx].end());
1305 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());
1308 return mesh_adj_ext;
1325 fs::util::str_to_file(filename, this->to_obj());
1344 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 1347 std::vector<float> new_vertices;
1348 std::vector<int> new_faces;
1349 std::unordered_map<int32_t, int32_t> vertex_index_map_full2submesh;
1350 int32_t new_vertex_idx = 0;
1351 for (
size_t i = 0; i < old_vertex_indices.size(); i++)
1353 vertex_index_map_full2submesh[old_vertex_indices[i]] = new_vertex_idx;
1354 new_vertices.push_back(this->vertices[
size_t(old_vertex_indices[i]) * 3]);
1355 new_vertices.push_back(this->vertices[
size_t(old_vertex_indices[i]) * 3 + 1]);
1356 new_vertices.push_back(this->vertices[
size_t(old_vertex_indices[i]) * 3 + 2]);
1362 for (
size_t i = 0; i < this->num_faces(); i++)
1364 face_v0 = this->faces[i * 3];
1365 face_v1 = this->faces[i * 3 + 1];
1366 face_v2 = this->faces[i * 3 + 2];
1367 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()))
1369 new_faces.push_back(vertex_index_map_full2submesh[face_v0]);
1370 new_faces.push_back(vertex_index_map_full2submesh[face_v1]);
1371 new_faces.push_back(vertex_index_map_full2submesh[face_v2]);
1375 submesh.
faces = new_faces;
1377 std::pair<std::unordered_map<int32_t, int32_t>,
fs::Mesh> result;
1378 if (!mapdir_fulltosubmesh)
1380 std::unordered_map<int32_t, int32_t> vertex_index_map_submesh2full;
1381 for (
auto const &pair : vertex_index_map_full2submesh)
1383 vertex_index_map_submesh2full[pair.second] = pair.first;
1385 result = std::pair<std::unordered_map<int32_t, int32_t>,
fs::Mesh>(vertex_index_map_submesh2full, submesh);
1389 result = std::pair<std::unordered_map<int32_t, int32_t>,
fs::Mesh>(vertex_index_map_full2submesh, submesh);
1401 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())
1404 if (submesh_to_orig_mapping.size() != data_submesh.size())
1406 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()) +
".");
1409 std::vector<float> data_orig_mesh(orig_mesh_num_vertices, fill_value);
1410 for (
size_t i = 0; i < data_submesh.size(); i++)
1412 auto got = submesh_to_orig_mapping.find(
int(i));
1413 if (got != submesh_to_orig_mapping.end())
1415 data_orig_mesh[got->second] = data_submesh[i];
1418 return (data_orig_mesh);
1440 std::vector<float> vertices;
1441 std::vector<int> faces;
1443 #ifdef LIBFS_DBG_INFO 1444 size_t num_lines_ignored = 0;
1447 while (std::getline(*is, line))
1450 std::istringstream iss(line);
1451 if (fs::util::starts_with(line,
"#"))
1457 if (fs::util::starts_with(line,
"v "))
1459 std::string elem_type_identifier;
1461 if (!(iss >> elem_type_identifier >> x >> y >> z))
1463 throw std::domain_error(
"Could not parse vertex line " + std::to_string(line_idx + 1) +
" of OBJ data, invalid format.\n");
1465 assert(elem_type_identifier ==
"v");
1466 vertices.push_back(x);
1467 vertices.push_back(y);
1468 vertices.push_back(z);
1470 else if (fs::util::starts_with(line,
"f "))
1472 std::string elem_type_identifier, v0raw, v1raw, v2raw;
1474 if (!(iss >> elem_type_identifier >> v0raw >> v1raw >> v2raw))
1476 throw std::domain_error(
"Could not parse face line " + std::to_string(line_idx + 1) +
" of OBJ data, invalid format.\n");
1478 assert(elem_type_identifier ==
"f");
1483 std::size_t found_v0 = v0raw.find(
"/");
1484 std::size_t found_v1 = v1raw.find(
"/");
1485 std::size_t found_v2 = v2raw.find(
"/");
1486 if (found_v0 != std::string::npos)
1488 v0raw = v0raw.substr(0, found_v0);
1490 if (found_v1 != std::string::npos)
1492 v1raw = v1raw.substr(0, found_v1);
1494 if (found_v2 != std::string::npos)
1496 v2raw = v0raw.substr(0, found_v2);
1498 v0 = std::stoi(v0raw);
1499 v1 = std::stoi(v1raw);
1500 v2 = std::stoi(v2raw);
1503 faces.push_back(v0 - 1);
1504 faces.push_back(v1 - 1);
1505 faces.push_back(v2 - 1);
1509 #ifdef LIBFS_DBG_INFO 1510 num_lines_ignored++;
1517 #ifdef LIBFS_DBG_INFO 1518 if (num_lines_ignored > 0)
1520 std::cout << LIBFS_APPTAG <<
"Ignored " << num_lines_ignored <<
" lines in Wavefront OBJ format mesh file.\n";
1524 mesh->
faces = faces;
1543 #ifdef LIBFS_DBG_INFO 1544 std::cout << LIBFS_APPTAG <<
"Reading brain mesh from Wavefront object format file " << filename <<
".\n";
1546 std::ifstream input(filename, std::fstream::in);
1547 if (input.is_open())
1554 throw std::runtime_error(
"Could not open Wavefront object format mesh file '" + filename +
"' for reading.\n");
1564 static void from_off(
Mesh *mesh, std::istream *is,
const std::string &source_filename =
"")
1567 std::string msg_source_file_part = source_filename.empty() ?
"" :
"'" + source_filename +
"'";
1571 int noncomment_line_idx = -1;
1573 std::vector<float> vertices;
1574 std::vector<int> faces;
1575 size_t num_vertices = 0;
1576 size_t num_faces = 0;
1577 size_t num_edges = 0;
1578 size_t num_verts_parsed = 0;
1579 size_t num_faces_parsed = 0;
1583 int num_verts_this_face, v0, v1, v2;
1585 while (std::getline(*is, line))
1588 std::istringstream iss(line);
1589 if (fs::util::starts_with(line,
"#"))
1595 noncomment_line_idx++;
1596 if (noncomment_line_idx == 0)
1598 std::string off_header_magic;
1599 if (!(iss >> off_header_magic))
1601 throw std::domain_error(
"Could not parse first header line " + std::to_string(line_idx + 1) +
" of OFF data, invalid format.\n");
1603 if (!(off_header_magic ==
"OFF" || off_header_magic ==
"COFF"))
1605 throw std::domain_error(
"OFF magic string invalid, file " + msg_source_file_part +
" not in OFF format.\n");
1609 else if (noncomment_line_idx == 1)
1611 if (!(iss >> num_vertices >> num_faces >> num_edges))
1613 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");
1619 if (num_verts_parsed < num_vertices)
1621 if (!(iss >> x >> y >> z))
1623 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");
1625 vertices.push_back(x);
1626 vertices.push_back(y);
1627 vertices.push_back(z);
1632 if (num_faces_parsed < num_faces)
1634 if (!(iss >> num_verts_this_face >> v0 >> v1 >> v2))
1636 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");
1638 if (num_verts_this_face != 3)
1640 throw std::domain_error(
"At OFF data " + msg_source_file_part +
" line " + std::to_string(line_idx + 1) +
": only triangular meshes supported.\n");
1642 faces.push_back(v0);
1643 faces.push_back(v1);
1644 faces.push_back(v2);
1651 if (num_verts_parsed < num_vertices)
1653 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");
1655 if (num_faces_parsed < num_faces)
1657 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");
1660 mesh->
faces = faces;
1679 #ifdef LIBFS_DBG_INFO 1680 std::cout << LIBFS_APPTAG <<
"Reading brain mesh from OFF format file " << filename <<
".\n";
1682 std::ifstream input(filename, std::fstream::in);
1683 if (input.is_open())
1690 throw std::runtime_error(
"Could not open Object file format (OFF) mesh file '" + filename +
"' for reading.\n");
1703 int noncomment_line_idx = -1;
1705 std::vector<float> vertices;
1706 std::vector<int> faces;
1708 bool in_header =
true;
1711 while (std::getline(*is, line))
1714 std::istringstream iss(line);
1715 if (fs::util::starts_with(line,
"comment"))
1721 noncomment_line_idx++;
1724 if (noncomment_line_idx == 0)
1727 throw std::domain_error(
"Invalid PLY file");
1729 else if (noncomment_line_idx == 1)
1731 if (line !=
"format ascii 1.0")
1732 throw std::domain_error(
"Unsupported PLY file format, only format 'format ascii 1.0' is supported.");
1735 if (line ==
"end_header")
1739 else if (fs::util::starts_with(line,
"element vertex"))
1741 std::string elem, elem_type_identifier;
1742 if (!(iss >> elem >> elem_type_identifier >> num_verts))
1744 throw std::domain_error(
"Could not parse element vertex line of PLY header, invalid format.\n");
1747 else if (fs::util::starts_with(line,
"element face"))
1749 std::string elem, elem_type_identifier;
1750 if (!(iss >> elem >> elem_type_identifier >> num_faces))
1752 throw std::domain_error(
"Could not parse element face line of PLY header, invalid format.\n");
1758 if (num_verts < 1 || num_faces < 1)
1760 throw std::domain_error(
"Invalid PLY file: missing element count lines of header.");
1763 if (vertices.size() < (size_t)num_verts * 3)
1766 if (!(iss >> x >> y >> z))
1768 throw std::domain_error(
"Could not parse vertex line " + std::to_string(line_idx) +
" of PLY data, invalid format.\n");
1770 vertices.push_back(x);
1771 vertices.push_back(y);
1772 vertices.push_back(z);
1776 if (faces.size() < (size_t)num_faces * 3)
1778 int verts_per_face, v0, v1, v2;
1779 if (!(iss >> verts_per_face >> v0 >> v1 >> v2))
1781 throw std::domain_error(
"Could not parse face line " + std::to_string(line_idx) +
" of PLY data, invalid format.\n");
1783 if (verts_per_face != 3)
1785 throw std::domain_error(
"Only triangular meshes are supported: PLY faces lines must contain exactly 3 vertex indices.\n");
1787 faces.push_back(v0);
1788 faces.push_back(v1);
1789 faces.push_back(v2);
1795 if (vertices.size() != (size_t)num_verts * 3)
1797 std::cerr <<
"PLY header mentions " << num_verts <<
" vertices, but found " << vertices.size() / 3 <<
".\n";
1799 if (faces.size() != (size_t)num_faces * 3)
1801 std::cerr <<
"PLY header mentions " << num_faces <<
" faces, but found " << faces.size() / 3 <<
".\n";
1804 mesh->
faces = faces;
1822 #ifdef LIBFS_DBG_INFO 1823 std::cout << LIBFS_APPTAG <<
"Reading brain mesh from PLY format file " << filename <<
".\n";
1825 std::ifstream input(filename, std::fstream::in);
1826 if (input.is_open())
1833 throw std::runtime_error(
"Could not open Stanford PLY format mesh file '" + filename +
"' for reading.\n");
1848 return (this->vertices.size() / 3);
1862 return (this->faces.size() / 3);
1877 const int32_t &
fm_at(
const size_t i,
const size_t j)
const 1879 size_t idx = _vidx_2d(i, j, 3);
1880 if (idx > this->faces.size() - 1)
1882 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");
1884 return (this->faces[idx]);
1900 if (face > this->num_faces() - 1)
1902 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");
1904 std::vector<int32_t> fv(3);
1905 fv[0] = this->fm_at(face, 0);
1906 fv[1] = this->fm_at(face, 1);
1907 fv[2] = this->fm_at(face, 2);
1924 if (vertex > this->num_vertices() - 1)
1926 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");
1928 std::vector<float> vc(3);
1929 vc[0] = this->vm_at(vertex, 0);
1930 vc[1] = this->vm_at(vertex, 1);
1931 vc[2] = this->vm_at(vertex, 2);
1948 const float &
vm_at(
const size_t i,
const size_t j)
const 1950 size_t idx = _vidx_2d(i, j, 3);
1951 if (idx > this->vertices.size() - 1)
1953 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");
1955 return (this->vertices[idx]);
1968 std::vector<uint8_t> empty_col;
1969 return (this->to_ply(empty_col));
1982 std::string
to_ply(
const std::vector<uint8_t> col)
const 1984 bool use_vertex_colors = col.size() != 0;
1985 std::stringstream plys;
1986 plys <<
"ply\nformat ascii 1.0\n";
1987 plys <<
"element vertex " << this->num_vertices() <<
"\n";
1988 plys <<
"property float x\nproperty float y\nproperty float z\n";
1989 if (use_vertex_colors)
1991 if (col.size() != this->vertices.size())
1993 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()) +
".");
1995 plys <<
"property uchar red\nproperty uchar green\nproperty uchar blue\n";
1997 plys <<
"element face " << this->num_faces() <<
"\n";
1998 plys <<
"property list uchar int vertex_index\n";
1999 plys <<
"end_header\n";
2001 #ifdef LIBFS_DBG_DEBUG 2002 fs::util::log(
"Writing " + std::to_string(this->vertices.size() / 3) +
" PLY format vertices.",
"INFO");
2005 for (
size_t vidx = 0; vidx < this->vertices.size(); vidx += 3)
2007 plys << vertices[vidx] <<
" " << vertices[vidx + 1] <<
" " << vertices[vidx + 2];
2008 if (use_vertex_colors)
2010 plys <<
" " << (int)col[vidx] <<
" " << (
int)col[vidx + 1] <<
" " << (int)col[vidx + 2];
2015 #ifdef LIBFS_DBG_DEBUG 2016 fs::util::log(
"Writing " + std::to_string(this->faces.size() / 3) +
" PLY format faces.",
"INFO");
2019 const int num_vertices_per_face = 3;
2020 for (
size_t fidx = 0; fidx < this->faces.size(); fidx += 3)
2022 plys << num_vertices_per_face <<
" " << faces[fidx] <<
" " << faces[fidx + 1] <<
" " << faces[fidx + 2] <<
"\n";
2024 return (plys.str());
2038 #ifdef LIBFS_DBG_INFO 2039 fs::util::log(
"Writing mesh to PLY file '" + filename +
"'.",
"INFO");
2041 fs::util::str_to_file(filename, this->to_ply());
2046 void to_ply_file(
const std::string &filename,
const std::vector<uint8_t> col)
const 2048 fs::util::str_to_file(filename, this->to_ply(col));
2061 std::vector<uint8_t> empty_col;
2062 return (this->to_off(empty_col));
2068 std::string
to_off(
const std::vector<uint8_t> col)
const 2070 bool use_vertex_colors = col.size() != 0;
2071 std::stringstream offs;
2072 if (use_vertex_colors)
2074 #ifdef LIBFS_DBG_INFO 2075 fs::util::log(
"Writing OFF representation of mesh with vertex colors.",
"INFO");
2077 if (col.size() != this->vertices.size())
2079 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()) +
".");
2085 #ifdef LIBFS_DBG_INFO 2086 fs::util::log(
"Writing OFF representation of mesh without vertex colors.",
"INFO");
2090 offs << this->num_vertices() <<
" " << this->num_faces() <<
" 0\n";
2092 for (
size_t vidx = 0; vidx < this->vertices.size(); vidx += 3)
2094 offs << vertices[vidx] <<
" " << vertices[vidx + 1] <<
" " << vertices[vidx + 2];
2095 if (use_vertex_colors)
2097 offs <<
" " << (int)col[vidx] <<
" " << (
int)col[vidx + 1] <<
" " << (int)col[vidx + 2] <<
" 255";
2102 const int num_vertices_per_face = 3;
2103 for (
size_t fidx = 0; fidx < this->faces.size(); fidx += 3)
2105 offs << num_vertices_per_face <<
" " << faces[fidx] <<
" " << faces[fidx + 1] <<
" " << faces[fidx + 2] <<
"\n";
2107 return (offs.str());
2121 fs::util::str_to_file(filename, this->to_off());
2126 void to_off_file(
const std::string &filename,
const std::vector<uint8_t> col)
const 2128 fs::util::str_to_file(filename, this->to_off(col));
2137 Curv(std::vector<float> curv_data) : num_faces(100000), num_vertices(0), num_values_per_vertex(1)
2140 num_vertices = int(data.size());
2144 Curv() : num_faces(100000), num_vertices(0), num_values_per_vertex(1) {}
2164 std::vector<int32_t>
r;
2165 std::vector<int32_t>
g;
2166 std::vector<int32_t>
b;
2167 std::vector<int32_t>
a;
2173 size_t num_ids = this->
id.size();
2174 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)
2176 std::cerr <<
"Inconsistent Colortable, vector sizes do not match.\n";
2184 for (
size_t i = 0; i < this->num_entries(); i++)
2186 if (this->name[i] == query_name)
2197 for (
size_t i = 0; i < this->num_entries(); i++)
2199 if (this->label[i] == query_label)
2218 int32_t region_idx = this->colortable.
get_region_idx(region_name);
2219 if (region_idx >= 0)
2221 return (this->region_vertices(this->colortable.
label[region_idx]));
2225 std::cerr <<
"No such region in annot, returning empty vector.\n";
2226 std::vector<int32_t> empty;
2234 std::vector<int32_t> reg_verts;
2235 for (
size_t i = 0; i < this->vertex_labels.size(); i++)
2237 if (this->vertex_labels[i] == region_label)
2239 reg_verts.push_back(
int(i));
2249 int num_channels = alpha ? 4 : 3;
2250 std::vector<uint8_t> col;
2251 col.reserve(this->num_vertices() * num_channels);
2252 std::vector<size_t> vertex_region_indices = this->vertex_regions();
2253 for (
size_t i = 0; i < this->num_vertices(); i++)
2255 col.push_back(this->colortable.
r[vertex_region_indices[i]]);
2256 col.push_back(this->colortable.
g[vertex_region_indices[i]]);
2257 col.push_back(this->colortable.
b[vertex_region_indices[i]]);
2260 col.push_back(this->colortable.
a[vertex_region_indices[i]]);
2270 size_t nv = this->vertex_indices.size();
2271 if (this->vertex_labels.size() != nv)
2273 throw std::runtime_error(
"Inconsistent annot, number of vertex indices and labels does not match.\n");
2282 std::vector<size_t> vert_reg;
2283 for (
size_t i = 0; i < this->num_vertices(); i++)
2285 vert_reg.push_back(0);
2287 for (
size_t region_idx = 0; region_idx < this->colortable.
num_entries(); region_idx++)
2289 std::vector<int32_t> reg_vertices = this->region_vertices(this->colortable.
label[region_idx]);
2290 for (
size_t region_vert_local_idx = 0; region_vert_local_idx < reg_vertices.size(); region_vert_local_idx++)
2292 int32_t region_vert_idx = reg_vertices[region_vert_local_idx];
2293 vert_reg[region_vert_idx] = region_idx;
2302 std::vector<std::string> region_names;
2303 std::vector<size_t> vertex_region_indices = this->vertex_regions();
2304 for (
size_t i = 0; i < this->num_vertices(); i++)
2306 region_names.push_back(this->colortable.
name[vertex_region_indices[i]]);
2308 return (region_names);
2318 dim1length = curv.
data.size();
2326 dim1length = curv_data.size();
2332 int32_t dim1length = 0;
2333 int32_t dim2length = 0;
2334 int32_t dim3length = 0;
2335 int32_t dim4length = 0;
2339 int16_t ras_good_flag = 0;
2344 return ((
size_t)dim1length * dim2length * dim3length * dim4length);
2358 MghData(std::vector<int32_t> curv_data) { data_mri_int = curv_data; }
2359 explicit MghData(std::vector<uint8_t> curv_data) { data_mri_uchar = curv_data; }
2360 explicit MghData(std::vector<short> curv_data) { data_mri_short = curv_data; }
2361 MghData(std::vector<float> curv_data) { data_mri_float = curv_data; }
2380 Mgh(std::vector<float> curv_data)
2396 Array4D(
unsigned int d1,
unsigned int d2,
unsigned int d3,
unsigned int d4) : d1(d1), d2(d2), d3(d3), d4(d4), data(_compute_4d_size(d1, d2, d3, d4)) {}
2403 Array4D(
MghHeader *mgh_header) : d1(_validate_mgh_dim(mgh_header->dim1length)), d2(_validate_mgh_dim(mgh_header->dim2length)), d3(_validate_mgh_dim(mgh_header->dim3length)), d4(_validate_mgh_dim(mgh_header->dim4length)), data(_compute_4d_size(d1, d2, d3, d4)) {}
2410 d1(_validate_mgh_dim(mgh->header.dim1length)), d2(_validate_mgh_dim(mgh->header.dim2length)), d3(_validate_mgh_dim(mgh->header.dim3length)), d4(_validate_mgh_dim(mgh->header.dim4length)), data(_compute_4d_size(d1, d2, d3, d4))
2415 const T &
at(
const unsigned int i1,
const unsigned int i2,
const unsigned int i3,
const unsigned int i4)
const 2417 return data[get_index(i1, i2, i3, i4)];
2421 unsigned int get_index(
const unsigned int i1,
const unsigned int i2,
const unsigned int i3,
const unsigned int i4)
const 2423 assert(i1 >= 0 && i1 < d1);
2424 assert(i2 >= 0 && i2 < d2);
2425 assert(i3 >= 0 && i3 < d3);
2426 assert(i4 >= 0 && i4 < d4);
2427 return (((i1 * d2 + i2) * d3 + i3) * d4 + i4);
2433 return (d1 * d2 * d3 * d4);
2445 static unsigned int _validate_mgh_dim(int32_t dim)
2449 throw std::domain_error(
"MGH dimension " + std::to_string(dim) +
" is not positive.\n");
2451 return static_cast<unsigned int>(dim);
2455 static size_t _compute_4d_size(
unsigned int d1,
unsigned int d2,
unsigned int d3,
unsigned int d4)
2457 if (d1 == 0 || d2 == 0 || d3 == 0 || d4 == 0)
2459 throw std::domain_error(
"Array4D dimensions must be positive.\n");
2462 if (!fs::util::safe_multiply(d1, d2, s1) ||
2463 !fs::util::safe_multiply(s1, d3, s2) ||
2464 !fs::util::safe_multiply(s2, d4, s3))
2466 throw std::overflow_error(
"Array4D dimensions cause size_t overflow.\n");
2470 throw std::runtime_error(
"Array4D size " + std::to_string(s3) +
2471 " elements exceeds maximum allowed allocation (" +
2480 void read_mgh_header(
MghHeader *, std::istream *);
2481 template <
typename T>
2482 std::vector<T> _read_mgh_data(
MghHeader *,
const std::string &);
2483 template <
typename T>
2484 std::vector<T> _read_mgh_data(
MghHeader *, std::istream *);
2485 std::vector<int32_t> _read_mgh_data_int(
MghHeader *,
const std::string &);
2486 std::vector<int32_t> _read_mgh_data_int(
MghHeader *, std::istream *);
2487 std::vector<uint8_t> _read_mgh_data_uchar(
MghHeader *,
const std::string &);
2488 std::vector<uint8_t> _read_mgh_data_uchar(
MghHeader *, std::istream *);
2489 std::vector<short> _read_mgh_data_short(
MghHeader *,
const std::string &);
2490 std::vector<short> _read_mgh_data_short(
MghHeader *, std::istream *);
2491 std::vector<float> _read_mgh_data_float(
MghHeader *,
const std::string &);
2492 std::vector<float> _read_mgh_data_float(
MghHeader *, std::istream *);
2509 read_mgh_header(&mgh_header, filename);
2510 mgh->
header = mgh_header;
2513 std::vector<int32_t> data = _read_mgh_data_int(&mgh_header, filename);
2518 std::vector<uint8_t> data = _read_mgh_data_uchar(&mgh_header, filename);
2523 std::vector<float> data = _read_mgh_data_float(&mgh_header, filename);
2528 std::vector<short> data = _read_mgh_data_short(&mgh_header, filename);
2533 #ifdef LIBFS_DBG_INFO 2534 if (fs::util::ends_with(filename,
".mgz"))
2536 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";
2539 throw std::runtime_error(
"Not reading MGH data from file '" + filename +
"', data type " + std::to_string(mgh->
header.
dtype) +
" not supported yet.\n");
2554 std::vector<std::string> subjects;
2555 std::ifstream input(filename, std::fstream::in);
2558 if (!input.is_open())
2560 throw std::runtime_error(
"Could not open subjects file '" + filename +
"'.\n");
2563 while (std::getline(input, line))
2565 subjects.push_back(line);
2578 read_mgh_header(&mgh_header, is);
2579 mgh->
header = mgh_header;
2582 std::vector<int32_t> data = _read_mgh_data_int(&mgh_header, is);
2587 std::vector<uint8_t> data = _read_mgh_data_uchar(&mgh_header, is);
2592 std::vector<float> data = _read_mgh_data_float(&mgh_header, is);
2597 std::vector<short> data = _read_mgh_data_short(&mgh_header, is);
2602 throw std::runtime_error(
"Not reading data from MGH stream, data type " + std::to_string(mgh->
header.
dtype) +
" not supported yet.\n");
2611 void read_mgh_header(
MghHeader *mgh_header, std::istream *is)
2613 const int MGH_VERSION = 1;
2615 int format_version = _freadt<int32_t>(*is);
2616 if (format_version != MGH_VERSION)
2618 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");
2620 mgh_header->
dim1length = _freadt<int32_t>(*is);
2621 mgh_header->
dim2length = _freadt<int32_t>(*is);
2622 mgh_header->
dim3length = _freadt<int32_t>(*is);
2623 mgh_header->
dim4length = _freadt<int32_t>(*is);
2629 throw std::domain_error(
"MGH header contains non-positive dimension(s): dims=(" +
2630 std::to_string(mgh_header->
dim1length) +
"," +
2631 std::to_string(mgh_header->
dim2length) +
"," +
2632 std::to_string(mgh_header->
dim3length) +
"," +
2633 std::to_string(mgh_header->
dim4length) +
").\n");
2637 if (!fs::util::check_alloc(static_cast<size_t>(mgh_header->
dim1length) *
2638 static_cast<size_t>(mgh_header->
dim2length) *
2640 static_cast<size_t>(mgh_header->
dim4length)))
2642 throw std::runtime_error(
"MGH header volume size exceeds maximum allowed allocation (" +
2646 mgh_header->
dtype = _freadt<int32_t>(*is);
2647 mgh_header->
dof = _freadt<int32_t>(*is);
2649 int unused_header_space_size_left = 256;
2651 unused_header_space_size_left -= 2;
2656 mgh_header->
xsize = _freadt<float>(*is);
2657 mgh_header->
ysize = _freadt<float>(*is);
2658 mgh_header->
zsize = _freadt<float>(*is);
2662 if (!fs::util::is_finite_float(mgh_header->
xsize) ||
2663 !fs::util::is_finite_float(mgh_header->
ysize) ||
2664 !fs::util::is_finite_float(mgh_header->
zsize))
2666 throw std::domain_error(
"MGH header contains NaN or Inf voxel size(s): x=" +
2667 std::to_string(mgh_header->
xsize) +
" y=" +
2668 std::to_string(mgh_header->
ysize) +
" z=" +
2669 std::to_string(mgh_header->
zsize) +
".\n");
2671 if (mgh_header->
xsize == 0.0f || mgh_header->
ysize == 0.0f || mgh_header->
zsize == 0.0f)
2673 throw std::domain_error(
"MGH header contains zero voxel size(s): x=" +
2674 std::to_string(mgh_header->
xsize) +
" y=" +
2675 std::to_string(mgh_header->
ysize) +
" z=" +
2676 std::to_string(mgh_header->
zsize) +
".\n");
2679 for (
int i = 0; i < 9; i++)
2681 mgh_header->
Mdc.push_back(_freadt<float>(*is));
2683 for (
int i = 0; i < 3; i++)
2685 mgh_header->
Pxyz_c.push_back(_freadt<float>(*is));
2689 for (
size_t i = 0; i < mgh_header->
Mdc.size(); i++)
2691 if (!fs::util::is_finite_float(mgh_header->
Mdc[i]))
2693 throw std::domain_error(
"MGH header Mdc matrix contains NaN or Inf at index " +
2694 std::to_string(i) +
".\n");
2697 for (
size_t i = 0; i < mgh_header->
Pxyz_c.size(); i++)
2699 if (!fs::util::is_finite_float(mgh_header->
Pxyz_c[i]))
2701 throw std::domain_error(
"MGH header Pxyz_c contains NaN or Inf at index " +
2702 std::to_string(i) +
".\n");
2706 unused_header_space_size_left -= 60;
2712 while (unused_header_space_size_left > 0)
2714 discarded = _freadt<uint8_t>(*is);
2715 unused_header_space_size_left -= 1;
2724 std::vector<int32_t> _read_mgh_data_int(
MghHeader *mgh_header,
const std::string &filename)
2726 if (mgh_header->
dtype != MRI_INT)
2728 std::cerr <<
"Expected MRI data type " << MRI_INT <<
", but found " << mgh_header->
dtype <<
".\n";
2730 return (_read_mgh_data<int32_t>(mgh_header, filename));
2737 std::vector<int32_t> _read_mgh_data_int(
MghHeader *mgh_header, std::istream *is)
2739 if (mgh_header->
dtype != MRI_INT)
2741 std::cerr <<
"Expected MRI data type " << MRI_INT <<
", but found " << mgh_header->
dtype <<
".\n";
2743 return (_read_mgh_data<int32_t>(mgh_header, is));
2750 std::vector<short> _read_mgh_data_short(
MghHeader *mgh_header,
const std::string &filename)
2752 if (mgh_header->
dtype != MRI_SHORT)
2754 std::cerr <<
"Expected MRI data type " << MRI_SHORT <<
", but found " << mgh_header->
dtype <<
".\n";
2756 return (_read_mgh_data<short>(mgh_header, filename));
2763 std::vector<short> _read_mgh_data_short(
MghHeader *mgh_header, std::istream *is)
2765 if (mgh_header->
dtype != MRI_SHORT)
2767 std::cerr <<
"Expected MRI data type " << MRI_SHORT <<
", but found " << mgh_header->
dtype <<
".\n";
2769 return (_read_mgh_data<short>(mgh_header, is));
2778 void read_mgh_header(
MghHeader *mgh_header,
const std::string &filename)
2781 ifs.open(filename, std::ios_base::in | std::ios::binary);
2784 read_mgh_header(mgh_header, &ifs);
2789 throw std::runtime_error(
"Unable to open MGH file '" + filename +
"'.\n");
2798 template <
typename T>
2799 std::vector<T> _read_mgh_data(
MghHeader *mgh_header,
const std::string &filename)
2802 ifs.open(filename, std::ios_base::in | std::ios::binary);
2805 size_t num_values = mgh_header->
num_values();
2808 size_t file_size = fs::util::get_file_size(filename);
2811 const size_t HEADER_SIZE = 284;
2812 size_t expected_data_bytes = 0;
2813 if (!fs::util::safe_multiply(num_values,
sizeof(T), expected_data_bytes))
2815 throw std::overflow_error(
"MGH data size computation overflowed.\n");
2817 if (file_size < HEADER_SIZE || (file_size - HEADER_SIZE) < expected_data_bytes)
2819 throw std::runtime_error(
"MGH file '" + filename +
"' is too small (" +
2820 std::to_string(file_size) +
" bytes) for the data claimed in its header (" +
2821 std::to_string(HEADER_SIZE + expected_data_bytes) +
" bytes).\n");
2825 if (!fs::util::check_alloc(num_values,
sizeof(T)))
2827 throw std::runtime_error(
"MGH file data size exceeds maximum allowed allocation.\n");
2830 ifs.seekg(284, ifs.beg);
2832 std::vector<T> data;
2833 data.reserve(num_values);
2834 for (
size_t i = 0; i < num_values; i++)
2836 data.push_back(_freadt<T>(ifs));
2843 throw std::runtime_error(
"Unable to open MGH file '" + filename +
"'.\n");
2851 template <
typename T>
2852 std::vector<T> _read_mgh_data(
MghHeader *mgh_header, std::istream *is)
2854 size_t num_values = mgh_header->
num_values();
2855 if (!fs::util::check_alloc(num_values,
sizeof(T)))
2857 throw std::runtime_error(
"MGH stream data size exceeds maximum allowed allocation.\n");
2859 std::vector<T> data;
2860 data.reserve(num_values);
2861 for (
size_t i = 0; i < num_values; i++)
2863 data.push_back(_freadt<T>(*is));
2872 std::vector<float> _read_mgh_data_float(
MghHeader *mgh_header,
const std::string &filename)
2874 if (mgh_header->
dtype != MRI_FLOAT)
2876 std::cerr <<
"Expected MRI data type " << MRI_FLOAT <<
", but found " << mgh_header->
dtype <<
".\n";
2878 return (_read_mgh_data<float>(mgh_header, filename));
2885 std::vector<float> _read_mgh_data_float(
MghHeader *mgh_header, std::istream *is)
2887 if (mgh_header->
dtype != MRI_FLOAT)
2889 std::cerr <<
"Expected MRI data type " << MRI_FLOAT <<
", but found " << mgh_header->
dtype <<
".\n";
2891 return (_read_mgh_data<float>(mgh_header, is));
2898 std::vector<uint8_t> _read_mgh_data_uchar(
MghHeader *mgh_header,
const std::string &filename)
2900 if (mgh_header->
dtype != MRI_UCHAR)
2902 std::cerr <<
"Expected MRI data type " << MRI_UCHAR <<
", but found " << mgh_header->
dtype <<
".\n";
2904 return (_read_mgh_data<uint8_t>(mgh_header, filename));
2911 std::vector<uint8_t> _read_mgh_data_uchar(
MghHeader *mgh_header, std::istream *is)
2913 if (mgh_header->
dtype != MRI_UCHAR)
2915 std::cerr <<
"Expected MRI data type " << MRI_UCHAR <<
", but found " << mgh_header->
dtype <<
".\n";
2917 return (_read_mgh_data<uint8_t>(mgh_header, is));
2935 const int SURF_TRIS_MAGIC = 16777214;
2937 is.open(filename, std::ios_base::in | std::ios::binary);
2940 int magic = _fread3(is);
2941 if (magic != SURF_TRIS_MAGIC)
2943 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");
2945 std::string created_line = _freadstringnewline(is);
2946 std::string comment_line = _freadstringnewline(is);
2947 int num_verts = _freadt<int32_t>(is);
2948 int num_faces = _freadt<int32_t>(is);
2953 throw std::domain_error(
"Surf file '" + filename +
"' has invalid num_verts: " + std::to_string(num_verts) +
".\n");
2957 throw std::domain_error(
"Surf file '" + filename +
"' has invalid num_faces: " + std::to_string(num_faces) +
".\n");
2961 size_t num_vert_coords = 0;
2962 if (!fs::util::safe_multiply(static_cast<size_t>(num_verts), 3, num_vert_coords))
2964 throw std::overflow_error(
"Surf file '" + filename +
"': num_verts * 3 overflowed.\n");
2966 size_t num_face_indices = 0;
2967 if (!fs::util::safe_multiply(static_cast<size_t>(num_faces), 3, num_face_indices))
2969 throw std::overflow_error(
"Surf file '" + filename +
"': num_faces * 3 overflowed.\n");
2973 size_t file_size = fs::util::get_file_size(filename);
2976 size_t vert_bytes = 0, face_bytes = 0;
2977 if (!fs::util::safe_multiply(num_vert_coords,
sizeof(
float), vert_bytes) ||
2978 !fs::util::safe_multiply(num_face_indices,
sizeof(int32_t), face_bytes))
2980 throw std::overflow_error(
"Surf file '" + filename +
"': expected data size overflowed.\n");
2983 if (vert_bytes > std::numeric_limits<size_t>::max() - face_bytes)
2985 throw std::overflow_error(
"Surf file '" + filename +
"': total data size overflowed.\n");
2987 size_t expected_total = vert_bytes + face_bytes;
2989 if (file_size < expected_total)
2991 throw std::runtime_error(
"Surf file '" + filename +
"' is too small (" +
2992 std::to_string(file_size) +
" bytes) for the data claimed in its header.\n");
2996 if (!fs::util::check_alloc(num_vert_coords,
sizeof(
float)) ||
2997 !fs::util::check_alloc(num_face_indices,
sizeof(int32_t)))
2999 throw std::runtime_error(
"Surf file '" + filename +
"' data size exceeds maximum allowed allocation.\n");
3002 #ifdef LIBFS_DBG_INFO 3003 std::cout << LIBFS_APPTAG <<
"Read surface file with " << num_verts <<
" vertices, " << num_faces <<
" faces.\n";
3005 std::vector<float> vdata;
3006 vdata.reserve(num_vert_coords);
3007 for (
size_t i = 0; i < num_vert_coords; i++)
3009 vdata.push_back(_freadt<float>(is));
3011 std::vector<int> fdata;
3012 fdata.reserve(num_face_indices);
3013 for (
size_t i = 0; i < num_face_indices; i++)
3015 fdata.push_back(_freadt<int32_t>(is));
3019 surface->
faces = fdata;
3023 throw std::runtime_error(
"Unable to open surface file '" + filename +
"'.\n");
3041 if (fs::util::ends_with(filename,
".obj"))
3045 else if (fs::util::ends_with(filename,
".ply"))
3049 else if (fs::util::ends_with(filename,
".off"))
3064 bool _is_bigendian()
3066 const short int number = 0x1;
3067 const char *numPtr =
reinterpret_cast<const char *
>(&number);
3068 return (numPtr[0] != 1);
3076 void read_curv(
Curv *curv, std::istream *is,
const std::string &source_filename =
"")
3078 const std::string msg_source_file_part = source_filename.empty() ?
"" :
"'" + source_filename +
"' ";
3079 const int CURV_MAGIC = 16777215;
3080 int magic = _fread3(*is);
3081 if (magic != CURV_MAGIC)
3083 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");
3086 curv->
num_faces = _freadt<int32_t>(*is);
3092 throw std::domain_error(
"Curv file " + msg_source_file_part +
"has invalid num_vertices: " + std::to_string(curv->
num_vertices) +
".\n");
3096 throw std::domain_error(
"Curv file " + msg_source_file_part +
"has invalid num_faces: " + std::to_string(curv->
num_faces) +
".\n");
3099 #ifdef LIBFS_DBG_INFO 3104 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");
3108 if (!source_filename.empty())
3110 size_t file_size = fs::util::get_file_size(source_filename);
3114 const size_t CURV_HEADER_SIZE = 15;
3115 size_t expected_data_bytes = 0;
3116 if (!fs::util::safe_multiply(static_cast<size_t>(curv->
num_vertices),
sizeof(
float), expected_data_bytes))
3118 throw std::overflow_error(
"Curv file " + msg_source_file_part +
"data size computation overflowed.\n");
3120 if (file_size < CURV_HEADER_SIZE || (file_size - CURV_HEADER_SIZE) < expected_data_bytes)
3122 throw std::runtime_error(
"Curv file " + msg_source_file_part +
"is too small (" +
3123 std::to_string(file_size) +
" bytes) for the data claimed in its header (" +
3124 std::to_string(CURV_HEADER_SIZE + expected_data_bytes) +
" bytes expected).\n");
3129 std::vector<float> data;
3130 if (!fs::util::check_alloc(static_cast<size_t>(curv->
num_vertices),
sizeof(
float)))
3132 throw std::runtime_error(
"Curv file " + msg_source_file_part +
"data size exceeds maximum allowed allocation.\n");
3135 for (
size_t i = 0; i < static_cast<size_t>(curv->
num_vertices); i++)
3137 data.push_back(_freadt<float>(*is));
3156 std::ifstream is(filename, std::fstream::in | std::fstream::binary);
3164 throw std::runtime_error(
"Could not open curv file '" + filename +
"' for reading.\n");
3170 void _read_annot_colortable(
Colortable *colortable, std::istream *is, int32_t num_entries)
3175 throw std::domain_error(
"Annot colortable num_entries " + std::to_string(num_entries) +
3179 int32_t num_chars_orig_filename = _freadt<int32_t>(*is);
3184 throw std::domain_error(
"Annot colortable original filename length " + std::to_string(num_chars_orig_filename) +
3190 for (int32_t i = 0; i < num_chars_orig_filename; i++)
3192 discarded = _freadt<uint8_t>(*is);
3196 int32_t num_entries_duplicated = _freadt<int32_t>(*is);
3197 if (num_entries != num_entries_duplicated)
3199 std::cerr <<
"Warning: the two num_entries header fields of this annotation do not match. Use with care.\n";
3202 colortable->
id.reserve(static_cast<size_t>(num_entries));
3203 colortable->
name.reserve(static_cast<size_t>(num_entries));
3204 colortable->
r.reserve(static_cast<size_t>(num_entries));
3205 colortable->
g.reserve(static_cast<size_t>(num_entries));
3206 colortable->
b.reserve(static_cast<size_t>(num_entries));
3207 colortable->
a.reserve(static_cast<size_t>(num_entries));
3208 colortable->
label.reserve(static_cast<size_t>(num_entries));
3210 int32_t entry_num_chars;
3211 for (int32_t i = 0; i < num_entries; i++)
3213 colortable->
id.push_back(_freadt<int32_t>(*is));
3214 entry_num_chars = _freadt<int32_t>(*is);
3216 colortable->
name.push_back(_freadfixedlengthstring(*is, entry_num_chars,
true, 256));
3217 colortable->
r.push_back(_freadt<int32_t>(*is));
3218 colortable->
g.push_back(_freadt<int32_t>(*is));
3219 colortable->
b.push_back(_freadt<int32_t>(*is));
3220 colortable->
a.push_back(_freadt<int32_t>(*is));
3221 colortable->
label.push_back(colortable->
r[i] + colortable->
g[i] * 256 + colortable->
b[i] * 65536 + colortable->
a[i] * 16777216);
3227 size_t _vidx_2d(
size_t row,
size_t column,
size_t row_length = 3)
3229 return (row + 1) * row_length - row_length + column;
3240 int32_t num_vertices = _freadt<int32_t>(*is);
3243 if (num_vertices <= 0)
3245 throw std::domain_error(
"Annot file has invalid num_vertices: " + std::to_string(num_vertices) +
".\n");
3249 size_t num_entries = 0;
3250 if (!fs::util::safe_multiply(static_cast<size_t>(num_vertices), 2, num_entries))
3252 throw std::overflow_error(
"Annot: num_vertices * 2 overflowed.\n");
3254 if (!fs::util::check_alloc(num_entries,
sizeof(int32_t)))
3256 throw std::runtime_error(
"Annot vertex/label data size exceeds maximum allowed allocation.\n");
3259 std::vector<int32_t> vertices;
3260 std::vector<int32_t> labels;
3261 vertices.reserve(num_vertices);
3262 labels.reserve(num_vertices);
3263 for (
size_t i = 0; i < num_entries; i++)
3267 vertices.push_back(_freadt<int32_t>(*is));
3271 labels.push_back(_freadt<int32_t>(*is));
3276 int32_t has_colortable = _freadt<int32_t>(*is);
3277 if (has_colortable == 1)
3279 int32_t num_colortable_entries_old_format = _freadt<int32_t>(*is);
3280 if (num_colortable_entries_old_format > 0)
3282 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");
3286 int32_t colortable_format_version = -num_colortable_entries_old_format;
3287 if (colortable_format_version == 2)
3289 int32_t num_colortable_entries = _freadt<int32_t>(*is);
3290 _read_annot_colortable(&annot->
colortable, is, num_colortable_entries);
3294 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");
3300 throw std::domain_error(
"Reading annotation without colortable not supported. Maybe invalid annotation file?\n");
3319 std::ifstream is(filename, std::fstream::in | std::fstream::binary);
3327 throw std::runtime_error(
"Could not open annot file '" + filename +
"' for reading.\n");
3365 if (fs::util::ends_with(filename, {
".MGH",
".mgh"}))
3372 for (
size_t i = 0; i < dims.size(); i++)
3381 std::cerr <<
"MGH file '" << filename <<
"' contains more than one non-empty dimension. Returning concatinated data.\n";
3400 template <
typename T>
3403 static_assert(CHAR_BIT == 8,
"CHAR_BIT != 8");
3405 unsigned char src[
sizeof(T)];
3406 unsigned char dst[
sizeof(T)];
3407 std::memcpy(src, &u,
sizeof(T));
3409 for (
size_t k = 0; k <
sizeof(T); k++)
3411 dst[k] = src[
sizeof(T) - k - 1];
3415 std::memcpy(&result, dst,
sizeof(T));
3423 template <
typename T>
3424 T _freadt(std::istream &is)
3427 is.read(reinterpret_cast<char *>(&t),
sizeof(t));
3428 if (static_cast<size_t>(is.gcount()) !=
sizeof(T))
3430 if (is.gcount() == 0)
3432 throw std::runtime_error(
"Unexpected end of binary stream: expected " + std::to_string(
sizeof(T)) +
" bytes, got EOF.\n");
3434 throw std::runtime_error(
"Short read in binary stream: expected " + std::to_string(
sizeof(T)) +
" bytes, got " + std::to_string(is.gcount()) +
".\n");
3436 if (!_is_bigendian())
3438 t = _swap_endian<T>(t);
3447 int _fread3(std::istream &is)
3450 is.read(reinterpret_cast<char *>(&i), 3);
3451 if (static_cast<size_t>(is.gcount()) != 3)
3453 if (is.gcount() == 0)
3455 throw std::runtime_error(
"Unexpected end of binary stream: expected 3 bytes, got EOF.\n");
3457 throw std::runtime_error(
"Short read in binary stream: expected 3 bytes, got " + std::to_string(is.gcount()) +
".\n");
3459 if (!_is_bigendian())
3461 i = _swap_endian<std::uint32_t>(i);
3463 i = ((i >> 8) & 0xffffff);
3471 template <
typename T>
3472 void _fwritet(std::ostream &os, T t)
3474 if (!_is_bigendian())
3476 t = _swap_endian<T>(t);
3478 os.write(reinterpret_cast<const char *>(&t),
sizeof(t));
3485 void _fwritei3(std::ostream &os, uint32_t i)
3487 unsigned char b1 = (i >> 16) & 255;
3488 unsigned char b2 = (i >> 8) & 255;
3489 unsigned char b3 = i & 255;
3491 if (!_is_bigendian())
3493 b1 = _swap_endian<unsigned char>(b1);
3494 b2 = _swap_endian<unsigned char>(b2);
3495 b3 = _swap_endian<unsigned char>(b3);
3498 os.write(reinterpret_cast<const char *>(&b1),
sizeof(b1));
3499 os.write(reinterpret_cast<const char *>(&b2),
sizeof(b2));
3500 os.write(reinterpret_cast<const char *>(&b3),
sizeof(b3));
3507 std::string _freadstringnewline(std::istream &is)
3510 std::getline(is, s,
'\n');
3518 std::string _freadfixedlengthstring(std::istream &is,
size_t length,
bool strip_last_char =
true,
size_t max_length =
LIBFS_MAX_STRING_LENGTH)
3522 throw std::domain_error(
"Fixed-length string read with zero length.\n");
3524 if (length > max_length)
3526 throw std::domain_error(
"Fixed-length string length " + std::to_string(length) +
" exceeds maximum " + std::to_string(max_length) +
".\n");
3530 is.read(&str[0], length);
3531 if (static_cast<size_t>(is.gcount()) != length)
3533 if (is.gcount() == 0)
3535 throw std::runtime_error(
"Unexpected end of binary stream while reading fixed-length string: expected " + std::to_string(length) +
" bytes, got EOF.\n");
3537 throw std::runtime_error(
"Short read in binary stream while reading fixed-length string: expected " + std::to_string(length) +
" bytes, got " + std::to_string(is.gcount()) +
".\n");
3539 if (strip_last_char)
3541 str = str.substr(0, length - 1);
3551 void write_curv(std::ostream &os, std::vector<float> curv_data, int32_t num_faces = 100000)
3553 const uint32_t CURV_MAGIC = 16777215;
3554 _fwritei3(os, CURV_MAGIC);
3555 _fwritet<int32_t>(os, int(curv_data.size()));
3556 _fwritet<int32_t>(os, num_faces);
3557 _fwritet<int32_t>(os, 1);
3558 for (
size_t i = 0; i < curv_data.size(); i++)
3560 _fwritet<float>(os, curv_data[i]);
3578 void write_curv(
const std::string &filename, std::vector<float> curv_data,
const int32_t num_faces = 100000)
3581 ofs.open(filename, std::ofstream::out | std::ofstream::binary);
3589 throw std::runtime_error(
"Unable to open curvature file '" + filename +
"' for writing.\n");
3600 _fwritet<int32_t>(os, 1);
3609 size_t unused_header_space_size_left = 256;
3611 unused_header_space_size_left -= 2;
3620 for (
int i = 0; i < 9; i++)
3624 for (
int i = 0; i < 3; i++)
3629 unused_header_space_size_left -= 60;
3632 for (
size_t i = 0; i < unused_header_space_size_left; i++)
3634 _fwritet<uint8_t>(os, 0);
3643 throw std::logic_error(
"Detected mismatch of MRI_INT data size and MGH header dim length values.\n");
3645 for (
size_t i = 0; i < num_values; i++)
3654 throw std::logic_error(
"Detected mismatch of MRI_FLOAT data size and MGH header dim length values.\n");
3656 for (
size_t i = 0; i < num_values; i++)
3665 throw std::logic_error(
"Detected mismatch of MRI_UCHAR data size and MGH header dim length values.\n");
3667 for (
size_t i = 0; i < num_values; i++)
3676 throw std::logic_error(
"Detected mismatch of MRI_SHORT data size and MGH header dim length values.\n");
3678 for (
size_t i = 0; i < num_values; i++)
3685 throw std::domain_error(
"Unsupported MRI data type " + std::to_string(mgh.
header.
dtype) +
", cannot write MGH data.\n");
3707 ofs.open(filename, std::ofstream::out | std::ofstream::binary);
3715 throw std::runtime_error(
"Unable to open MGH file '" + filename +
"' for writing.\n");
3732 Label(std::vector<int> vertices, std::vector<float> values)
3734 assert(vertices.size() == values.size());
3737 coord_x = std::vector<float>(vertices.size(), 0.0f);
3738 coord_y = std::vector<float>(vertices.size(), 0.0f);
3739 coord_z = std::vector<float>(vertices.size(), 0.0f);
3746 value = std::vector<float>(vertices.size(), 0.0f);
3747 coord_x = std::vector<float>(vertices.size(), 0.0f);
3748 coord_y = std::vector<float>(vertices.size(), 0.0f);
3749 coord_z = std::vector<float>(vertices.size(), 0.0f);
3761 if (surface_num_verts < this->vertex.size())
3763 std::cerr <<
"Invalid number of vertices for surface, must be at least " << this->vertex.size() <<
"\n";
3765 std::vector<bool> is_in = std::vector<bool>(surface_num_verts,
false);
3767 for (
size_t i = 0; i < this->vertex.size(); i++)
3769 is_in[this->vertex[i]] =
true;
3777 size_t num_ent = this->vertex.size();
3778 if (this->coord_x.size() != num_ent || this->coord_y.size() != num_ent || this->coord_z.size() != num_ent || this->value.size() != num_ent)
3780 std::cerr <<
"Inconsistent label: sizes of property vectors do not match.\n";
3792 void write_surf(std::vector<float> vertices, std::vector<int32_t> faces, std::ostream &os)
3794 const uint32_t SURF_TRIS_MAGIC = 16777214;
3795 _fwritei3(os, SURF_TRIS_MAGIC);
3796 std::string created_and_comment_lines =
"Created by fslib\n\n";
3797 os << created_and_comment_lines;
3798 _fwritet<int32_t>(os, int(vertices.size() / 3));
3799 _fwritet<int32_t>(os, int(faces.size() / 3));
3800 for (
size_t i = 0; i < vertices.size(); i++)
3802 _fwritet<float>(os, vertices[i]);
3804 for (
size_t i = 0; i < faces.size(); i++)
3806 _fwritet<int32_t>(os, faces[i]);
3823 void write_surf(std::vector<float> vertices, std::vector<int32_t> faces,
const std::string &filename)
3826 ofs.open(filename, std::ofstream::out | std::ofstream::binary);
3834 throw std::runtime_error(
"Unable to open surf file '" + filename +
"' for writing.\n");
3853 ofs.open(filename, std::ofstream::out | std::ofstream::binary);
3861 throw std::runtime_error(
"Unable to open surf file '" + filename +
"' for writing.\n");
3875 size_t num_entries_header = 0;
3876 size_t num_entries = 0;
3877 while (std::getline(*is, line))
3880 std::istringstream iss(line);
3889 if (!(iss >> num_entries_header))
3891 throw std::domain_error(
"Could not parse entry count from label file, invalid format.\n");
3897 float x, y, z, value;
3898 if (!(iss >> vertex >> x >> y >> z >> value))
3900 throw std::domain_error(
"Could not parse line " + std::to_string(line_idx + 1) +
" of label file, invalid format.\n");
3902 label->
vertex.push_back(vertex);
3906 label->
value.push_back(value);
3911 if (num_entries != num_entries_header)
3913 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");
3915 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)
3917 throw std::domain_error(
"Expected " + std::to_string(num_entries) +
" entries in all Label vectors, but some did not match.\n");
3936 std::ifstream infile(filename, std::fstream::in);
3937 if (infile.is_open())
3944 throw std::runtime_error(
"Could not open label file '" + filename +
"' for reading.\n");
3955 os <<
"#!ascii label from subject anonymous\n" 3956 << num_entries <<
"\n";
3957 for (
size_t i = 0; i < num_entries; i++)
3979 ofs.open(filename, std::ofstream::out);
3987 throw std::runtime_error(
"Unable to open label file '" + filename +
"' for writing.\n");
4008 if (fs::util::ends_with(filename, {
".ply",
".PLY"}))
4012 else if (fs::util::ends_with(filename, {
".obj",
".OBJ"}))
4016 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:3551
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:837
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:2211
size_t num_entries() const
Get the number of enties (regions) in this Colortable.
Definition: libfs.h:2171
Mgh(Curv curv)
Definition: libfs.h:2375
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:3753
std::string to_off(const std::vector< uint8_t > col) const
Return string representing the mesh in PLY format.
Definition: libfs.h:2068
Models a FreeSurfer curv file that contains per-vertex float data.
Definition: libfs.h:2133
const int MRI_SHORT
MRI data type representing a 16 bit signed integer.
Definition: libfs.h:788
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:3754
unsigned int d2
size of data along 2nd dimension
Definition: libfs.h:2437
const std::string LOGTAG_EXCESSIVE
Logging threshold for warning messages.
Definition: libfs.h:217
An annotation, also known as a brain surface parcellation. Assigns to each vertex a region...
Definition: libfs.h:2209
const std::string LOGTAG_VERBOSE
Logging threshold for warning messages.
Definition: libfs.h:214
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:3076
edge_set as_edgelist() const
Return edge list representation of this mesh.
Definition: libfs.h:1046
std::vector< int32_t > label
label integer computed from rgba values. Maps to the Annot.vertex_label field.
Definition: libfs.h:2168
Array4D(MghHeader *mgh_header)
Definition: libfs.h:2403
std::string to_obj() const
Return string representing the mesh in Wavefront Object (.obj) format.
Definition: libfs.h:982
std::string time_tag(std::chrono::system_clock::time_point t)
Get current time as string, e.g. for log messages.
Definition: libfs.h:187
static void from_obj(Mesh *mesh, const std::string &filename)
Read a brainmesh from a Wavefront object format mesh file.
Definition: libfs.h:1541
const std::string LOGTAG_WARNING
Logging threshold for warning messages.
Definition: libfs.h:208
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:1157
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:565
bool file_exists(const std::string &name)
Check whether a file exists (can be read) at given path.
Definition: libfs.h:434
const std::string LOGTAG_INFO
Logging threshold for warning messages.
Definition: libfs.h:211
#define LIBFS_MAX_ALLOC_BYTES
Maximum memory allocation limit.
Definition: libfs.h:37
A simple 4D array datastructure, useful for representing volume data.
Definition: libfs.h:2390
std::vector< float > data
The curvature data, one value per vertex. Something like the cortical thickness at each vertex...
Definition: libfs.h:2150
static void from_ply(Mesh *mesh, std::istream *is)
Read a brainmesh from a Stanford PLY format stream.
Definition: libfs.h:1699
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:1877
std::vector< T > data
the data, as a 1D vector. Use fs::Array4D::at for easy access in 4D.
Definition: libfs.h:2440
std::vector< int32_t > b
green channel of RGBA color
Definition: libfs.h:2166
static void from_ply(Mesh *mesh, const std::string &filename)
Read a brainmesh from a Stanford PLY format mesh file.
Definition: libfs.h:1820
std::vector< int32_t > g
blue channel of RGBA color
Definition: libfs.h:2165
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:3343
void write_mgh(const Mgh &mgh, std::ostream &os)
Write MGH data to a stream.
Definition: libfs.h:3598
static void from_off(Mesh *mesh, const std::string &filename)
Read a brainmesh from an OFF format mesh file.
Definition: libfs.h:1677
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:3759
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:1401
Models a triangular mesh, used for brain surface meshes.
Definition: libfs.h:817
const int MRI_UCHAR
MRI data type representing an 8 bit unsigned integer.
Definition: libfs.h:779
size_t num_entries() const
Return the number of entries (vertices/voxels) in this label.
Definition: libfs.h:3775
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:2421
Models the data of an MGH file. Currently these are 1D vectors, but one can compute the 4D array usin...
Definition: libfs.h:2355
void read_label(Label *label, std::istream *is)
Read a FreeSurfer ASCII label from a stream.
Definition: libfs.h:3871
void to_ply_file(const std::string &filename) const
Export this mesh to a file in Stanford PLY format.
Definition: libfs.h:2036
MghData(std::vector< uint8_t > curv_data)
constructor to create MghData from MRI_UCHAR (uint8_t) data.
Definition: libfs.h:2359
Mesh(std::vector< float > cvertices, std::vector< int32_t > cfaces)
Construct a Mesh from the given vertices and faces.
Definition: libfs.h:821
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:2280
std::vector< std::vector< bool > > as_adjmatrix() const
Return adjacency matrix representation of this mesh.
Definition: libfs.h:1007
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:2415
Array4D(Mgh *mgh)
Definition: libfs.h:2409
unsigned int d1
size of data along 1st dimension
Definition: libfs.h:2436
#define LIBFS_MAX_STRING_LENGTH
Maximum length for fixed-length strings read from binary headers (e.g., filenames in annot colortable...
Definition: libfs.h:42
std::string to_ply() const
Return string representing the mesh in PLY format. Overload that works without passing a color vector...
Definition: libfs.h:1966
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:2160
const int MRI_FLOAT
MRI data type representing a 32 bit float.
Definition: libfs.h:785
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:3792
std::vector< std::vector< size_t > > as_adjlist(const bool via_matrix=true) const
Return adjacency list representation of this mesh.
Definition: libfs.h:1075
static fs::Mesh construct_pyramid()
Construct and return a simple pyramidal mesh.
Definition: libfs.h:887
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:1134
std::vector< int32_t > id
internal region index
Definition: libfs.h:2162
void write_mesh(const Mesh &mesh, const std::string &filename)
Write a mesh to a file in different formats.
Definition: libfs.h:4006
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:2232
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:2366
const int MRI_INT
MRI data type representing a 32 bit signed integer.
Definition: libfs.h:782
static void from_obj(Mesh *mesh, std::istream *is)
Read a brainmesh from a Wavefront object format stream.
Definition: libfs.h:1435
Curv(std::vector< float > curv_data)
Construct a Curv instance from the given per-vertex data.
Definition: libfs.h:2137
unsigned int d3
size of data along 3rd dimension
Definition: libfs.h:2438
Models a whole MGH file.
Definition: libfs.h:2370
size_t num_vertices() const
Get the number of vertices of this parcellation (or the associated surface).
Definition: libfs.h:2268
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:2156
void write_surf(const Mesh &mesh, const std::string &filename)
Write a mesh to a binary file in FreeSurfer surf format.
Definition: libfs.h:3850
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:509
void read_annot(Annot *annot, std::istream *is)
Read a FreeSurfer annotation or brain surface parcellation from an annot stream.
Definition: libfs.h:3237
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:2153
std::vector< float > vertex_coords(const size_t vertex) const
Get all coordinates of the vertex, given by its index.
Definition: libfs.h:1922
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:1564
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:1898
Mgh(std::vector< float > curv_data)
Definition: libfs.h:2380
std::vector< std::string > read_subjectsfile(const std::string &filename)
Read a vector of subject identifiers from a FreeSurfer subjects file.
Definition: libfs.h:2552
std::vector< float > value
the value of the label, can represent continuous data like a p-value, or sometimes simply 1...
Definition: libfs.h:3756
std::vector< int32_t > r
red channel of RGBA color
Definition: libfs.h:2164
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:2506
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:2046
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:1033
size_t num_faces() const
Return the number of faces in this mesh.
Definition: libfs.h:1860
void write_label(const Label &label, std::ostream &os)
Write label data to a stream.
Definition: libfs.h:3952
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:3752
std::string to_ply(const std::vector< uint8_t > col) const
Return string representing the mesh in PLY format.
Definition: libfs.h:1982
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:2300
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:2247
static fs::Mesh construct_cube()
Construct and return a simple cube mesh.
Definition: libfs.h:850
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:2363
void read_mgh(Mgh *mgh, std::istream *is)
Read MGH data from a stream.
Definition: libfs.h:2575
MghData(std::vector< float > curv_data)
constructor to create MghData from MRI_FLOAT (float) data.
Definition: libfs.h:2361
MghData(std::vector< short > curv_data)
constructor to create MghData from MRI_SHORT (short) data.
Definition: libfs.h:2360
const std::string LOGTAG_ERROR
Logging threshold for error messages.
Definition: libfs.h:205
Mesh()
Construct an empty Mesh.
Definition: libfs.h:835
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:1344
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:2364
Label(std::vector< int > vertices)
Construct a Label from the given vertices / voxel numbers.
Definition: libfs.h:3743
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:1278
void to_obj_file(const std::string &filename) const
Export this mesh to a file in Wavefront OBJ format.
Definition: libfs.h:1323
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:2933
Curv()
Construct an empty Curv instance.
Definition: libfs.h:2144
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:462
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:2216
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:2126
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:3039
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:2182
int32_t num_faces
The number of faces of the mesh to which this belongs, typically irrelevant and ignored.
Definition: libfs.h:2147
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:2365
#define LIBFS_MAX_COLORTABLE_ENTRIES
Maximum number of entries in an annotation colortable.
Definition: libfs.h:47
unsigned int num_values() const
Get number of values/voxels.
Definition: libfs.h:2431
Colortable colortable
A Colortable defining the regions (most importantly, the region name and visualization color)...
Definition: libfs.h:2213
MghHeader header
Header for this MGH instance.
Definition: libfs.h:2372
void log(std::string const &message, std::string const loglevel="INFO")
Log a message, goes to stdout.
Definition: libfs.h:222
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:1948
std::vector< T > vflatten(std::vector< std::vector< T >> values)
Flatten 2D vector.
Definition: libfs.h:363
Label(std::vector< int > vertices, std::vector< float > values)
Construct a Label from the given vertices / voxel numbers and values.
Definition: libfs.h:3732
std::vector< int32_t > a
alpha channel of RGBA color
Definition: libfs.h:2167
const std::string LOGTAG_CRITICAL
Logging threshold for critical messages.
Definition: libfs.h:202
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:2195
Label()
Default constructor for a label.
Definition: libfs.h:3729
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:920
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:838
void to_off_file(const std::string &filename) const
Export this mesh to a file in OFF format.
Definition: libfs.h:2119
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:2212
MghData(Curv curv)
constructor to create MghData from a Curv instance
Definition: libfs.h:2362
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:3755
Array4D(unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4)
Definition: libfs.h:2396
MghData(std::vector< int32_t > curv_data)
constructor to create MghData from MRI_INT (int32_t) data.
Definition: libfs.h:2358
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:3363
Mgh()
Empty default constuctor.
Definition: libfs.h:2374
std::string to_off() const
Return string representing the mesh in OFF format. Overload that works without passing a color vector...
Definition: libfs.h:2059
std::vector< std::string > name
region name
Definition: libfs.h:2163
MghData data
4D data for this MGH instance.
Definition: libfs.h:2373
unsigned int d4
size of data along 4th dimension
Definition: libfs.h:2439
size_t num_vertices() const
Return the number of vertices in this mesh.
Definition: libfs.h:1846
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:2778