OGS
TetGenInterface.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "TetGenInterface.h"
5
6#include <cstddef>
7#include <fstream>
8#include <range/v3/numeric/accumulate.hpp>
9#include <string>
10
11#include "BaseLib/FileTools.h"
12#include "BaseLib/Logging.h"
13#include "BaseLib/StringTools.h"
14#include "GeoLib/Triangle.h"
17#include "MeshLib/Mesh.h"
18#include "MeshLib/Node.h"
20
21namespace FileIO
22{
24
25auto constructPointsFromNodes(std::vector<MeshLib::Node*> nodes)
26{
27 std::vector<GeoLib::Point*> points;
28 points.reserve(nodes.size());
29 std::transform(nodes.begin(), nodes.end(), std::back_inserter(points),
30 [](auto const* node)
31 { return new GeoLib::Point(*node, node->getID()); });
32 return points;
33}
34
35bool TetGenInterface::readTetGenGeometry(std::string const& geo_fname,
36 GeoLib::GEOObjects& geo_objects)
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}
81
82std::size_t TetGenInterface::getNFacets(std::ifstream& input)
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}
112
114 std::ifstream& input,
115 std::vector<GeoLib::Surface*>& surfaces,
116 const std::vector<GeoLib::Point*>& points,
117 const std::vector<std::size_t>& pnt_id_map)
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}
208
209MeshLib::Mesh* TetGenInterface::readTetGenMesh(std::string const& nodes_fname,
210 std::string const& ele_fname)
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}
261
263 std::vector<MeshLib::Node*>& nodes)
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}
296
297bool TetGenInterface::parseNodesFileHeader(std::string const& line,
298 std::size_t& n_nodes,
299 std::size_t& dim,
300 std::size_t& n_attributes,
301 bool& boundary_markers)
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}
327
328bool TetGenInterface::parseNodes(std::ifstream& ins,
329 std::vector<MeshLib::Node*>& nodes,
330 std::size_t n_nodes,
331 std::size_t dim)
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}
406
408 std::ifstream& ins,
409 std::vector<MeshLib::Element*>& elements,
410 std::vector<int>& materials,
411 const std::vector<MeshLib::Node*>& nodes) const
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}
450
452 std::size_t& n_tets,
453 std::size_t& n_nodes_per_tet,
454 bool& region_attribute)
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}
489
490bool TetGenInterface::parseElements(std::ifstream& ins,
491 std::vector<MeshLib::Element*>& elements,
492 std::vector<int>& materials,
493 const std::vector<MeshLib::Node*>& nodes,
494 std::size_t n_tets,
495 std::size_t n_nodes_per_tet,
496 bool region_attribute) const
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}
595
597 const std::string& file_name,
598 const GeoLib::GEOObjects& geo_objects,
599 const std::string& geo_name,
600 const std::vector<GeoLib::Point>& attribute_points)
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}
675
677 const std::string& file_name,
678 const MeshLib::Mesh& mesh,
679 std::vector<MeshLib::Node>& attribute_points) const
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}
736
737void TetGenInterface::write2dElements(std::ofstream& out,
738 const MeshLib::Mesh& mesh) const
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}
767
769 std::ofstream& out,
770 const MeshLib::Mesh& mesh,
771 std::vector<MeshLib::Node>& attribute_points) const
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}
826
828 const MeshLib::Element& element,
829 unsigned& element_count,
830 std::string const& matId)
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}
850
851} // end namespace FileIO
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
bool readElementsFromStream(std::ifstream &ins, std::vector< MeshLib::Element * > &elements, std::vector< int > &materials, const std::vector< MeshLib::Node * > &nodes) const
bool _boundary_markers
true if boundary markers are set, false otherwise
MeshLib::Mesh * readTetGenMesh(std::string const &nodes_fname, std::string const &ele_fname)
bool parseNodes(std::ifstream &ins, std::vector< MeshLib::Node * > &nodes, std::size_t n_nodes, std::size_t dim)
static bool parseElementsFileHeader(std::string &line, std::size_t &n_tets, std::size_t &n_nodes_per_tet, bool &region_attribute)
void write3dElements(std::ofstream &out, const MeshLib::Mesh &mesh, std::vector< MeshLib::Node > &attribute_points) const
bool readNodesFromStream(std::ifstream &ins, std::vector< MeshLib::Node * > &nodes)
static bool parseNodesFileHeader(std::string const &line, std::size_t &n_nodes, std::size_t &dim, std::size_t &n_attributes, bool &boundary_markers)
bool _zero_based_idx
the value is true if the indexing is zero based, else false
bool readTetGenGeometry(std::string const &geo_fname, GeoLib::GEOObjects &geo_objects)
void write2dElements(std::ofstream &out, const MeshLib::Mesh &mesh) 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
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)
static void writeElementToFacets(std::ofstream &out, const MeshLib::Element &element, unsigned &element_count, std::string const &matId)
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)
std::size_t getNFacets(std::ifstream &input)
Returns the declared number of facets in the poly file.
Container class for geometric objects.
Definition GEOObjects.h:46
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
const std::vector< Surface * > * getSurfaceVec(const std::string &name) const
Returns the surface vector with the given name as a 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
A Surface is represented by Triangles. It consists of a reference to a vector of (pointers to) points...
std::map< std::string, std::size_t > NameIdMap
Definition TemplateVec.h:30
Class Triangle consists of a reference to a point vector and a vector that stores the indices in the ...
Definition Triangle.h:21
virtual MeshElemType getGeomType() const =0
std::size_t getID() const
Returns the ID of the element.
Definition Element.h:80
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
Definition Mesh.h:97
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition Mesh.h:100
unsigned getDimension() const
Returns the dimension of the mesh (determined by the maximum dimension over all elements).
Definition Mesh.h:79
Properties & getProperties()
Definition Mesh.h:125
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:88
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
bool existsPropertyVector(std::string_view name) const
PropertyVector< T > * createNewPropertyVector(std::string_view name, MeshItemType mesh_item_type, std::size_t n_components=1)
PropertyVector< T > const * getPropertyVector(std::string_view name) const
constexpr void assign(R &&r)
static std::map< MeshLib::MeshElemType, unsigned > getNumberOfElementTypes(const MeshLib::Mesh &mesh)
void simplify(std::string &str)
std::string getFileExtension(const std::string &path)
void cleanupVectorElements(std::vector< T * > &items)
Definition Algorithm.h:249
std::string extractBaseNameWithoutExtension(std::string const &pathname)
std::vector< std::string > splitString(std::string const &str)
T str2number(const std::string &str)
Definition StringTools.h:53
auto constructPointsFromNodes(std::vector< MeshLib::Node * > nodes)
TemplateElement< MeshLib::TetRule4 > Tet
Definition Tet.h:14
MathLib::Point3d getCenterOfGravity(Element const &element)
Calculates the center of gravity for the mesh element.
Definition Element.cpp:131