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 40 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)
 Writes facet information from a 2D element to the stream and increments the total element count accordingly.
 

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 93 of file TetGenInterface.cpp.

94{
95 std::string line;
96 while (!input.fail())
97 {
98 std::getline(input, line);
99 if (input.fail())
100 {
101 ERR("TetGenInterface::getNFacets(): Error reading number of "
102 "facets.");
103 return 0;
104 }
105
106 BaseLib::simplify(line);
107 if (line.empty() || line.compare(0, 1, "#") == 0)
108 {
109 continue;
110 }
111
112 const std::list<std::string> fields = BaseLib::splitString(line, ' ');
113 auto it = fields.begin();
114 const auto nFacets(BaseLib::str2number<std::size_t>(*it));
115 if (fields.size() > 1)
116 {
117 _boundary_markers = BaseLib::str2number<std::size_t>(*(++it)) != 0;
118 }
119 return nFacets;
120 }
121 return 0;
122}
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition: Logging.h:45
bool _boundary_markers
true if boundary markers are set, false otherwise
void simplify(std::string &str)
Definition: StringTools.cpp:77
std::vector< std::string > splitString(std::string const &str)
Definition: StringTools.cpp:29

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

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 504 of file TetGenInterface.cpp.

511{
512 std::string line;
513 std::vector<std::size_t> ids(n_nodes_per_tet);
514
515 elements.reserve(n_tets);
516 materials.reserve(n_tets);
517
518 const unsigned offset = (_zero_based_idx) ? 0 : 1;
519 for (std::size_t k(0); k < n_tets && !ins.fail(); k++)
520 {
521 std::getline(ins, line);
522 if (ins.fail())
523 {
524 ERR("TetGenInterface::parseElements(): Error reading tetrahedron "
525 "{:d}.",
526 k);
527 return false;
528 }
529
530 std::size_t pos_end = 0;
531 std::size_t pos_beg = line.find_first_not_of(' ', pos_end);
532 pos_end = line.find_first_of(" \n", pos_beg);
533
534 if (line.empty() || pos_beg == pos_end ||
535 line.compare(pos_beg, 1, "#") == 0)
536 {
537 k--;
538 continue;
539 }
540
541 if (pos_beg == std::string::npos || pos_end == std::string::npos)
542 {
543 ERR("TetGenInterface::parseElements(): Error reading id of "
544 "tetrahedron {:d}.",
545 k);
546 return false;
547 }
548
549 // read node ids
550 for (std::size_t i(0); i < n_nodes_per_tet; i++)
551 {
552 pos_beg = line.find_first_not_of(' ', pos_end);
553 pos_end = line.find_first_of(' ', pos_beg);
554 if (pos_end == std::string::npos)
555 {
556 pos_end = line.size();
557 }
558 if (pos_beg != std::string::npos && pos_end != std::string::npos)
559 {
560 ids[i] = BaseLib::str2number<std::size_t>(
561 line.substr(pos_beg, pos_end - pos_beg)) -
562 offset;
563 }
564 else
565 {
566 ERR("TetGenInterface::parseElements(): Error reading node {:d} "
567 "of tetrahedron {:d}.",
568 i,
569 k);
570 return false;
571 }
572 }
573
574 // read region attribute - this is something like material group
575 int region(0);
576 if (region_attribute)
577 {
578 pos_beg = line.find_first_not_of(' ', pos_end);
579 pos_end = line.find_first_of(' ', pos_beg);
580 if (pos_end == std::string::npos)
581 {
582 pos_end = line.size();
583 }
584 if (pos_beg != std::string::npos && pos_end != std::string::npos)
585 {
586 region = BaseLib::str2number<int>(
587 line.substr(pos_beg, pos_end - pos_beg));
588 }
589 else
590 {
591 ERR("TetGenInterface::parseElements(): Error reading region "
592 "attribute of tetrahedron {:d}.",
593 k);
594 return false;
595 }
596 }
597 // insert new element into vector
598 auto** tet_nodes = new MeshLib::Node*[4];
599 for (int n = 0; n < 4; n++)
600 {
601 tet_nodes[n] = nodes[ids[n]];
602 }
603 elements.push_back(new MeshLib::Tet(tet_nodes));
604 materials.push_back(region);
605 }
606
607 return true;
608}
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:225

References _zero_based_idx, and ERR().

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 465 of file TetGenInterface.cpp.

