OGS
FileIO::TetGenInterface Class Referencefinal

Detailed Description

class TetGenInterface is used to read file formats used by TetGen. Currently supported formats are: poly - Geometric point and surface definition node - mesh node / geometric point definition ele - mesh element definition

Definition at line 31 of file TetGenInterface.h.

#include <TetGenInterface.h>

Public Member Functions

 TetGenInterface ()
bool readTetGenGeometry (std::string const &geo_fname, GeoLib::GEOObjects &geo_objects)
MeshLib::MeshreadTetGenMesh (std::string const &nodes_fname, std::string const &ele_fname)
bool writeTetGenSmesh (const std::string &file_name, const MeshLib::Mesh &mesh, std::vector< MeshLib::Node > &attribute_points) const

Static Public Member Functions

static bool writeTetGenSmesh (const std::string &file_name, const GeoLib::GEOObjects &geo_objects, const std::string &geo_name, const std::vector< GeoLib::Point > &attribute_points)

Private Member Functions

std::size_t getNFacets (std::ifstream &input)
 Returns the declared number of facets in the poly file.
bool parseSmeshFacets (std::ifstream &input, std::vector< GeoLib::Surface * > &surfaces, const std::vector< GeoLib::Point * > &points, const std::vector< std::size_t > &pnt_id_map)
bool readNodesFromStream (std::ifstream &ins, std::vector< MeshLib::Node * > &nodes)
bool parseNodes (std::ifstream &ins, std::vector< MeshLib::Node * > &nodes, std::size_t n_nodes, std::size_t dim)
bool readElementsFromStream (std::ifstream &ins, std::vector< MeshLib::Element * > &elements, std::vector< int > &materials, const std::vector< MeshLib::Node * > &nodes) const
bool parseElements (std::ifstream &ins, std::vector< MeshLib::Element * > &elements, std::vector< int > &materials, const std::vector< MeshLib::Node * > &nodes, std::size_t n_tets, std::size_t n_nodes_per_tet, bool region_attribute) const
void write2dElements (std::ofstream &out, const MeshLib::Mesh &mesh) const
void write3dElements (std::ofstream &out, const MeshLib::Mesh &mesh, std::vector< MeshLib::Node > &attribute_points) const

Static Private Member Functions

static bool parseNodesFileHeader (std::string const &line, std::size_t &n_nodes, std::size_t &dim, std::size_t &n_attributes, bool &boundary_markers)
static bool parseElementsFileHeader (std::string &line, std::size_t &n_tets, std::size_t &n_nodes_per_tet, bool &region_attribute)
static void writeElementToFacets (std::ofstream &out, const MeshLib::Element &element, unsigned &element_count, std::string const &matId)

Private Attributes

bool _zero_based_idx {false}
 the value is true if the indexing is zero based, else false
bool _boundary_markers {false}
 true if boundary markers are set, false otherwise

Constructor & Destructor Documentation

◆ TetGenInterface()

FileIO::TetGenInterface::TetGenInterface ( )
default

Member Function Documentation

◆ getNFacets()

std::size_t FileIO::TetGenInterface::getNFacets ( std::ifstream & input)
private

Returns the declared number of facets in the poly file.

Definition at line 82 of file TetGenInterface.cpp.

83{
84 std::string line;
85 while (!input.fail())
86 {
87 std::getline(input, line);
88 if (input.fail())
89 {
90 ERR("TetGenInterface::getNFacets(): Error reading number of "
91 "facets.");
92 return 0;
93 }
94
96 if (line.empty() || line.compare(0, 1, "#") == 0)
97 {
98 continue;
99 }
100
101 const std::list<std::string> fields = BaseLib::splitString(line, ' ');
102 auto it = fields.begin();
103 const auto nFacets(BaseLib::str2number<std::size_t>(*it));
104 if (fields.size() > 1)
105 {
107 }
108 return nFacets;
109 }
110 return 0;
111}
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
bool _boundary_markers
true if boundary markers are set, false otherwise
void simplify(std::string &str)
std::vector< std::string > splitString(std::string const &str)
T str2number(const std::string &str)
Definition StringTools.h:53

References _boundary_markers, ERR(), BaseLib::simplify(), BaseLib::splitString(), and BaseLib::str2number().

Referenced by parseSmeshFacets().

◆ parseElements()

bool FileIO::TetGenInterface::parseElements ( std::ifstream & ins,
std::vector< MeshLib::Element * > & elements,
std::vector< int > & materials,
const std::vector< MeshLib::Node * > & nodes,
std::size_t n_tets,
std::size_t n_nodes_per_tet,
bool region_attribute ) const
private

Method parses the tetrahedras and put them in the element vector of the mesh class.

Parameters
insthe input stream
elementsthe elements vector to be filled
materialsthe vector containing material ids to be filled
nodesthe node information needed for creating elements
n_tetsthe number of tetrahedras that should be read
n_nodes_per_tetthe number of nodes per tetrahedron
region_attributeif region attribute is true, region information is read
Returns
true, if the tetrahedras are read, false if the method detects an error

Definition at line 490 of file TetGenInterface.cpp.

