34 #ifndef EGS_MESH_TETGEN_PARSER_
35 #define EGS_MESH_TETGEN_PARSER_
48 namespace tetgen_parser {
56 EGS_MeshSpec parse_tetgen_files(
const std::string &filename,
59 enum class TetGenFile { Node, Ele };
68 static inline void ltrim(std::string &s) {
69 s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](
unsigned char ch) {
70 return !std::isspace(ch);
87 std::vector<EGS_MeshSpec::Node> parse_tetgen_node_file(std::istream &input,
89 std::vector<EGS_MeshSpec::Node> nodes;
101 int num_boundary = -1;
102 std::getline(input, line);
103 std::istringstream line_stream(line);
104 line_stream >> num_nodes >> num_coords >> num_attr >> num_boundary;
105 if (line_stream.fail() || num_nodes == -1) {
106 throw std::runtime_error(
"failed to parse TetGen node file header");
108 if (num_coords != 3) {
109 throw std::runtime_error(
"TetGen node file parsing failed, expected"
114 if (num_nodes < 50000) {
118 egs_mesh::internal::PercentCounter progress(info,
"EGS_Mesh: reading " +
119 std::to_string(num_nodes) +
" nodes");
120 progress.start(num_nodes);
122 nodes.reserve(num_nodes);
125 while (nodes.size() <
static_cast<std::size_t
>(num_nodes)) {
126 std::getline(input, line);
129 if (line.rfind(
'#', 0) == 0) {
132 std::istringstream line_stream(line);
137 line_stream >> tag >> x >> y >> z;
138 if (line_stream.fail() || tag == -1) {
139 throw std::runtime_error(
"TetGen node file parsing failed");
144 progress.finish(
"EGS_Mesh: read " + std::to_string(num_nodes) +
" nodes");
161 std::vector<EGS_MeshSpec::Tetrahedron> parse_tetgen_ele_file(
163 std::vector<EGS_MeshSpec::Tetrahedron> elts;
174 std::getline(input, line);
175 std::istringstream line_stream(line);
176 line_stream >> num_elts >> num_nodes >> num_attr;
177 if (line_stream.fail() || num_elts == -1) {
178 throw std::runtime_error(
"failed to parse TetGen ele file header");
180 if (num_nodes != 4) {
181 throw std::runtime_error(
"TetGen ele file parsing failed, expected"
182 " 4 nodes per tetrahedron");
185 throw std::runtime_error(
"TetGen ele file parsing failed, expected"
186 " each element to only have one attribute (EGSnrc medium)");
190 if (num_elts < 50000) {
194 egs_mesh::internal::PercentCounter progress(info,
"EGS_Mesh: reading " +
195 std::to_string(num_elts) +
" tetrahedrons");
196 progress.start(num_elts);
198 elts.reserve(num_elts);
200 while (elts.size() <
static_cast<std::size_t
>(num_elts)) {
201 std::getline(input, line);
204 if (line.rfind(
'#', 0) == 0) {
207 std::istringstream line_stream(line);
214 line_stream >> tag >> n0 >> n1 >> n2 >> n3 >> media;
215 if (line_stream.fail() || tag == -1) {
216 throw std::runtime_error(
"Tetgen ele file parsing failed");
221 progress.finish(
"EGS_Mesh: read " + std::to_string(num_elts)
228 std::vector<EGS_MeshSpec::Medium> find_tetgen_elt_media(
229 const std::vector<EGS_MeshSpec::Tetrahedron> &elts) {
231 std::set<int> media_tags;
232 for (
const auto &e: elts) {
233 media_tags.insert(e.medium_tag);
235 std::vector<EGS_MeshSpec::Medium> media;
236 media.reserve(media_tags.size());
237 for (
const auto &m : media_tags) {
246 EGS_MeshSpec parse_tetgen_files(
const std::string &filename,
248 std::string node_file;
249 std::string ele_file;
250 if (tetgen_file_kind == TetGenFile::Ele) {
252 node_file = filename.substr(0, filename.size() - 4) +
".node";
254 else if (tetgen_file_kind == TetGenFile::Node) {
255 ele_file = filename.substr(0, filename.size() - 5) +
".ele";
256 node_file = filename;
259 throw std::runtime_error(
"Unhandled TetGen file type");
262 std::ifstream node_stream(node_file);
264 throw std::runtime_error(std::string(
"Tetgen node file `") + node_file
265 +
"` does not exist or is not readable");
267 std::ifstream ele_stream(ele_file);
269 throw std::runtime_error(std::string(
"Tetgen ele file `") + ele_file
270 +
"` does not exist or is not readable");
273 auto nodes = internal::parse_tetgen_node_file(node_stream, info);
274 auto elts = internal::parse_tetgen_ele_file(ele_stream, info);
275 auto media = internal::find_tetgen_elt_media(elts);
276 return EGS_MeshSpec(std::move(elts), std::move(nodes), std::move(media));
281 #endif // EGS_MESH_TETGEN_PARSER_
A 3D point. Units are cm.
A tetrahedral mesh element.
A medium. The medium name must match an EGSnrc medium name.
A container for raw unstructured tetrahedral mesh data.
Tetrahedral mesh geometry: header.
void(* EGS_InfoFunction)(const char *,...)
Defines a function printf-like prototype for functions to be used to report info, warnings...