469{
470 std::size_t pos_beg;
471 std::size_t pos_end;
472
473 // number of tetrahedras
474 pos_beg = line.find_first_not_of(' ');
475 pos_end = line.find_first_of(' ', pos_beg);
476 if (pos_beg != std::string::npos && pos_end != std::string::npos)
477 {
478 n_tets = BaseLib::str2number<std::size_t>(
479 line.substr(pos_beg, pos_end - pos_beg));
480 }
481 else
482 {
483 ERR("TetGenInterface::parseElementsFileHeader(): Could not read number "
484 "of tetrahedra specified in header.");
485 return false;
486 }
487 // nodes per tet - either 4 or 10
488 pos_beg = line.find_first_not_of(" \t", pos_end);
489 pos_end = line.find_first_of(" \t", pos_beg);
490 n_nodes_per_tet = BaseLib::str2number<std::size_t>(
491 line.substr(pos_beg, pos_end - pos_beg));
492 // region attribute at tetrahedra?
493 pos_beg = line.find_first_not_of(" \t", pos_end);
494 pos_end = line.find_first_of(" \t\n", pos_beg);
495 if (pos_end == std::string::npos)
496 {
497 pos_end = line.size();
498 }
499 region_attribute = line.substr(pos_beg, pos_end - pos_beg) == "1";
500
501 return true;
502}

References ERR().

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 342 of file TetGenInterface.cpp.

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

References _zero_based_idx, and ERR().

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 311 of file TetGenInterface.cpp.

316{
317 std::list<std::string> pnt_header = BaseLib::splitString(line, ' ');
318 if (pnt_header.empty())
319 {
320 ERR("TetGenInterface::parseNodesFileHeader(): could not read number of "
321 "nodes specified in header.");
322 return false;
323 }
324 auto it = pnt_header.begin();
325 n_nodes = BaseLib::str2number<std::size_t>(*it);
326 dim = (pnt_header.size() == 1) ? 3
327 : BaseLib::str2number<std::size_t>(*(++it));
328
329 if (pnt_header.size() < 4)
330 {
331 n_attributes = 0;
332 boundary_markers = false;
333 return true;
334 }
335
336 n_attributes = BaseLib::str2number<std::size_t>(*(++it));
337 boundary_markers = *(++it) == "1";
338
339 return true;
340}

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

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 124 of file TetGenInterface.cpp.

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

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

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 421 of file TetGenInterface.cpp.

426{
427 std::string line;
428 std::getline(ins, line);
429 std::size_t n_tets;
430 std::size_t n_nodes_per_tet;
431 bool region_attributes;
432
433 while (!ins.fail())
434 {
435 BaseLib::simplify(line);
436 if (line.empty() || line.compare(0, 1, "#") == 0)
437 {
438 // this line is a comment - skip
439 std::getline(ins, line);
440 continue;
441 }
442
443 // read header line
444 bool header_okay = parseElementsFileHeader(
445 line, n_tets, n_nodes_per_tet, region_attributes);
446 if (!header_okay)
447 {
448 return false;
449 }
450 if (!parseElements(ins,
451 elements,
452 materials,
453 nodes,
454 n_tets,
455 n_nodes_per_tet,
456 region_attributes))
457 {
458 return false;
459 }
460 return true;
461 }
462 return false;
463}
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 276 of file TetGenInterface.cpp.

278{
279 std::string line;
280 std::getline(ins, line);
281 std::size_t n_nodes;
282 std::size_t dim;
283 std::size_t n_attributes;
284 bool boundary_markers;
285
286 while (!ins.fail())
287 {
288 BaseLib::simplify(line);
289 if (line.empty() || line.compare(0, 1, "#") == 0)
290 {
291 // this line is a comment - skip
292 std::getline(ins, line);
293 continue;
294 }
295 // read header line
296 bool header_okay = parseNodesFileHeader(line, n_nodes, dim,
297 n_attributes, boundary_markers);
298 if (!header_okay)
299 {
300 return false;
301 }
302 if (!parseNodes(ins, nodes, n_nodes, dim))
303 {
304 return false;
305 }
306 return true;
307 }
308 return false;
309}
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 46 of file TetGenInterface.cpp.

48{
49 std::ifstream poly_stream(geo_fname.c_str());
50
51 if (!poly_stream)
52 {
53 ERR("TetGenInterface::readTetGenGeometry() failed to open {:s}",
54 geo_fname);
55 return false;
56 }
57 std::string ext(BaseLib::getFileExtension(geo_fname));
58 if (ext != ".smesh")
59 {
60 ERR("TetGenInterface::readTetGenGeometry() - unknown file type (only "
61 "*.smesh is supported).");
62 return false;
63 }
64
65 std::vector<MeshLib::Node*> nodes;
66 if (!readNodesFromStream(poly_stream, nodes))
67 {
68 // remove nodes read until now
70 return false;
71 }
72 auto points = constructPointsFromNodes(nodes);
74
75 std::string geo_name(BaseLib::extractBaseNameWithoutExtension(geo_fname));
76 geo_objects.addPointVec(std::move(points), geo_name);
77 const std::vector<std::size_t>& id_map(
78 geo_objects.getPointVecObj(geo_name)->getIDMap());
79
80 std::vector<GeoLib::Surface*> surfaces;
81 if (!parseSmeshFacets(poly_stream, surfaces,
82 *geo_objects.getPointVec(geo_name), id_map))
83 {
84 // remove surfaces read until now but keep the points
86 }
87 geo_objects.addSurfaceVec(std::move(surfaces), geo_name,
89
90 return true;
91}
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
Definition: GEOObjects.cpp:72
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()))
Definition: GEOObjects.cpp:47
const PointVec * getPointVecObj(const std::string &name) const
Definition: GEOObjects.cpp:85
void addSurfaceVec(std::vector< Surface * > &&sfc, const std::string &name, SurfaceVec::NameIdMap &&sfc_names)
Definition: GEOObjects.cpp:240
const std::vector< std::size_t > & getIDMap() const
Definition: PointVec.h:96
std::map< std::string, std::size_t > NameIdMap
Definition: TemplateVec.h:43
std::string getFileExtension(const std::string &path)
Definition: FileTools.cpp:193
void cleanupVectorElements(std::vector< T * > &items)
Definition: Algorithm.h:253
std::string extractBaseNameWithoutExtension(std::string const &pathname)
Definition: FileTools.cpp:187
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 220 of file TetGenInterface.cpp.

222{
223 std::ifstream ins_nodes(nodes_fname.c_str());
224 std::ifstream ins_ele(ele_fname.c_str());
225
226 if (!ins_nodes || !ins_ele)
227 {
228 if (!ins_nodes)
229 {
230 ERR("TetGenInterface::readTetGenMesh failed to open {:s}",
231 nodes_fname);
232 }
233 if (!ins_ele)
234 {
235 ERR("TetGenInterface::readTetGenMesh failed to open {:s}",
236 ele_fname);
237 }
238 return nullptr;
239 }
240
241 std::vector<MeshLib::Node*> nodes;
242 if (!readNodesFromStream(ins_nodes, nodes))
243 {
244 // remove nodes read until now
246 return nullptr;
247 }
248
249 std::vector<MeshLib::Element*> elements;
250 std::vector<int> materials;
251 if (!readElementsFromStream(ins_ele, elements, materials, nodes))
252 {
253 BaseLib::cleanupVectorElements(nodes, elements);
254 return nullptr;
255 }
256
257 MeshLib::Properties properties;
258 // Transmit material values if there is any material value != 0
259 if (std::any_of(materials.cbegin(), materials.cend(),
260 [](int m) { return m != 0; }))
261 {
262 auto* const mat_props = properties.createNewPropertyVector<int>(
263 "MaterialIDs", MeshLib::MeshItemType::Cell);
264 mat_props->reserve(elements.size());
265 std::copy(materials.cbegin(),
266 materials.cend(),
267 std::back_inserter(*mat_props));
268 }
269
270 const std::string mesh_name(
272 return new MeshLib::Mesh(mesh_name, nodes, elements,
273 true /* compute_element_neighbors */, properties);
274}
bool readElementsFromStream(std::ifstream &ins, std::vector< MeshLib::Element * > &elements, std::vector< int > &materials, const std::vector< MeshLib::Node * > &nodes) const
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
Definition: Properties.h:36
PropertyVector< T > * createNewPropertyVector(std::string_view name, MeshItemType mesh_item_type, std::size_t n_components=1)

References 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 751 of file TetGenInterface.cpp.

753{
754 // the surfaces header
755 auto const& types =
757 std::size_t const n_tri =
758 (types.find(MeshLib::MeshElemType::TRIANGLE) != types.end())
760 : 0;
761 std::size_t const n_quad =
762 (types.find(MeshLib::MeshElemType::QUAD) != types.end())
764 : 0;
765 unsigned const nTotalTriangles = n_tri + 2 * n_quad;
766 out << nTotalTriangles << " 1\n";
767
768 const std::vector<MeshLib::Element*>& elements = mesh.getElements();
769 MeshLib::PropertyVector<int> const* const mat_ids =
770 mesh.getProperties().existsPropertyVector<int>("MaterialIDs")
771 ? mesh.getProperties().getPropertyVector<int>("MaterialIDs")
772 : nullptr;
773 const std::size_t nElements(elements.size());
774 unsigned element_count(0);
775 for (std::size_t i = 0; i < nElements; ++i)
776 {
777 std::string const matId = mat_ids ? std::to_string((*mat_ids)[i]) : "";
778 this->writeElementToFacets(out, *elements[i], element_count, matId);
779 }
780}
static void writeElementToFacets(std::ofstream &out, const MeshLib::Element &element, unsigned &element_count, std::string const &matId)
Writes facet information from a 2D element to the stream and increments the total element count accor...
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition: Mesh.h:109
Properties & getProperties()
Definition: Mesh.h:134
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 782 of file TetGenInterface.cpp.

786{
787 const std::vector<MeshLib::Element*>& elements = mesh.getElements();
788 const std::size_t nElements(elements.size());
789 if (!attribute_points.empty())
790 {
791 attribute_points.clear();
792 }
793
794 // get position where number of facets need to be written and figure out
795 // worst case of chars that are needed
796 const std::streamoff before_elems_pos(out.tellp());
797 const unsigned n_spaces(
798 static_cast<unsigned>(std::floor(log(nElements * 8))) + 1);
799 out << std::string(n_spaces, ' ') << " 1\n";
800 auto const* const materialIds =
801 mesh.getProperties().getPropertyVector<int>("MaterialIDs");
802 unsigned element_count(0);
803 for (std::size_t i = 0; i < nElements; ++i)
804 {
805 if (elements[i]->getDimension() < 3)
806 {
807 continue;
808 }
809
810 const unsigned nFaces(elements[i]->getNumberOfNeighbors());
811 std::string const mat_id_str =
812 materialIds ? std::to_string((*materialIds)[i]) : "";
813 for (std::size_t j = 0; j < nFaces; ++j)
814 {
815 MeshLib::Element const* const neighbor(elements[i]->getNeighbor(j));
816
817 if (neighbor && materialIds &&
818 (*materialIds)[i] <= (*materialIds)[neighbor->getID()])
819 {
820 continue;
821 }
822
823 std::unique_ptr<MeshLib::Element const> const face(
824 elements[i]->getFace(j));
825 this->writeElementToFacets(out, *face, element_count, mat_id_str);
826 }
827 if (materialIds)
828 {
829 attribute_points.emplace_back(
830 MeshLib::getCenterOfGravity(*elements[i]).data(),
831 (*materialIds)[i]);
832 }
833 }
834 // add number of facets at correct position and jump back
835 const std::streamoff after_elems_pos(out.tellp());
836 out.seekp(before_elems_pos);
837 out << element_count;
838 out.seekp(after_elems_pos);
839}
MathLib::Point3d getCenterOfGravity(Element const &element)
Calculates the center of gravity for the mesh element.
Definition: Element.cpp:124
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 841 of file TetGenInterface.cpp.

845{
846 element_count++;
848 {
849 out << "3 " << getNodeIndex(element, 0) << " "
850 << getNodeIndex(element, 1) << " " << getNodeIndex(element, 2)
851 << " " << matId << " # " << element_count << "\n";
852 }
853 else if (element.getGeomType() == MeshLib::MeshElemType::QUAD)
854 {
855 out << "3 " << getNodeIndex(element, 0) << " "
856 << getNodeIndex(element, 1) << " " << getNodeIndex(element, 2)
857 << " " << matId << " # " << element_count << "\n";
858 element_count++;
859 out << "3 " << getNodeIndex(element, 0) << " "
860 << getNodeIndex(element, 2) << " " << getNodeIndex(element, 3)
861 << " " << matId << " # " << element_count << "\n";
862 }
863}
virtual MeshElemType getGeomType() const =0
std::size_t getNodeIndex(Element const &element, unsigned const idx)
Definition: Element.cpp:219

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 610 of file TetGenInterface.cpp.

615{
616 std::vector<GeoLib::Point*> const* const points =
617 geo_objects.getPointVec(geo_name);
618 std::vector<GeoLib::Surface*> const* const surfaces =
619 geo_objects.getSurfaceVec(geo_name);
620
621 if (points == nullptr)
622 {
623 ERR("Geometry {:s} not found.", geo_name);
624 return false;
625 }
626 if (surfaces == nullptr)
627 {
628 WARN("No surfaces found for geometry {:s}. Writing points only.",
629 geo_name);
630 }
631
632 std::ofstream out(file_name.c_str(), std::ios::out);
633 out.precision(std::numeric_limits<double>::digits10);
634 // the points header
635 const std::size_t nPoints(points->size());
636 out << nPoints << " 3\n";
637 // the point list
638 for (std::size_t i = 0; i < nPoints; ++i)
639 {
640 out << i << " " << (*(*points)[i])[0] << " " << (*(*points)[i])[1]
641 << " " << (*(*points)[i])[2] << "\n";
642 }
643 // the surfaces header
644 const std::size_t nSurfaces = (surfaces) ? surfaces->size() : 0;
645 std::size_t nTotalTriangles(0);
646 for (std::size_t i = 0; i < nSurfaces; ++i)
647 {
648 nTotalTriangles += (*surfaces)[i]->getNumberOfTriangles();
649 }
650 out << nTotalTriangles << " 1\n";
651
652 for (std::size_t i = 0; i < nSurfaces; ++i)
653 {
654 const std::size_t nTriangles((*surfaces)[i]->getNumberOfTriangles());
655 const std::size_t marker(i + 1); // must NOT be 0!
656 // the poly list
657 for (std::size_t j = 0; j < nTriangles; ++j)
658 {
659 const GeoLib::Triangle& tri = *(*(*surfaces)[i])[j];
660 out << "3 " << tri[0] << " " << tri[1] << " " << tri[2] << " "
661 << marker << "\n";
662 }
663 }
664 out << "0\n"; // the polygon holes list
665 // the region attributes list
666 if (attribute_points.empty())
667 {
668 out << "0\n";
669 }
670 else
671 {
672 const std::size_t nAttributePoints(attribute_points.size());
673 out << nAttributePoints << "\n";
674 for (std::size_t i = 0; i < nAttributePoints; ++i)
675 {
676 out << i + 1 << " " << attribute_points[i][0] << " "
677 << attribute_points[i][1] << " " << attribute_points[i][2]
678 << " " << 10 * attribute_points[i].getID() << "\n";
679 }
680 }
681 INFO(
682 "TetGenInterface::writeTetGenSmesh() - {:d} points and {:d} surfaces "
683 "successfully written.",
684 nPoints,
685 nSurfaces);
686 out.close();
687 return true;
688}
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition: Logging.h:35
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition: Logging.h:40
const std::vector< Surface * > * getSurfaceVec(const std::string &name) const
Returns the surface vector with the given name as a const.
Definition: GEOObjects.cpp:270
Class Triangle consists of a reference to a point vector and a vector that stores the indices in the ...
Definition: Triangle.h:27

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 690 of file TetGenInterface.cpp.

694{
695 if (mesh.getDimension() == 1)
696 {
697 return false;
698 }
699
700 const std::vector<MeshLib::Node*>& nodes = mesh.getNodes();
701
702 std::ofstream out(file_name.c_str(), std::ios::out);
703 out.precision(std::numeric_limits<double>::digits10);
704 // the points header
705 const std::size_t nPoints(nodes.size());
706 out << nPoints << " 3\n";
707 // the point list
708 for (std::size_t i = 0; i < nPoints; ++i)
709 {
710 out << i << " " << (*nodes[i])[0] << " " << (*nodes[i])[1] << " "
711 << (*nodes[i])[2] << "\n";
712 }
713
714 if (mesh.getDimension() == 2)
715 {
716 write2dElements(out, mesh);
717 }
718 else
719 {
720 write3dElements(out, mesh, attribute_points);
721 }
722
723 out << "0\n"; // the polygon holes list
724
725 // the region attributes list
726 if (attribute_points.empty())
727 {
728 out << "0\n";
729 }
730 else
731 {
732 const std::size_t nAttributePoints(attribute_points.size());
733 out << nAttributePoints << "\n";
734 for (std::size_t i = 0; i < nAttributePoints; ++i)
735 {
736 out << i + 1 << " " << attribute_points[i][0] << " "
737 << attribute_points[i][1] << " " << attribute_points[i][2]
738 << " " << 10 * attribute_points[i].getID() << "\n";
739 }
740 }
741
742 INFO(
743 "TetGenInterface::writeTetGenPoly() - {:d} points and {:d} surfaces "
744 "successfully written.",
745 nPoints,
746 mesh.getNumberOfElements());
747 out.close();
748 return true;
749}
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:106
unsigned getDimension() const
Returns the dimension of the mesh (determined by the maximum dimension over all elements).
Definition: Mesh.h:88
std::size_t getNumberOfElements() const
Get the number of elements.
Definition: Mesh.h:97

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 219 of file TetGenInterface.h.

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 216 of file TetGenInterface.h.

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


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