497{
498 std::string line;
499 std::vector<std::size_t> ids(n_nodes_per_tet);
500
501 elements.reserve(n_tets);
502 materials.reserve(n_tets);
503
504 const unsigned offset = (_zero_based_idx) ? 0 : 1;
505 for (std::size_t k(0); k < n_tets && !ins.fail(); k++)
506 {
507 std::getline(ins, line);
508 if (ins.fail())
509 {
510 ERR("TetGenInterface::parseElements(): Error reading tetrahedron "
511 "{:d}.",
512 k);
513 return false;
514 }
515
516 std::size_t pos_end = 0;
517 std::size_t pos_beg = line.find_first_not_of(' ', pos_end);
518 pos_end = line.find_first_of(" \n", pos_beg);
519
520 if (line.empty() || pos_beg == pos_end ||
521 line.compare(pos_beg, 1, "#") == 0)
522 {
523 k--;
524 continue;
525 }
526
527 if (pos_beg == std::string::npos || pos_end == std::string::npos)
528 {
529 ERR("TetGenInterface::parseElements(): Error reading id of "
530 "tetrahedron {:d}.",
531 k);
532 return false;
533 }
534
535 // read node ids
536 for (std::size_t i(0); i < n_nodes_per_tet; i++)
537 {
538 pos_beg = line.find_first_not_of(' ', pos_end);
539 pos_end = line.find_first_of(' ', pos_beg);
540 if (pos_end == std::string::npos)
541 {
542 pos_end = line.size();
543 }
544 if (pos_beg != std::string::npos && pos_end != std::string::npos)
545 {
547 line.substr(pos_beg, pos_end - pos_beg)) -
548 offset;
549 }
550 else
551 {
552 ERR("TetGenInterface::parseElements(): Error reading node {:d} "
553 "of tetrahedron {:d}.",
554 i,
555 k);
556 return false;
557 }
558 }
559
560 // read region attribute - this is something like material group
561 int region(0);
562 if (region_attribute)
563 {
564 pos_beg = line.find_first_not_of(' ', pos_end);
565 pos_end = line.find_first_of(' ', pos_beg);
566 if (pos_end == std::string::npos)
567 {
568 pos_end = line.size();
569 }
570 if (pos_beg != std::string::npos && pos_end != std::string::npos)
571 {
573 line.substr(pos_beg, pos_end - pos_beg));
574 }
575 else
576 {
577 ERR("TetGenInterface::parseElements(): Error reading region "
578 "attribute of tetrahedron {:d}.",
579 k);
580 return false;
581 }
582 }
583 // insert new element into vector
584 auto** tet_nodes = new MeshLib::Node*[4];
585 for (int n = 0; n < 4; n++)
586 {
587 tet_nodes[n] = nodes[ids[n]];
588 }
589 elements.push_back(new MeshLib::Tet(tet_nodes));
590 materials.push_back(region);
591 }
592
593 return true;
594}
bool _zero_based_idx
the value is true if the indexing is zero based, else false
constexpr ranges::views::view_closure ids
For an element of a range view return its id.
Definition Mesh.h:216
TemplateElement< MeshLib::TetRule4 > Tet
Definition Tet.h:14

References _zero_based_idx, ERR(), and BaseLib::str2number().

Referenced by readElementsFromStream().

◆ parseElementsFileHeader()

bool FileIO::TetGenInterface::parseElementsFileHeader ( std::string & line,
std::size_t & n_tets,
std::size_t & n_nodes_per_tet,
bool & region_attribute )
staticprivate

Method parses the header of the elements file created by TetGen

Parameters
linethe header is in this string (input)
n_tetsthe number of tets to read (input)
n_nodes_per_tetthe number of nodes per tets (input)
region_attributeis on output true, if there
Returns

Definition at line 451 of file TetGenInterface.cpp.

455{
456 std::size_t pos_beg;
457 std::size_t pos_end;
458
459 // number of tetrahedras
460 pos_beg = line.find_first_not_of(' ');
461 pos_end = line.find_first_of(' ', pos_beg);
462 if (pos_beg != std::string::npos && pos_end != std::string::npos)
463 {
465 line.substr(pos_beg, pos_end - pos_beg));
466 }
467 else
468 {
469 ERR("TetGenInterface::parseElementsFileHeader(): Could not read number "
470 "of tetrahedra specified in header.");
471 return false;
472 }
473 // nodes per tet - either 4 or 10
474 pos_beg = line.find_first_not_of(" \t", pos_end);
475 pos_end = line.find_first_of(" \t", pos_beg);
476 n_nodes_per_tet = BaseLib::str2number<std::size_t>(
477 line.substr(pos_beg, pos_end - pos_beg));
478 // region attribute at tetrahedra?
479 pos_beg = line.find_first_not_of(" \t", pos_end);
480 pos_end = line.find_first_of(" \t\n", pos_beg);
481 if (pos_end == std::string::npos)
482 {
483 pos_end = line.size();
484 }
485 region_attribute = line.substr(pos_beg, pos_end - pos_beg) == "1";
486
487 return true;
488}

References ERR(), and BaseLib::str2number().

Referenced by readElementsFromStream().

◆ parseNodes()

bool FileIO::TetGenInterface::parseNodes ( std::ifstream & ins,
std::vector< MeshLib::Node * > & nodes,
std::size_t n_nodes,
std::size_t dim )
private

method parses the lines reading the nodes from TetGen nodes file

Parameters
insthe input stream (input)
nodesthe nodes vector to be filled (input)
n_nodesthe number of nodes to read (input)
dimthe spatial dimension of the node (input)
Returns
true, if the nodes are read, false if the method detects an error

Definition at line 328 of file TetGenInterface.cpp.

332{
333 std::string line;
334 nodes.reserve(n_nodes);
335
336 std::size_t k(0);
337 while (k < n_nodes && !ins.fail())
338 {
339 std::vector<double> coordinates(dim);
340 std::getline(ins, line);
341 if (ins.fail())
342 {
343 ERR("TetGenInterface::parseNodes(): Error reading node {:d}.", k);
344 return false;
345 }
346
347 std::size_t id;
348 std::size_t pos_end = 0;
349 std::size_t pos_beg = line.find_first_not_of(' ', pos_end);
350 pos_end = line.find_first_of(" \n", pos_beg);
351
352 if (line.empty() || pos_beg == pos_end ||
353 line.compare(pos_beg, 1, "#") == 0)
354 {
355 continue;
356 }
357
358 if (pos_beg != std::string::npos && pos_end != std::string::npos)
359 {
361 line.substr(pos_beg, pos_end - pos_beg));
362 if (k == 0 && id == 0)
363 {
364 _zero_based_idx = true;
365 }
366 }
367 else
368 {
369 ERR("TetGenInterface::parseNodes(): Error reading ID of node {:d}.",
370 k);
371 return false;
372 }
373 // read coordinates
374 const unsigned offset = (_zero_based_idx) ? 0 : 1;
375 for (std::size_t i(0); i < dim; i++)
376 {
377 pos_beg = line.find_first_not_of(' ', pos_end);
378 pos_end = line.find_first_of(" \n", pos_beg);
379 if (pos_end == std::string::npos)
380 {
381 pos_end = line.size();
382 }
383 if (pos_beg != std::string::npos)
384 {
385 coordinates[i] = BaseLib::str2number<double>(
386 line.substr(pos_beg, pos_end - pos_beg));
387 }
388 else
389 {
390 ERR("TetGenInterface::parseNodes(): error reading coordinate "
391 "{:d} of node {:d}.",
392 i,
393 k);
394 return false;
395 }
396 }
397
398 nodes.push_back(new MeshLib::Node(coordinates.data(), id - offset));
399 // read attributes and boundary markers ... - at the moment we do not
400 // use this information
401 ++k;
402 }
403
404 return true;
405}

References _zero_based_idx, ERR(), and BaseLib::str2number().

Referenced by readNodesFromStream().

◆ parseNodesFileHeader()

bool FileIO::TetGenInterface::parseNodesFileHeader ( std::string const & line,
std::size_t & n_nodes,
std::size_t & dim,
std::size_t & n_attributes,
bool & boundary_markers )
staticprivate

Method parses the header of the nodes file created by TetGen

Parameters
linethe header is in this string (input)
n_nodesnumber of nodes in the file (output)
dimthe spatial dimension of the node (output)
n_attributesthe number of attributes for each node (output)
boundary_markershave the nodes boundary information (output)
Returns
true, if the file header is read, false if the method detects an error

Definition at line 297 of file TetGenInterface.cpp.

302{
303 std::list<std::string> pnt_header = BaseLib::splitString(line, ' ');
304 if (pnt_header.empty())
305 {
306 ERR("TetGenInterface::parseNodesFileHeader(): could not read number of "
307 "nodes specified in header.");
308 return false;
309 }
310 auto it = pnt_header.begin();
312 dim = (pnt_header.size() == 1) ? 3
314
315 if (pnt_header.size() < 4)
316 {
317 n_attributes = 0;
318 boundary_markers = false;
319 return true;
320 }
321
322 n_attributes = BaseLib::str2number<std::size_t>(*(++it));
323 boundary_markers = *(++it) == "1";
324
325 return true;
326}

References ERR(), BaseLib::splitString(), and BaseLib::str2number().

Referenced by readNodesFromStream().

◆ parseSmeshFacets()

bool FileIO::TetGenInterface::parseSmeshFacets ( std::ifstream & input,
std::vector< GeoLib::Surface * > & surfaces,
const std::vector< GeoLib::Point * > & points,
const std::vector< std::size_t > & pnt_id_map )
private

Method parses the lines reading the facets from TetGen smesh file

Parameters
inputthe input stream (input)
surfacesthe vector of surfaces to be filled (output)
pointsthe point vector needed for creating surfaces (input)
pnt_id_mapthe id map to compensate for possibly changed point ids after adding the point vector to GEOObjects
Returns
true, if the facets have been read correctly, false if the method detects an error

Definition at line 113 of file TetGenInterface.cpp.

118{
119 const std::size_t nFacets(this->getNFacets(input));
120 std::string line;
121 surfaces.reserve(nFacets);
122 std::list<std::string>::const_iterator it;
123
124 const unsigned offset = (_zero_based_idx) ? 0 : 1;
125 std::vector<std::size_t> idx_map;
126
127 std::size_t k(0);
128 while (k < nFacets && !input.fail())
129 {
130 std::getline(input, line);
131 if (input.fail())
132 {
133 ERR("TetGenInterface::parseFacets(): Error reading facet {:d}.", k);
134 return false;
135 }
136
137 BaseLib::simplify(line);
138 if (line.empty() || line.compare(0, 1, "#") == 0)
139 {
140 continue;
141 }
142
143 // read facets
144 const std::list<std::string> point_fields =
145 BaseLib::splitString(line, ' ');
146 it = point_fields.begin();
147 const auto nPoints = BaseLib::str2number<std::size_t>(*it);
148 if (nPoints != 3)
149 {
150 ERR("Smesh-files are currently only supported for triangle "
151 "meshes.");
152 return false;
153 }
154 const std::size_t point_field_size =
155 (_boundary_markers) ? nPoints + 1 : nPoints;
156 if (point_fields.size() > point_field_size)
157 {
158 std::vector<std::size_t> point_ids;
159 for (std::size_t j(0); j < nPoints; ++j)
160 {
161 point_ids.push_back(
162 pnt_id_map[BaseLib::str2number<std::size_t>(*(++it)) -
163 offset]);
164 }
165
166 const std::size_t sfc_marker =
168 : 0;
169 const std::size_t idx =
170 std::find(idx_map.begin(), idx_map.end(), sfc_marker) -
171 idx_map.begin();
172 if (idx >= surfaces.size())
173 {
174 idx_map.push_back(sfc_marker);
175 surfaces.push_back(new GeoLib::Surface(points));
176 }
177 surfaces[idx]->addTriangle(point_ids[0], point_ids[1],
178 point_ids[2]);
179 }
180 else
181 {
182 ERR("TetGenInterface::parseFacets(): Error reading points for "
183 "facet {:d}.",
184 k);
185 return false;
186 }
187 ++k;
188 }
189 // here the poly-file potentially defines a number of points to mark holes
190 // within the volumes defined by the facets, these are ignored for now here
191 // the poly-file potentially defines a number of region attributes, these
192 // are ignored for now
193
194 auto const nTotalTriangles = ranges::accumulate(
195 surfaces, std::size_t{0}, {},
196 [](auto const* surface) { return surface->getNumberOfTriangles(); });
197 if (nTotalTriangles == nFacets)
198 {
199 return true;
200 }
201
202 ERR("TetGenInterface::parseFacets(): Number of expected total triangles "
203 "({:d}) does not match number of found triangles ({:d}).",
204 surfaces.size(),
205 nTotalTriangles);
206 return false;
207}
std::size_t getNFacets(std::ifstream &input)
Returns the declared number of facets in the poly file.

References _boundary_markers, _zero_based_idx, ERR(), getNFacets(), BaseLib::simplify(), BaseLib::splitString(), and BaseLib::str2number().

Referenced by readTetGenGeometry().

◆ readElementsFromStream()

bool FileIO::TetGenInterface::readElementsFromStream ( std::ifstream & ins,
std::vector< MeshLib::Element * > & elements,
std::vector< int > & materials,
const std::vector< MeshLib::Node * > & nodes ) const
private

Method reads the elements from stream and stores them in an element vector. For this purpose it uses methods parseElementsFileHeader() and parseElements().

Parameters
insthe input stream
elementsthe elements vector to be filled
materialsthe vector containing material ids to be filled
nodesthe node information needed for creating elements
Returns
true, if all information is read, false if the method detects an error

Definition at line 407 of file TetGenInterface.cpp.

412{
413 std::string line;
414 std::getline(ins, line);
415 std::size_t n_tets;
416 std::size_t n_nodes_per_tet;
417 bool region_attributes;
418
419 while (!ins.fail())
420 {
421 BaseLib::simplify(line);
422 if (line.empty() || line.compare(0, 1, "#") == 0)
423 {
424 // this line is a comment - skip
425 std::getline(ins, line);
426 continue;
427 }
428
429 // read header line
430 bool header_okay = parseElementsFileHeader(
431 line, n_tets, n_nodes_per_tet, region_attributes);
432 if (!header_okay)
433 {
434 return false;
435 }
436 if (!parseElements(ins,
437 elements,
438 materials,
439 nodes,
440 n_tets,
441 n_nodes_per_tet,
442 region_attributes))
443 {
444 return false;
445 }
446 return true;
447 }
448 return false;
449}
static bool parseElementsFileHeader(std::string &line, std::size_t &n_tets, std::size_t &n_nodes_per_tet, bool &region_attribute)
bool parseElements(std::ifstream &ins, std::vector< MeshLib::Element * > &elements, std::vector< int > &materials, const std::vector< MeshLib::Node * > &nodes, std::size_t n_tets, std::size_t n_nodes_per_tet, bool region_attribute) const

References parseElements(), parseElementsFileHeader(), and BaseLib::simplify().

Referenced by readTetGenMesh().

◆ readNodesFromStream()

bool FileIO::TetGenInterface::readNodesFromStream ( std::ifstream & ins,
std::vector< MeshLib::Node * > & nodes )
private

Method reads the nodes from stream and stores them in a node vector. For this purpose it uses methods parseNodesFileHeader() and parseNodes().

Parameters
insthe input stream
nodesoutput vector of nodes.
Returns
true, if all information is read, false if the method detects an error

Definition at line 262 of file TetGenInterface.cpp.

264{
265 std::string line;
266 std::getline(ins, line);
267 std::size_t n_nodes;
268 std::size_t dim;
269 std::size_t n_attributes;
270 bool boundary_markers;
271
272 while (!ins.fail())
273 {
274 BaseLib::simplify(line);
275 if (line.empty() || line.compare(0, 1, "#") == 0)
276 {
277 // this line is a comment - skip
278 std::getline(ins, line);
279 continue;
280 }
281 // read header line
282 bool header_okay = parseNodesFileHeader(line, n_nodes, dim,
283 n_attributes, boundary_markers);
284 if (!header_okay)
285 {
286 return false;
287 }
288 if (!parseNodes(ins, nodes, n_nodes, dim))
289 {
290 return false;
291 }
292 return true;
293 }
294 return false;
295}
bool parseNodes(std::ifstream &ins, std::vector< MeshLib::Node * > &nodes, std::size_t n_nodes, std::size_t dim)
static bool parseNodesFileHeader(std::string const &line, std::size_t &n_nodes, std::size_t &dim, std::size_t &n_attributes, bool &boundary_markers)

References parseNodes(), parseNodesFileHeader(), and BaseLib::simplify().

Referenced by readTetGenGeometry(), and readTetGenMesh().

◆ readTetGenGeometry()

bool FileIO::TetGenInterface::readTetGenGeometry ( std::string const & geo_fname,
GeoLib::GEOObjects & geo_objects )

Method reads geometry from a TetGen poly or smesh file.

Parameters
geo_fnamefile name of the poly file
geo_objectswhere the geometry is written to
Returns
on success the method returns true, otherwise it returns false

Definition at line 35 of file TetGenInterface.cpp.

