7#include <igl/writeMESH.h>
9#include <geogram/mesh/mesh_io.h>
28 if (n_refinement <= 0)
30 std::vector<bool> refine_mask(
elements.size(),
false);
31 for (
int i = 0; i <
elements.size(); i++)
33 refine_mask[i] =
true;
35 for (
int i = 0; i < refine_mask.size(); i++)
39 refine(n_refinement - 1, t);
45 for (
int lv = 0; lv <
n_cell_edges(element_global_id); lv++)
66 for (
int i = 0; i <
V.rows(); i++)
70 for (
int i = 0; i <
F.rows(); i++)
82 for (
int f = 0; f <
n_cells(); ++f)
83 if (nodes[f].size() != 4)
84 throw std::runtime_error(
"NCMesh doesn't support high order mesh!");
92 auto extent = max - min;
93 double scale = extent.maxCoeff();
96 v.pos = (v.pos - min.transpose()) / scale;
156 for (
int d = 0; d < 3; d++)
158 if (v.pos[d] > max[d])
160 if (v.pos[d] < min[d])
171 for (
int f = 0; f <
n_faces(); ++f)
177 for (
int vid = 0; vid < vs.size(); ++vid)
180 std::sort(vs.begin(), vs.end());
192 for (
int e = 0; e <
n_cells(); ++e)
201 assert(boundary_ids.size() ==
n_faces());
202 for (
int i = 0; i < boundary_ids.size(); i++)
209 assert(body_ids.size() ==
n_cells());
210 for (
int i = 0; i < body_ids.size(); i++)
365 for (
int i = 0; i < 4; i++)
368 for (
int j = 0; j < 3; j++)
371 if (idx.
edge == e_id)
402 int v0_ = v0, v1_ = v1;
408 for (
int i = 0; i < 4; i++)
416 for (
int j = 0; j < 3; j++)
422 if ((ev0 == v0_ && ev1 == v1_) || (ev0 == v1_ && ev1 == v0_))
440 std::vector<uint32_t> hs;
448 std::vector<uint32_t> hs;
478 for (
int i = 0; i < 4; i++)
500 if (face.n_elem() != 2)
546 assert(
elements[id_full].is_valid());
547 if (
elements[id_full].is_not_valid())
548 throw std::runtime_error(
"Cannot refine an invalid element!");
550 const auto v =
elements[id_full].vertices;
551 elements[id_full].is_refined =
true;
554 for (
int f = 0; f <
elements[id_full].faces.size(); f++)
557 for (
int e = 0; e <
elements[id_full].edges.size(); e++)
560 for (
int i = 0; i < v.size(); i++)
561 vertices[v(i)].remove_element(id_full);
563 if (
elements[id_full].children(0) >= 0)
565 for (
int c = 0; c <
elements[id_full].children.size(); c++)
567 const int child_id =
elements[id_full].children(c);
569 elem.is_ghost =
false;
572 for (
int f = 0; f < elem.faces.size(); f++)
573 faces[elem.faces(f)].add_element(child_id);
575 for (
int e = 0; e < elem.edges.size(); e++)
576 edges[elem.edges(e)].add_element(child_id);
578 for (
int v = 0; v < elem.vertices.size(); v++)
579 vertices[elem.vertices(v)].add_element(child_id);
589 const int v5 =
get_vertex(Eigen::Vector2i(v1, v2));
590 const int v8 =
get_vertex(Eigen::Vector2i(v3, v2));
591 const int v6 =
get_vertex(Eigen::Vector2i(v1, v3));
592 const int v7 =
get_vertex(Eigen::Vector2i(v1, v4));
593 const int v9 =
get_vertex(Eigen::Vector2i(v4, v2));
594 const int v10 =
get_vertex(Eigen::Vector2i(v3, v4));
597 for (
int i = 0; i < v.size(); i++)
598 for (
int j = 0; j < i; j++)
608 for (
int i = 0; i < v.size(); i++)
609 for (
int j = 0; j < i; j++)
610 for (
int k = 0; k < j; k++)
616 int facei =
get_face(v[i], vij, vik);
617 int facej =
get_face(v[j], vjk, vij);
618 int facek =
get_face(v[k], vjk, vik);
619 int facem =
get_face(vij, vjk, vik);
620 faces[facei].boundary_id =
faces[fid].boundary_id;
621 faces[facej].boundary_id =
faces[fid].boundary_id;
622 faces[facek].boundary_id =
faces[fid].boundary_id;
623 faces[facem].boundary_id =
faces[fid].boundary_id;
628 add_element(Eigen::Vector4i(v1, v5, v6, v7), id_full);
630 add_element(Eigen::Vector4i(v5, v2, v8, v9), id_full);
632 add_element(Eigen::Vector4i(v6, v8, v3, v10), id_full);
634 add_element(Eigen::Vector4i(v7, v9, v10, v4), id_full);
636 add_element(Eigen::Vector4i(v5, v6, v7, v9), id_full);
638 add_element(Eigen::Vector4i(v5, v9, v8, v6), id_full);
640 add_element(Eigen::Vector4i(v6, v7, v9, v10), id_full);
642 add_element(Eigen::Vector4i(v6, v10, v9, v8), id_full);
649 std::vector<int> full_ids(ids.size());
650 for (
int i = 0; i < ids.size(); i++)
653 for (
int i : full_ids)
659 const int parent_id =
elements[id_full].parent;
662 for (
int i = 0; i < parent.children.size(); i++)
663 if (
elements[parent.children(i)].is_not_valid())
664 throw std::runtime_error(
"Invalid siblings in coarsening!");
667 for (
int c = 0; c < parent.children.size(); c++)
669 auto &elem =
elements[parent.children(c)];
670 elem.is_ghost =
true;
673 for (
int f = 0; f < elem.faces.size(); f++)
674 faces[elem.faces(f)].remove_element(parent.children(c));
676 for (
int e = 0; e < elem.edges.size(); e++)
677 edges[elem.edges(e)].remove_element(parent.children(c));
679 for (
int v = 0; v < elem.vertices.size(); v++)
680 vertices[elem.vertices(v)].remove_element(parent.children(c));
684 parent.is_refined =
false;
687 for (
int f = 0; f < parent.faces.size(); f++)
688 faces[parent.faces(f)].add_element(parent_id);
690 for (
int e = 0; e < parent.edges.size(); e++)
691 edges[parent.edges(e)].add_element(parent_id);
693 for (
int v = 0; v < parent.vertices.size(); v++)
694 vertices[parent.vertices(v)].add_element(parent_id);
701 for (
auto &face :
faces)
703 if (face.n_elem() == 1)
704 face.isboundary =
true;
706 face.isboundary =
false;
709 for (
auto &face :
faces)
711 if (face.leader >= 0)
713 face.isboundary =
false;
714 faces[face.leader].isboundary =
false;
719 vert.isboundary =
false;
721 for (
auto &edge :
edges)
722 edge.isboundary =
false;
724 for (
auto &face :
faces)
726 if (face.isboundary && face.n_elem())
728 for (
int j = 0; j < 3; j++)
729 vertices[face.vertices(j)].isboundary =
true;
731 for (
int j = 0; j < 3; j++)
732 for (
int i = 0; i < j; i++)
733 edges[
find_edge(face.vertices(i), face.vertices(j))].isboundary =
true;
753 for (
int i = 0, e = 0; i <
elements.size(); i++)
767 for (
int i = 0, j = 0; i <
vertices.size(); i++)
779 for (
int i = 0, j = 0; i <
edges.size(); i++)
781 if (
edges[i].n_elem() == 0)
791 for (
int i = 0, j = 0; i <
faces.size(); i++)
793 if (
faces[i].n_elem() == 0)
804 assert(
typeid(mesh) ==
typeid(
NCMesh3D));
817 for (
int i = 0; i < mesh3d.
n_cells(); i++)
819 Eigen::Vector4i cell = mesh3d.
elements[i].vertices;
820 cell = cell.array() + n_v;
829 return std::make_unique<NCMesh3D>(*
this);
837 GEO::mesh_load(path, M);
844 assert(M.vertices.dimension() == 3);
846 Eigen::MatrixXd
V(M.vertices.nb(), 2);
847 Eigen::MatrixXi C(M.cells.nb(), 4);
849 for (
int v = 0; v <
V.rows(); v++)
850 V.row(v) << M.vertices.point(v)[0], M.vertices.point(v)[1], M.vertices.point(v)[2];
852 for (
int c = 0; c < C.rows(); c++)
854 if (M.cells.type(c) != GEO::MESH_TET)
855 throw std::runtime_error(
"NCMesh3D only supports tet mesh!");
856 for (
int i = 0; i < C.cols(); i++)
857 C(c, i) = M.cells.vertex(c, i);
862 for (
int i = 0; i <
V.rows(); i++)
866 for (
int i = 0; i < C.rows(); i++)
878 std::sort(v.data(), v.data() + v.size());
881 return search->second;
887 std::sort(v.data(), v.data() + v.size());
900 std::sort(v.data(), v.data() + v.size());
903 return search->second;
909 std::sort(v.data(), v.data() + v.size());
913 edges.emplace_back(v);
914 id =
edges.size() - 1;
921 std::sort(v.data(), v.data() + v.size());
924 return search->second;
930 std::sort(v.data(), v.data() + v.size());
934 faces.emplace_back(v);
935 id =
faces.size() - 1;
943 std::vector<follower_edge> list1, list2;
946 double p_mid = (p1 + p2) / 2;
947 traverse_edge(Eigen::Vector2i(v[0], v_mid), p1, p_mid, depth + 1, list1);
950 std::make_move_iterator(list1.begin()),
951 std::make_move_iterator(list1.end()));
952 traverse_edge(Eigen::Vector2i(v_mid, v[1]), p_mid, p2, depth + 1, list2);
955 std::make_move_iterator(list2.begin()),
956 std::make_move_iterator(list2.end()));
961 if (follower_id >= 0 &&
edges[follower_id].n_elem() > 0)
962 list.emplace_back(follower_id, p1, p2);
967 for (
auto &edge :
edges)
970 edge.followers.clear();
971 edge.weights.setConstant(-1);
974 for (
int e_id = 0; e_id <
edges.size(); e_id++)
976 auto &edge =
edges[e_id];
977 if (edge.n_elem() == 0)
979 std::vector<follower_edge> followers;
981 for (
auto &s : followers)
983 if (
edges[s.id].leader >= 0 && std::abs(
edges[s.id].weights(1) -
edges[s.id].weights(0)) < std::abs(s.p2 - s.p1))
985 edge.followers.push_back(s.id);
986 edges[s.id].leader = e_id;
987 edges[s.id].weights << s.p1, s.p2;
992 for (
auto &edge :
edges)
993 if (edge.leader >= 0 && edge.followers.size())
994 edge.followers.clear();
996 void NCMesh3D::traverse_face(
int v1,
int v2,
int v3, Eigen::Vector2d p1, Eigen::Vector2d p2, Eigen::Vector2d p3,
int depth, std::vector<follower_face> &face_list, std::vector<int> &edge_list)
const
1001 std::vector<follower_face> list1, list2, list3, list4;
1002 std::vector<int> list1_, list2_, list3_, list4_;
1009 if (v12 >= 0 && v23 >= 0 && v31 >= 0)
1011 auto p12 = (p1 + p2) / 2, p23 = (p2 + p3) / 2, p31 = (p1 + p3) / 2;
1012 traverse_face(v1, v12, v31, p1, p12, p31, depth + 1, list1, list1_);
1013 traverse_face(v12, v2, v23, p12, p2, p23, depth + 1, list2, list2_);
1014 traverse_face(v31, v23, v3, p31, p23, p3, depth + 1, list3, list3_);
1015 traverse_face(v12, v23, v31, p12, p23, p31, depth + 1, list4, list4_);
1017 face_list.insert(face_list.end(), std::make_move_iterator(list1.begin()), std::make_move_iterator(list1.end()));
1018 face_list.insert(face_list.end(), std::make_move_iterator(list2.begin()), std::make_move_iterator(list2.end()));
1019 face_list.insert(face_list.end(), std::make_move_iterator(list3.begin()), std::make_move_iterator(list3.end()));
1020 face_list.insert(face_list.end(), std::make_move_iterator(list4.begin()), std::make_move_iterator(list4.end()));
1022 edge_list.insert(edge_list.end(), std::make_move_iterator(list1_.begin()), std::make_move_iterator(list1_.end()));
1023 edge_list.insert(edge_list.end(), std::make_move_iterator(list2_.begin()), std::make_move_iterator(list2_.end()));
1024 edge_list.insert(edge_list.end(), std::make_move_iterator(list3_.begin()), std::make_move_iterator(list3_.end()));
1025 edge_list.insert(edge_list.end(), std::make_move_iterator(list4_.begin()), std::make_move_iterator(list4_.end()));
1029 int follower_id =
find_face(Eigen::Vector3i(v1, v2, v3));
1030 if (follower_id >= 0 &&
faces[follower_id].n_elem() > 0)
1031 face_list.emplace_back(follower_id, p1, p2, p3);
1036 Eigen::Matrix<int, 4, 3> fv;
1037 fv.row(0) << 0, 1, 2;
1038 fv.row(1) << 0, 1, 3;
1039 fv.row(2) << 1, 2, 3;
1040 fv.row(3) << 2, 0, 3;
1042 for (
auto &face :
faces)
1045 face.followers.clear();
1048 for (
auto &edge :
edges)
1050 edge.leader_face = -1;
1053 for (
int f_id = 0; f_id <
faces.size(); f_id++)
1055 auto &face =
faces[f_id];
1056 if (face.n_elem() == 0)
1058 std::vector<follower_face> followers;
1059 std::vector<int> interior_edges;
1060 traverse_face(face.vertices(0), face.vertices(1), face.vertices(2), Eigen::Vector2d(0, 0), Eigen::Vector2d(1, 0), Eigen::Vector2d(0, 1), 0, followers, interior_edges);
1061 for (
auto &s : followers)
1063 faces[s.id].leader = f_id;
1064 face.followers.push_back(s.id);
1066 for (
int s : interior_edges)
1067 if (s >= 0 &&
edges[s].leader < 0 &&
edges[s].n_elem() > 0)
1068 edges[s].leader_face = f_id;
1079 for (
auto &small_edge :
edges)
1082 if (small_edge.n_elem() == 0)
1086 int large_edge = small_edge.leader;
1089 assert(
edges[large_edge].leader < 0);
1092 for (
int j = 0; j < 2; j++)
1094 const int v_id = small_edge.vertices(j);
1101 for (
auto &small_face :
faces)
1104 if (small_face.n_elem() == 0)
1108 int large_face = small_face.leader;
1113 for (
int j = 0; j < 3; j++)
1115 const int v_id = small_face.vertices(j);
1117 if (v_id !=
faces[large_face].
vertices(0) && v_id !=
faces[large_face].vertices(1) && v_id !=
faces[large_face].vertices(2))
1129 const int level = (parent < 0) ? 0 :
elements[parent].level + 1;
1134 if ((e1.cross(e2)).dot(e3) < 0)
1135 std::swap(v[2], v[3]);
1139 assert((e1.cross(e2)).dot(e3) > 0);
1141 elements.emplace_back(3, v, level, parent);
1147 const int face012 =
get_face(v[0], v[1], v[2]);
1148 const int face013 =
get_face(v[0], v[1], v[3]);
1149 const int face123 =
get_face(v[1], v[2], v[3]);
1150 const int face203 =
get_face(v[2], v[0], v[3]);
1152 faces[face012].add_element(
id);
1153 faces[face013].add_element(
id);
1154 faces[face123].add_element(
id);
1155 faces[face203].add_element(
id);
1157 elements[id].faces << face012, face013, face123, face203;
1160 const int edge01 =
get_edge(v[0], v[1]);
1161 const int edge12 =
get_edge(v[1], v[2]);
1162 const int edge20 =
get_edge(v[2], v[0]);
1163 const int edge03 =
get_edge(v[0], v[3]);
1164 const int edge13 =
get_edge(v[1], v[3]);
1165 const int edge23 =
get_edge(v[2], v[3]);
1167 edges[edge01].add_element(
id);
1168 edges[edge12].add_element(
id);
1169 edges[edge20].add_element(
id);
1170 edges[edge03].add_element(
id);
1171 edges[edge13].add_element(
id);
1172 edges[edge23].add_element(
id);
1174 elements[id].edges << edge01, edge12, edge20, edge03, edge13, edge23;
1178 for (
int i = 0; i < v.size(); i++)
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
std::vector< ElementType > elements_tag_
list of element types
std::vector< int > boundary_ids_
list of surface labels
std::vector< int > element_vertices(const int el_id) const
list of vids of an element
std::vector< int > body_ids_
list of volume labels
virtual void append(const Mesh &mesh)
appends a new mesh to the end of this
int find_vertex(Eigen::Vector2i v) const
bool is_boundary_element(const int element_global_id) const override
is cell boundary
void compute_body_ids(const std::function< int(const size_t, const std::vector< int > &, const RowVectorNd &)> &marker) override
computes boundary selections based on a function
std::vector< int > all_to_valid_elemMap
int n_faces() const override
number of faces
int valid_to_all_edge(const int id) const
Navigation3D::Index next_around_edge(Navigation3D::Index idx) const override
int face_edge(const int f_id, const int le_id) const
int n_cell_faces(const int c_id) const override
void traverse_edge(Eigen::Vector2i v, double p1, double p2, int depth, std::vector< follower_edge > &list) const
std::unordered_map< Eigen::Vector2i, int, ArrayHasher2D > midpointMap
int n_cells() const override
number of cells
void build_element_vertex_adjacency()
void prepare_mesh() override
method used to finalize the mesh.
std::vector< ncBoundary > edges
int valid_to_all_face(const int id) const
void bounding_box(RowVectorNd &min, RowVectorNd &max) const override
computes the bbox of the mesh
void append(const Mesh &mesh) override
appends a new mesh to the end of this
std::vector< int > refineHistory
double edge_length(const int gid) const override
edge length
int n_edges() const override
number of edges
void compute_boundary_ids(const std::function< int(const size_t, const std::vector< int > &, const RowVectorNd &, bool)> &marker) override
computes boundary selections based on a function
int get_edge(Eigen::Vector2i v)
void set_point(const int global_index, const RowVectorNd &p) override
Set the point.
int add_element(Eigen::Vector4i v, int parent=-1)
int get_face(Eigen::Vector3i v)
void attach_higher_order_nodes(const Eigen::MatrixXd &V, const std::vector< std::vector< int > > &nodes) override
attach high order nodes
int n_face_vertices(const int f_id) const override
number of vertices of a face
RowVectorNd cell_barycenter(const int c) const override
cell barycenter
std::vector< uint32_t > edge_neighs(const int e_gid) const override
int all_to_valid_elem(const int id) const
int n_vertices() const override
number of vertices
std::vector< ncVert > vertices
Navigation3D::Index get_index_from_element_edge(int hi, int v0, int v1) const override
std::unordered_map< Eigen::Vector2i, int, ArrayHasher2D > edgeMap
void traverse_face(int v1, int v2, int v3, Eigen::Vector2d p1, Eigen::Vector2d p2, Eigen::Vector2d p3, int depth, std::vector< follower_face > &face_list, std::vector< int > &edge_list) const
void refine(const int n_refinement, const double t) override
refine the mesh
void normalize() override
normalize the mesh
std::vector< int > all_to_valid_vertexMap
int all_to_valid_edge(const int id) const
void get_face_elements_neighs(const int f_id, std::vector< int > &ids) const
std::unique_ptr< Mesh > copy() const override
Create a copy of the mesh.
int valid_to_all_elem(const int id) const
void refine_element(int id_full)
Navigation3D::Index switch_vertex(Navigation3D::Index idx) const override
RowVectorNd kernel(const int cell_id) const override
bool is_boundary_vertex(const int vertex_global_id) const override
is vertex boundary
int cell_face(const int c_id, const int lf_id) const override
bool build_from_matrices(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F) override
build a mesh from matrices
void compute_elements_tag() override
compute element types, see ElementType
RowVectorNd point(const int global_index) const override
point coordinates
std::vector< int > all_to_valid_edgeMap
int find_edge(Eigen::Vector2i v) const
Navigation3D::Index get_index_from_element(int hi, int lf, int lv) const override
bool is_boundary_face(const int face_global_id) const override
is face boundary
int cell_vertex(const int f_id, const int lv_id) const override
id of the vertex of a cell
std::vector< int > all_to_valid_faceMap
void coarsen_element(int id_full)
Navigation3D::Index next_around_face(Navigation3D::Index idx) const override
std::vector< int > valid_to_all_elemMap
std::vector< int > valid_to_all_edgeMap
void build_face_follower_chain()
RowVectorNd face_barycenter(const int f) const override
face barycenter
void build_edge_follower_chain()
int n_cell_edges(const int c_id) const override
Navigation3D::Index switch_element(Navigation3D::Index idx) const override
void get_vertex_elements_neighs(const int v_id, std::vector< int > &ids) const override
std::vector< ncElem > elements
std::unordered_map< Eigen::Vector3i, int, ArrayHasher3D > faceMap
RowVectorNd edge_barycenter(const int e) const override
edge barycenter
std::vector< int > valid_to_all_faceMap
std::vector< uint32_t > vertex_neighs(const int v_gid) const override
std::vector< int > valid_to_all_vertexMap
std::array< int, 4 > get_ordered_vertices_from_tet(const int element_index) const override
void update_elements_tag() override
Update elements types.
int valid_to_all_vertex(const int id) const
int edge_vertex(const int e_id, const int lv_id) const override
id of the edge vertex
void refine_elements(const std::vector< int > &ids)
void build_index_mapping()
int get_vertex(Eigen::Vector2i v)
int find_face(Eigen::Vector3i v) const
void get_edge_elements_neighs(const int e_id, std::vector< int > &ids) const override
Navigation3D::Index switch_face(Navigation3D::Index idx) const override
int face_vertex(const int f_id, const int lv_id) const override
id of the face vertex
int all_to_valid_face(const int id) const
bool load(const std::string &path) override
loads a mesh from the path
Navigation3D::Index get_index_from_element_face(int hi, int v0, int v1, int v2) const override
void set_body_ids(const std::vector< int > &body_ids) override
Set the volume sections.
void set_boundary_ids(const std::vector< int > &boundary_ids) override
Set the boundary selection from a vector.
std::vector< ncBoundary > faces
Navigation3D::Index switch_edge(Navigation3D::Index idx) const override
bool endswith(const std::string &str, const std::string &suffix)
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd