7#include <range/v3/algorithm/copy.hpp>
8#include <range/v3/algorithm/transform.hpp>
9#include <range/v3/range/conversion.hpp>
10#include <range/v3/view/transform.hpp>
27 if ((id1 == 0 && id2 == 1) || (id1 == 1 && id2 == 0))
31 if ((id1 == 1 && id2 == 2) || (id1 == 2 && id2 == 1))
35 if ((id1 == 0 && id2 == 2) || (id1 == 2 && id2 == 0))
39 if ((id1 == 3 && id2 == 4) || (id1 == 4 && id2 == 3))
43 if ((id1 == 4 && id2 == 5) || (id1 == 5 && id2 == 4))
47 if ((id1 == 3 && id2 == 5) || (id1 == 5 && id2 == 3))
51 return std::numeric_limits<unsigned>::max();
57template <
typename ElementType>
59 std::span<MeshLib::Node* const>
const element_nodes,
60 std::vector<MeshLib::Node*>
const& nodes,
61 std::array<std::size_t, ElementType::n_all_nodes>
const local_ids)
64 auto lookup_in = [](
auto const& values)
66 return ranges::views::transform([&values](std::size_t
const n)
67 {
return values[n]; });
70 std::array<MeshLib::Node*, ElementType::n_all_nodes> new_nodes;
71 ranges::copy(local_ids | lookup_in(element_nodes) |
ids | lookup_in(nodes),
74 return std::make_unique<ElementType>(new_nodes);
79 std::vector<MeshLib::Node*>
const& nodes,
80 std::vector<MeshLib::Element*>& new_elements)
82 std::array<std::size_t, 3>
const tri1_node_ids{0, 1, 2};
83 new_elements.push_back(
87 std::array<std::size_t, 3>
const tri2_node_ids{0, 2, 3};
88 new_elements.push_back(
97 std::vector<MeshLib::Node*>
const& nodes,
98 std::vector<MeshLib::Element*>& new_elements)
100 auto addTetrahedron =
101 [&prism, &nodes, &new_elements](std::array<std::size_t, 4>
const ids)
103 new_elements.push_back(
107 addTetrahedron({0, 1, 2, 3});
108 addTetrahedron({3, 2, 4, 5});
109 addTetrahedron({2, 1, 3, 4});
116 std::vector<MeshLib::Node*>
const& nodes,
117 std::vector<MeshLib::Element*>& new_elements)
132 std::vector<MeshLib::Node*>
const& nodes,
133 std::vector<MeshLib::Element*>& new_elements)
135 auto addTetrahedron =
136 [&pyramid, &nodes, &new_elements](std::array<std::size_t, 4>
const ids)
138 new_elements.push_back(
143 addTetrahedron({0, 1, 2, 4});
144 addTetrahedron({0, 2, 3, 4});
152 const std::vector<MeshLib::Node*>& nodes)
154 std::array<std::size_t, 2> line_node_ids = {0, 0};
159 line_node_ids[1] = i;
163 assert(line_node_ids[1] != 0);
171 const std::vector<MeshLib::Node*>& nodes)
177 std::array<MeshLib::Node*, 3> tri_nodes;
179 tri_nodes[2] =
nullptr;
182 if (element->
getNode(i)->
getID() != tri_nodes[0]->getID())
187 if (element->
getNode(j)->
getID() != tri_nodes[1]->getID())
199 assert(tri_nodes[2] !=
nullptr);
207 std::vector<MeshLib::Node*>
const& nodes,
208 unsigned const min_elem_dim = 1)
210 std::array<MeshLib::Node*, 4> new_nodes;
212 new_nodes[count++] = nodes[element->
getNode(0)->
getID()];
219 bool unique_node(
true);
220 for (
unsigned j = 0; j < i; ++j)
230 new_nodes[count++] = nodes[element->
getNode(i)->
getID()];
236 *new_nodes[2], *new_nodes[3]));
237 if (isQuad && min_elem_dim < 3)
240 for (
unsigned i = 1; i < 3; ++i)
249 new_nodes[i + 1] = new_nodes[i];
266 unsigned const n_unique_nodes,
267 std::vector<MeshLib::Node*>
const& nodes,
268 std::vector<MeshLib::Element*>& new_elements,
269 unsigned const min_elem_dim)
271 if (n_unique_nodes == 4)
277 new_elements.push_back(elem);
280 else if (n_unique_nodes == 3 && min_elem_dim < 3)
284 else if (n_unique_nodes == 2 && min_elem_dim == 1)
294 unsigned const n_unique_nodes,
295 std::vector<MeshLib::Node*>
const& nodes,
296 std::vector<MeshLib::Element*>& new_elements,
297 unsigned const min_elem_dim)
299 auto addTetrahedron =
300 [&org_elem, &nodes, &new_elements](std::array<std::size_t, 4>
const ids)
302 new_elements.push_back(
314 if (n_unique_nodes == 5)
316 for (
unsigned i = 0; i < 5; ++i)
318 for (
unsigned j = i + 1; j < 6; ++j)
327 {(i + 1) % 3, (i + 2) % 3, i, (i + 1) % 3 + 3});
329 {(i + 1) % 3 + 3, (i + 2) % 3, i, (i + 2) % 3 + 3});
334 const unsigned i_offset = (i > 2) ? i - 3 : i + 3;
335 const unsigned j_offset = (i > 2) ? j - 3 : j + 3;
337 if (k == std::numeric_limits<unsigned>::max())
339 ERR(
"Unexpected error during prism reduction.");
342 const unsigned k_offset = (i > 2) ? k - 3 : k + 3;
344 addTetrahedron({i_offset, j_offset, k_offset, i});
353 const unsigned l_offset = (i > 2) ? l - 3 : l + 3;
354 addTetrahedron({l_offset, k_offset, i, k});
360 else if (n_unique_nodes == 4)
366 new_elements.push_back(elem);
369 else if (n_unique_nodes == 3 && min_elem_dim < 3)
373 else if (n_unique_nodes == 2 && min_elem_dim == 1)
384 if (id1 == 0 && id2 == 1)
388 if (id1 == 1 && id2 == 2)
392 if (id1 == 2 && id2 == 3)
396 if (id1 == 3 && id2 == 0)
400 if (id1 == 4 && id2 == 5)
404 if (id1 == 5 && id2 == 6)
408 if (id1 == 6 && id2 == 7)
412 if (id1 == 7 && id2 == 4)
416 if (id1 == 0 && id2 == 4)
420 if (id1 == 1 && id2 == 5)
424 if (id1 == 2 && id2 == 6)
428 if (id1 == 3 && id2 == 7)
432 if (id1 == 1 && id2 == 0)
436 if (id1 == 2 && id2 == 1)
440 if (id1 == 3 && id2 == 2)
444 if (id1 == 0 && id2 == 3)
448 if (id1 == 5 && id2 == 4)
452 if (id1 == 6 && id2 == 5)
456 if (id1 == 7 && id2 == 6)
460 if (id1 == 4 && id2 == 7)
464 if (id1 == 4 && id2 == 0)
468 if (id1 == 5 && id2 == 1)
472 if (id1 == 6 && id2 == 2)
476 if (id1 == 7 && id2 == 3)
482 "lutHexCuttingQuadNodes() for nodes {} and {} does not have a valid "
491 constexpr std::array<unsigned, 8> hex_diametral_node_ids = {
492 {6, 7, 4, 5, 2, 3, 0, 1}};
494 return hex_diametral_node_ids[id];
540 return {std::numeric_limits<unsigned>::max(),
541 std::numeric_limits<unsigned>::max()};
547 std::array<std::size_t, 4>
const& base_node_ids)
550 for (std::size_t i = 0; i < nNodes; ++i)
552 bool top_node =
true;
553 for (
unsigned j = 0; j < 4; ++j)
565 return std::numeric_limits<unsigned>::max();
573 unsigned const n_unique_nodes,
574 std::vector<MeshLib::Node*>
const& nodes,
575 std::vector<MeshLib::Element*>& new_elements,
576 unsigned const min_elem_dim)
582 if (n_unique_nodes == 7)
585 for (
unsigned i = 0; i < 7; ++i)
587 for (
unsigned j = i + 1; j < 8; ++j)
592 const std::array<unsigned, 4> base_node_ids(
594 std::array<std::size_t, 5>
const pyr_node_ids = {
595 base_node_ids[0], base_node_ids[1], base_node_ids[2],
596 base_node_ids[3], i};
597 new_elements.push_back(
606 std::array<std::size_t, 6>
const prism_node_ids{
607 base_node_ids[0], base_node_ids[3],
610 new_elements.push_back(
619 else if (n_unique_nodes == 6)
622 for (
unsigned i = 0; i < 6; ++i)
628 std::array<std::size_t, 6>
const prism_node_ids{
640 new_elements.push_back(
650 std::array<std::size_t, 6>
const prism_node_ids{
661 new_elements.push_back(
672 for (
unsigned i = 0; i < 7; ++i)
674 for (
unsigned j = i + 1; j < 8; ++j)
679 for (
unsigned k = i; k < 7; ++k)
681 for (
unsigned l = k + 1; l < 8; ++l)
683 if (!(i == k && j == l) && org_elem->
isEdge(i, j) &&
688 const std::pair<unsigned, unsigned> back(
691 std::numeric_limits<unsigned>::max() ||
693 std::numeric_limits<unsigned>::max())
695 ERR(
"Unexpected error during Hex "
700 std::array<unsigned, 4>
const cutting_plane(
703 std::array<std::size_t, 6>
const pris1_node_ids{
704 back.first, cutting_plane[0],
705 cutting_plane[3], back.second,
706 cutting_plane[1], cutting_plane[2]};
708 org_elem->
nodes(), nodes, pris1_node_ids);
709 unsigned nNewElements =
711 new_elements, min_elem_dim);
713 std::array<std::size_t, 6>
const pris2_node_ids{
721 org_elem->
nodes(), nodes, pris2_node_ids);
724 new_elements, min_elem_dim);
733 else if (n_unique_nodes == 5)
736 std::array<std::size_t, 4>
const first_four_node_ids = {
739 unsigned const fifth_node =
742 bool tet_changed(
false);
747 std::array
const tet1_nodes = {
748 nodes[first_four_node_ids[0]], nodes[first_four_node_ids[1]],
749 nodes[first_four_node_ids[2]],
755 new_elements.push_back(tet1);
758 std::array
const tet2_nodes = {
759 (tet_changed) ? nodes[first_four_node_ids[0]]
760 : nodes[first_four_node_ids[1]],
761 nodes[first_four_node_ids[2]], nodes[first_four_node_ids[3]],
766 else if (n_unique_nodes == 4)
772 new_elements.push_back(elem);
776 else if (n_unique_nodes == 3 && min_elem_dim < 3)
781 else if (min_elem_dim == 1)
797 std::vector<MeshLib::Node*>
const& nodes,
798 std::vector<MeshLib::Element*>& elements)
822 unsigned const n_unique_nodes,
823 std::vector<MeshLib::Node*>
const& nodes,
824 std::vector<MeshLib::Element*>& elements,
825 unsigned const min_elem_dim)
839 if (n_unique_nodes == 3 && min_elem_dim < 3)
843 else if (min_elem_dim == 1)
851 return reduceHex(element, n_unique_nodes, nodes, elements,
856 reducePyramid(element, n_unique_nodes, nodes, elements, min_elem_dim);
861 return reducePrism(element, n_unique_nodes, nodes, elements,
865 ERR(
"Unknown element type.");
873 unsigned count(nNodes);
875 for (
unsigned i = 0; i < nNodes - 1; ++i)
877 for (
unsigned j = i + 1; j < nNodes; ++j)
892 std::vector<size_t>
const& node_ids)
894 std::size_t
const n_nodes = node_ids.size();
895 for (std::size_t i = 0; i < n_nodes; ++i)
897 if (node_ids[i] != i)
908 std::vector<size_t>
const& elem_ids)
910 assert(new_prop.
size() == old_prop.
size());
911 assert(new_prop.
size() == elem_ids.size());
912 ranges::transform(elem_ids, new_prop.
begin(),
913 [&](std::size_t
const i) { return old_prop[i]; });
920 std::vector<std::size_t>
const& node_ids,
921 std::vector<std::size_t>
const& elem_ids)
926 for (
auto name : prop_names)
988 WARN(
"PropertyVector {:s} not being converted.", name);
990 return new_properties;
1001 std::size_t
const nNodes = id_map.size();
1003 for (std::size_t i = 0; i < nNodes; ++i)
1015 unsigned const min_elem_dim)
const
1017 if (this->
_mesh.getNumberOfElements() == 0)
1022 std::vector<MeshLib::Element*>
const& elements(this->
_mesh.getElements());
1024 std::vector<MeshLib::Node*> new_nodes =
1026 std::vector<MeshLib::Element*> new_elements;
1027 std::vector<std::size_t> element_ids;
1029 for (std::size_t k(0); k < elements.size(); ++k)
1032 unsigned const n_unique_nodes(getNumberOfUniqueNodes(elem));
1039 std::size_t
const n_new_elements(
1040 subdivideElement(elem, new_nodes, new_elements));
1041 if (n_new_elements == 0)
1043 ERR(
"Element {:d} has unknown element type.", k);
1044 _mesh.resetNodeIDs();
1048 element_ids.insert(element_ids.end(), n_new_elements, k);
1053 element_ids.push_back(k);
1056 else if (n_unique_nodes < elem->getNumberOfBaseNodes() &&
1059 std::size_t
const n_new_elements(reduceElement(
1060 elem, n_unique_nodes, new_nodes, new_elements, min_elem_dim));
1061 element_ids.insert(element_ids.end(), n_new_elements, k);
1065 ERR(
"Something is wrong, more unique nodes than actual nodes");
1069 auto const& props =
_mesh.getProperties();
1071 copyProperties(props, node_ids, element_ids);
1073 _mesh.resetNodeIDs();
1074 if (!new_elements.empty())
1076 return new MeshLib::Mesh(new_mesh_name, new_nodes, new_elements,
1086 double const eps)
const
1088 const std::vector<MeshLib::Node*>& nodes(
_mesh.getNodes());
1089 const std::size_t nNodes(
_mesh.getNumberOfNodes());
1090 std::vector<std::size_t> id_map(nNodes);
1091 const double half_eps(eps / 2.0);
1092 const double sqr_eps(eps * eps);
1093 std::iota(id_map.begin(), id_map.end(), 0);
1097 for (std::size_t k = 0; k < nNodes; ++k)
1100 if (node->
getID() != k)
1104 std::vector<std::vector<MeshLib::Node*>
const*>
const node_vectors(
1107 const std::size_t nVectors(node_vectors.size());
1108 for (std::size_t i = 0; i < nVectors; ++i)
1110 const std::vector<MeshLib::Node*>& cell_vector(*node_vectors[i]);
1111 const std::size_t nGridCellNodes(cell_vector.size());
1112 for (std::size_t j = 0; j < nGridCellNodes; ++j)
1117 if (id_map[node->
getID()] == id_map[test_node->
getID()])
1125 if (test_node->
getID() != id_map[test_node->
getID()])
1142 const std::vector<std::size_t>& id_map)
const
1144 const std::vector<MeshLib::Node*>& nodes(
_mesh.getNodes());
1145 const std::size_t nNodes(nodes.size());
1146 std::vector<MeshLib::Node*> new_nodes;
1147 new_nodes.reserve(nNodes);
1148 for (std::size_t k = 0; k < nNodes; ++k)
1152 if (nodes[k]->getID() == id_map[k])
1154 std::size_t
const id(new_nodes.size());
1156 (*nodes[k])[0], (*nodes[k])[1], (*nodes[k])[2],
id));
1157 nodes[k]->setID(
id);
1164 nodes[k]->setID(nodes[id_map[k]]->getID());
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Collects error flags for mesh elements.
std::vector< std::vector< POINT * > const * > getPntVecsOfGridCellsIntersectingCube(P const ¢er, double half_len) const
std::size_t getID() const
virtual MeshElemType getGeomType() const =0
virtual ElementErrorCode validate() const =0
virtual const Element * getFace(unsigned i) const =0
Returns the i-th face of the element.
virtual unsigned getNumberOfBaseNodes() const =0
virtual const Node * getNode(unsigned idx) const =0
virtual bool isEdge(unsigned i, unsigned j) const =0
Returns true if these two indices form an edge and false otherwise.
virtual constexpr unsigned getDimension() const =0
Get dimension of the mesh element.
constexpr std::span< Node *const > nodes() const
Span of element's nodes, their pointers actually.
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
std::vector< std::string > getPropertyVectorNames() const
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 PROP_VAL_TYPE * begin()
constexpr std::size_t size() const
constexpr void push_back(const PROP_VAL_TYPE &value)
void cleanupVectorElements(std::vector< T * > &items)
bool isCoplanar(const MathLib::Point3d &a, const MathLib::Point3d &b, const MathLib::Point3d &c, const MathLib::Point3d &d)
Checks if the four given points are located on a plane.
double sqrDist(MathLib::Point3d const &p0, MathLib::Point3d const &p1)
MeshLib specific, lazy, non-owning, non-mutating, composable range views.
constexpr ranges::views::view_closure ids
For an element of a range view return its id.
TemplateElement< MeshLib::TetRule4 > Tet
TemplateElement< MeshLib::QuadRule4 > Quad
TemplateElement< MeshLib::TriRule3 > Tri
unsigned getNodeIDinElement(Element const &element, const MeshLib::Node *node)
Returns the position of the given node in the node array of this element.
Element * copyElement(Element const *const element, const std::vector< Node * > &nodes, std::vector< std::size_t > const *const id_map)
std::size_t reduceElement(MeshLib::Element const *const element, unsigned const n_unique_nodes, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &elements, unsigned const min_elem_dim)
unsigned lutHexDiametralNode(unsigned const id)
MeshLib::Element * constructTri(MeshLib::Element const *const element, const std::vector< MeshLib::Node * > &nodes)
MeshLib::Element * constructLine(MeshLib::Element const *const element, const std::vector< MeshLib::Node * > &nodes)
unsigned reduceHex(MeshLib::Element const *const org_elem, unsigned const n_unique_nodes, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &new_elements, unsigned const min_elem_dim)
unsigned reducePrism(MeshLib::Element const *const org_elem, unsigned const n_unique_nodes, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &new_elements, unsigned const min_elem_dim)
void fillNodeProperty(MeshLib::PropertyVector< T > &new_prop, MeshLib::PropertyVector< T > const &old_prop, std::vector< size_t > const &node_ids)
unsigned getNumberOfUniqueNodes(MeshLib::Element const *const element)
unsigned subdivideHex(MeshLib::Element const *const hex, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &new_elements)
Subdivides a Hex with nonplanar faces into tets.
std::unique_ptr< MeshLib::Element > createElement(std::span< MeshLib::Node *const > const element_nodes, std::vector< MeshLib::Node * > const &nodes, std::array< std::size_t, ElementType::n_all_nodes > const local_ids)
std::size_t subdivideElement(MeshLib::Element const *const element, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &elements)
void reducePyramid(MeshLib::Element const *const org_elem, unsigned const n_unique_nodes, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &new_elements, unsigned const min_elem_dim)
MeshLib::Properties copyProperties(MeshLib::Properties const &props, std::vector< std::size_t > const &node_ids, std::vector< std::size_t > const &elem_ids)
unsigned subdividePrism(MeshLib::Element const *const prism, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &new_elements)
Subdivides a prism with nonplanar quad faces into two tets.
std::array< unsigned, 4 > lutHexCuttingQuadNodes(unsigned id1, unsigned id2)
std::pair< unsigned, unsigned > lutHexBackNodes(unsigned const i, unsigned const j, unsigned const k, unsigned const l)
unsigned subdividePyramid(MeshLib::Element const *const pyramid, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &new_elements)
Subdivides a pyramid with a nonplanar base into two tets.
void fillElemProperty(MeshLib::PropertyVector< T > &new_prop, MeshLib::PropertyVector< T > const &old_prop, std::vector< size_t > const &elem_ids)
unsigned findPyramidTopNode(MeshLib::Element const &element, std::array< std::size_t, 4 > const &base_node_ids)
MeshLib::Element * constructFourNodeElement(MeshLib::Element const *const element, std::vector< MeshLib::Node * > const &nodes, unsigned const min_elem_dim=1)
unsigned subdivideQuad(MeshLib::Element const *const quad, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &new_elements)
Subdivides a nonplanar quad into two triangles.