37{
38 std::ifstream poly_stream(geo_fname.c_str());
39
40 if (!poly_stream)
41 {
42 ERR("TetGenInterface::readTetGenGeometry() failed to open {:s}",
43 geo_fname);
44 return false;
45 }
46 std::string ext(BaseLib::getFileExtension(geo_fname));
47 if (ext != ".smesh")
48 {
49 ERR("TetGenInterface::readTetGenGeometry() - unknown file type (only "
50 "*.smesh is supported).");
51 return false;
52 }
53
54 std::vector<MeshLib::Node*> nodes;
55 if (!readNodesFromStream(poly_stream, nodes))
56 {
57 // remove nodes read until now
59 return false;
60 }
61 auto points = constructPointsFromNodes(nodes);
63
64 std::string geo_name(BaseLib::extractBaseNameWithoutExtension(geo_fname));
65 geo_objects.addPointVec(std::move(points), geo_name);
66 const std::vector<std::size_t>& id_map(
67 geo_objects.getPointVecObj(geo_name)->getIDMap());
68
69 std::vector<GeoLib::Surface*> surfaces;
70 if (!parseSmeshFacets(poly_stream, surfaces,
71 *geo_objects.getPointVec(geo_name), id_map))
72 {
73 // remove surfaces read until now but keep the points
75 }
76 geo_objects.addSurfaceVec(std::move(surfaces), geo_name,
78
79 return true;
80}
bool readNodesFromStream(std::ifstream &ins, std::vector< MeshLib::Node * > &nodes)
bool parseSmeshFacets(std::ifstream &input, std::vector< GeoLib::Surface * > &surfaces, const std::vector< GeoLib::Point * > &points, const std::vector< std::size_t > &pnt_id_map)
const std::vector< Point * > * getPointVec(const std::string &name) const
void addPointVec(std::vector< Point * > &&points, std::string &name, PointVec::NameIdMap &&pnt_id_name_map, double const eps=std::sqrt(std::numeric_limits< double >::epsilon()))
const PointVec * getPointVecObj(const std::string &name) const
void addSurfaceVec(std::vector< Surface * > &&sfc, const std::string &name, SurfaceVec::NameIdMap &&sfc_names)
const std::vector< std::size_t > & getIDMap() const
Definition PointVec.h:86
std::map< std::string, std::size_t > NameIdMap
Definition TemplateVec.h:30
std::string getFileExtension(const std::string &path)
void cleanupVectorElements(std::vector< T * > &items)
Definition Algorithm.h:249
std::string extractBaseNameWithoutExtension(std::string const &pathname)
auto constructPointsFromNodes(std::vector< MeshLib::Node * > nodes)

References GeoLib::GEOObjects::addPointVec(), GeoLib::GEOObjects::addSurfaceVec(), BaseLib::cleanupVectorElements(), FileIO::constructPointsFromNodes(), ERR(), BaseLib::extractBaseNameWithoutExtension(), BaseLib::getFileExtension(), GeoLib::PointVec::getIDMap(), GeoLib::GEOObjects::getPointVec(), GeoLib::GEOObjects::getPointVecObj(), parseSmeshFacets(), and readNodesFromStream().

Referenced by MainWindow::loadFile().

◆ readTetGenMesh()

MeshLib::Mesh * FileIO::TetGenInterface::readTetGenMesh ( std::string const & nodes_fname,
std::string const & ele_fname )

Method reads the TetGen mesh from node file and element file.

Parameters
nodes_fnamefile name of the nodes file
ele_fnamefile name of the elements file
Returns
on success the method returns a (pointer to a) CFEMesh, else the method returns nullptr

Definition at line 209 of file TetGenInterface.cpp.

211{
212 std::ifstream ins_nodes(nodes_fname.c_str());
213 std::ifstream ins_ele(ele_fname.c_str());
214
215 if (!ins_nodes || !ins_ele)
216 {
217 if (!ins_nodes)
218 {
219 ERR("TetGenInterface::readTetGenMesh failed to open {:s}",
220 nodes_fname);
221 }
222 if (!ins_ele)
223 {
224 ERR("TetGenInterface::readTetGenMesh failed to open {:s}",
225 ele_fname);
226 }
227 return nullptr;
228 }
229
230 std::vector<MeshLib::Node*> nodes;
231 if (!readNodesFromStream(ins_nodes, nodes))
232 {
233 // remove nodes read until now
235 return nullptr;
236 }
237
238 std::vector<MeshLib::Element*> elements;
239 std::vector<int> materials;
240 if (!readElementsFromStream(ins_ele, elements, materials, nodes))
241 {
242 BaseLib::cleanupVectorElements(nodes, elements);
243 return nullptr;
244 }
245
246 MeshLib::Properties properties;
247 // Transmit material values if there is any material value != 0
248 if (std::any_of(materials.cbegin(), materials.cend(),
249 [](int m) { return m != 0; }))
250 {
251 auto* const mat_props = properties.createNewPropertyVector<int>(
252 "MaterialIDs", MeshLib::MeshItemType::Cell);
253 mat_props->assign(materials);
254 }
255
256 const std::string mesh_name(
258 return new MeshLib::Mesh(mesh_name, nodes, elements,
259 true /* compute_element_neighbors */, properties);
260}
bool readElementsFromStream(std::ifstream &ins, std::vector< MeshLib::Element * > &elements, std::vector< int > &materials, const std::vector< MeshLib::Node * > &nodes) const
PropertyVector< T > * createNewPropertyVector(std::string_view name, MeshItemType mesh_item_type, std::size_t n_components=1)
constexpr void assign(R &&r)

References MeshLib::PropertyVector< PROP_VAL_TYPE >::assign(), MeshLib::Cell, BaseLib::cleanupVectorElements(), MeshLib::Properties::createNewPropertyVector(), ERR(), BaseLib::extractBaseNameWithoutExtension(), readElementsFromStream(), and readNodesFromStream().

Referenced by MainWindow::loadFile().

◆ write2dElements()

void FileIO::TetGenInterface::write2dElements ( std::ofstream & out,
const MeshLib::Mesh & mesh ) const
private

Writes the elements from a 2D mesh to a TetGen smesh-file.

Parameters
outthe output stream the information is written to.
meshmesh containing the subsurface boundary representation used for meshing.

Definition at line 737 of file TetGenInterface.cpp.

739{
740 // the surfaces header
741 auto const& types =
743 std::size_t const n_tri =
744 (types.find(MeshLib::MeshElemType::TRIANGLE) != types.end())
746 : 0;
747 std::size_t const n_quad =
748 (types.find(MeshLib::MeshElemType::QUAD) != types.end())
750 : 0;
751 unsigned const nTotalTriangles = n_tri + 2 * n_quad;
752 out << nTotalTriangles << " 1\n";
753
754 const std::vector<MeshLib::Element*>& elements = mesh.getElements();
755 MeshLib::PropertyVector<int> const* const mat_ids =
756 mesh.getProperties().existsPropertyVector<int>("MaterialIDs")
757 ? mesh.getProperties().getPropertyVector<int>("MaterialIDs")
758 : nullptr;
759 const std::size_t nElements(elements.size());
760 unsigned element_count(0);
761 for (std::size_t i = 0; i < nElements; ++i)
762 {
763 std::string const matId = mat_ids ? std::to_string((*mat_ids)[i]) : "";
764 this->writeElementToFacets(out, *elements[i], element_count, matId);
765 }
766}
static void writeElementToFacets(std::ofstream &out, const MeshLib::Element &element, unsigned &element_count, std::string const &matId)
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition Mesh.h:100
Properties & getProperties()
Definition Mesh.h:125
bool existsPropertyVector(std::string_view name) const
PropertyVector< T > const * getPropertyVector(std::string_view name) const
static std::map< MeshLib::MeshElemType, unsigned > getNumberOfElementTypes(const MeshLib::Mesh &mesh)

References MeshLib::Properties::existsPropertyVector(), MeshLib::Mesh::getElements(), MeshToolsLib::MeshInformation::getNumberOfElementTypes(), MeshLib::Mesh::getProperties(), MeshLib::Properties::getPropertyVector(), MeshLib::QUAD, MeshLib::TRIANGLE, and writeElementToFacets().

Referenced by writeTetGenSmesh().

◆ write3dElements()

void FileIO::TetGenInterface::write3dElements ( std::ofstream & out,
const MeshLib::Mesh & mesh,
std::vector< MeshLib::Node > & attribute_points ) const
private

Writes the elements from a 3D mesh to a TetGen smesh-file.

Parameters
outthe output stream the information is written to.
meshthe 3D mesh.
attribute_pointsattribute points containing material IDs (emptied when called and then filled with correct values).

Definition at line 768 of file TetGenInterface.cpp.

772{
773 const std::vector<MeshLib::Element*>& elements = mesh.getElements();
774 const std::size_t nElements(elements.size());
775 if (!attribute_points.empty())
776 {
777 attribute_points.clear();
778 }
779
780 // get position where number of facets need to be written and figure out
781 // worst case of chars that are needed
782 const std::streamoff before_elems_pos(out.tellp());
783 const unsigned n_spaces(
784 static_cast<unsigned>(std::floor(log(nElements * 8))) + 1);
785 out << std::string(n_spaces, ' ') << " 1\n";
786 auto const* const materialIds =
787 mesh.getProperties().getPropertyVector<int>("MaterialIDs");
788 unsigned element_count(0);
789 for (std::size_t i = 0; i < nElements; ++i)
790 {
791 if (elements[i]->getDimension() < 3)
792 {
793 continue;
794 }
795
796 const unsigned nFaces(elements[i]->getNumberOfNeighbors());
797 std::string const mat_id_str =
798 materialIds ? std::to_string((*materialIds)[i]) : "";
799 for (std::size_t j = 0; j < nFaces; ++j)
800 {
801 MeshLib::Element const* const neighbor(elements[i]->getNeighbor(j));
802
803 if (neighbor && materialIds &&
804 (*materialIds)[i] <= (*materialIds)[neighbor->getID()])
805 {
806 continue;
807 }
808
809 std::unique_ptr<MeshLib::Element const> const face(
810 elements[i]->getFace(j));
811 this->writeElementToFacets(out, *face, element_count, mat_id_str);
812 }
813 if (materialIds)
814 {
815 attribute_points.emplace_back(
816 MeshLib::getCenterOfGravity(*elements[i]).data(),
817 (*materialIds)[i]);
818 }
819 }
820 // add number of facets at correct position and jump back
821 const std::streamoff after_elems_pos(out.tellp());
822 out.seekp(before_elems_pos);
823 out << element_count;
824 out.seekp(after_elems_pos);
825}
MathLib::Point3d getCenterOfGravity(Element const &element)
Calculates the center of gravity for the mesh element.
Definition Element.cpp:131
unsigned getDimension(MeshLib::MeshElemType eleType)

References MeshLib::getCenterOfGravity(), MeshLib::Mesh::getElements(), MeshLib::Element::getID(), MeshLib::Mesh::getProperties(), MeshLib::Properties::getPropertyVector(), and writeElementToFacets().

Referenced by writeTetGenSmesh().

◆ writeElementToFacets()

void FileIO::TetGenInterface::writeElementToFacets ( std::ofstream & out,
const MeshLib::Element & element,
unsigned & element_count,
std::string const & matId )
staticprivate

Writes facet information from a 2D element to the stream and increments the total element count accordingly

Definition at line 827 of file TetGenInterface.cpp.

831{
832 element_count++;
834 {
835 out << "3 " << getNodeIndex(element, 0) << " "
836 << getNodeIndex(element, 1) << " " << getNodeIndex(element, 2)
837 << " " << matId << " # " << element_count << "\n";
838 }
839 else if (element.getGeomType() == MeshLib::MeshElemType::QUAD)
840 {
841 out << "3 " << getNodeIndex(element, 0) << " "
842 << getNodeIndex(element, 1) << " " << getNodeIndex(element, 2)
843 << " " << matId << " # " << element_count << "\n";
844 element_count++;
845 out << "3 " << getNodeIndex(element, 0) << " "
846 << getNodeIndex(element, 2) << " " << getNodeIndex(element, 3)
847 << " " << matId << " # " << element_count << "\n";
848 }
849}
virtual MeshElemType getGeomType() const =0
std::size_t getNodeIndex(Element const &element, unsigned const idx)
Definition Element.cpp:226

References MeshLib::Element::getGeomType(), MeshLib::QUAD, and MeshLib::TRIANGLE.

Referenced by write2dElements(), and write3dElements().

◆ writeTetGenSmesh() [1/2]

bool FileIO::TetGenInterface::writeTetGenSmesh ( const std::string & file_name,
const GeoLib::GEOObjects & geo_objects,
const std::string & geo_name,
const std::vector< GeoLib::Point > & attribute_points )
static

Writes the geometry of a given name to TetGen smesh-file.

Parameters
file_namefile name of the new smesh file.
geo_objectsthe container for the geometry.
geo_namethe name for the geometry containing the subsurface boundary representation used for meshing.
attribute_pointsattribute points containing material IDs (if the vector is empty no attributes are written).
Returns
returns true on success and false otherwise.

Definition at line 596 of file TetGenInterface.cpp.

601{
602 std::vector<GeoLib::Point*> const* const points =
603 geo_objects.getPointVec(geo_name);
604 std::vector<GeoLib::Surface*> const* const surfaces =
605 geo_objects.getSurfaceVec(geo_name);
606
607 if (points == nullptr)
608 {
609 ERR("Geometry {:s} not found.", geo_name);
610 return false;
611 }
612 if (surfaces == nullptr)
613 {
614 WARN("No surfaces found for geometry {:s}. Writing points only.",
615 geo_name);
616 }
617
618 std::ofstream out(file_name.c_str(), std::ios::out);
619 out.precision(std::numeric_limits<double>::max_digits10);
620 // the points header
621 const std::size_t nPoints(points->size());
622 out << nPoints << " 3\n";
623 // the point list
624 for (std::size_t i = 0; i < nPoints; ++i)
625 {
626 out << i << " " << (*(*points)[i])[0] << " " << (*(*points)[i])[1]
627 << " " << (*(*points)[i])[2] << "\n";
628 }
629 // the surfaces header
630 const std::size_t nSurfaces = (surfaces) ? surfaces->size() : 0;
631 std::size_t nTotalTriangles(0);
632 for (std::size_t i = 0; i < nSurfaces; ++i)
633 {
634 nTotalTriangles += (*surfaces)[i]->getNumberOfTriangles();
635 }
636 out << nTotalTriangles << " 1\n";
637
638 for (std::size_t i = 0; i < nSurfaces; ++i)
639 {
640 const std::size_t nTriangles((*surfaces)[i]->getNumberOfTriangles());
641 const std::size_t marker(i + 1); // must NOT be 0!
642 // the poly list
643 for (std::size_t j = 0; j < nTriangles; ++j)
644 {
645 const GeoLib::Triangle& tri = *(*(*surfaces)[i])[j];
646 out << "3 " << tri[0] << " " << tri[1] << " " << tri[2] << " "
647 << marker << "\n";
648 }
649 }
650 out << "0\n"; // the polygon holes list
651 // the region attributes list
652 if (attribute_points.empty())
653 {
654 out << "0\n";
655 }
656 else
657 {
658 const std::size_t nAttributePoints(attribute_points.size());
659 out << nAttributePoints << "\n";
660 for (std::size_t i = 0; i < nAttributePoints; ++i)
661 {
662 out << i + 1 << " " << attribute_points[i][0] << " "
663 << attribute_points[i][1] << " " << attribute_points[i][2]
664 << " " << 10 * attribute_points[i].getID() << "\n";
665 }
666 }
667 INFO(
668 "TetGenInterface::writeTetGenSmesh() - {:d} points and {:d} surfaces "
669 "successfully written.",
670 nPoints,
671 nSurfaces);
672 out.close();
673 return true;
674}
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
const std::vector< Surface * > * getSurfaceVec(const std::string &name) const
Returns the surface vector with the given name as a const.

References ERR(), GeoLib::GEOObjects::getPointVec(), GeoLib::GEOObjects::getSurfaceVec(), INFO(), and WARN().

Referenced by MeshLayerEditDialog::createTetMesh(), MeshView::exportToTetGen(), and main().

◆ writeTetGenSmesh() [2/2]

bool FileIO::TetGenInterface::writeTetGenSmesh ( const std::string & file_name,
const MeshLib::Mesh & mesh,
std::vector< MeshLib::Node > & attribute_points ) const

Writes the geometry of a given name to TetGen smesh-file.

Parameters
file_namefile name of the new smesh file.
meshmesh containing the subsurface boundary representation used for meshing.
attribute_pointsattribute points containing material IDs (if the vector is empty no attributes are written).
Returns
returns true on success and false otherwise.

Definition at line 676 of file TetGenInterface.cpp.

680{
681 if (mesh.getDimension() == 1)
682 {
683 return false;
684 }
685
686 const std::vector<MeshLib::Node*>& nodes = mesh.getNodes();
687
688 std::ofstream out(file_name.c_str(), std::ios::out);
689 out.precision(std::numeric_limits<double>::max_digits10);
690 // the points header
691 const std::size_t nPoints(nodes.size());
692 out << nPoints << " 3\n";
693 // the point list
694 for (std::size_t i = 0; i < nPoints; ++i)
695 {
696 out << i << " " << (*nodes[i])[0] << " " << (*nodes[i])[1] << " "
697 << (*nodes[i])[2] << "\n";
698 }
699
700 if (mesh.getDimension() == 2)
701 {
702 write2dElements(out, mesh);
703 }
704 else
705 {
706 write3dElements(out, mesh, attribute_points);
707 }
708
709 out << "0\n"; // the polygon holes list
710
711 // the region attributes list
712 if (attribute_points.empty())
713 {
714 out << "0\n";
715 }
716 else
717 {
718 const std::size_t nAttributePoints(attribute_points.size());
719 out << nAttributePoints << "\n";
720 for (std::size_t i = 0; i < nAttributePoints; ++i)
721 {
722 out << i + 1 << " " << attribute_points[i][0] << " "
723 << attribute_points[i][1] << " " << attribute_points[i][2]
724 << " " << 10 * attribute_points[i].getID() << "\n";
725 }
726 }
727
728 INFO(
729 "TetGenInterface::writeTetGenPoly() - {:d} points and {:d} surfaces "
730 "successfully written.",
731 nPoints,
732 mesh.getNumberOfElements());
733 out.close();
734 return true;
735}
void write3dElements(std::ofstream &out, const MeshLib::Mesh &mesh, std::vector< MeshLib::Node > &attribute_points) const
void write2dElements(std::ofstream &out, const MeshLib::Mesh &mesh) const
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
Definition Mesh.h:97
unsigned getDimension() const
Returns the dimension of the mesh (determined by the maximum dimension over all elements).
Definition Mesh.h:79
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:88

References MeshLib::Mesh::getDimension(), MeshLib::Mesh::getNodes(), MeshLib::Mesh::getNumberOfElements(), INFO(), write2dElements(), and write3dElements().

Member Data Documentation

◆ _boundary_markers

bool FileIO::TetGenInterface::_boundary_markers {false}
private

true if boundary markers are set, false otherwise

Definition at line 222 of file TetGenInterface.h.

222{false};

Referenced by getNFacets(), and parseSmeshFacets().

◆ _zero_based_idx

bool FileIO::TetGenInterface::_zero_based_idx {false}
private

the value is true if the indexing is zero based, else false

Definition at line 219 of file TetGenInterface.h.

219{false};

Referenced by parseElements(), parseNodes(), and parseSmeshFacets().


The documentation for this class was generated from the following files: