5#include <igl/writeOBJ.h>
15 assert(keep.size() ==
n_faces());
17 std::vector<int> old_node_ids(
vertices.size(), -1);
21 std::vector<int> old_boundary_ids(
edges.size(), -1);
23 for (
int e = 0; e <
n_edges(); ++e)
26 for (
int e = 0; e < keep.size(); ++e)
32 element.is_ghost =
true;
33 for (
const int edge : element.edges)
34 edges[edge].remove_element(full_id);
35 for (
const int vertex : element.vertices)
51 for (
int e = 0; e <
n_edges(); ++e)
72 if (n_refinement <= 0)
75 std::vector<bool> refine_mask(
elements.size(),
false);
76 for (
int i = 0; i <
elements.size(); i++)
78 refine_mask[i] =
true;
80 for (
int i = 0; i < refine_mask.size(); i++)
84 refine(n_refinement - 1, t);
91 if (
F.cols() != 3 ||
F.minCoeff() < 0)
94 mesh_.clear(
false,
false);
109 for (
int i = 0; i <
V.rows(); i++)
113 for (
int i = 0; i <
F.rows(); i++)
125 for (
int f = 0; f <
n_faces(); ++f)
126 if (nodes[f].size() != 3)
127 throw std::runtime_error(
"NCMesh doesn't support high order mesh!");
134 const double t = i / (n_new_nodes + 1.0);
136 return std::make_pair((1 - t) * v1 + t * v2, -1);
144 const double b2 = i / (n_new_nodes + 2.0);
145 const double b3 = j / (n_new_nodes + 2.0);
146 const double b1 = 1 - b3 - b2;
150 return std::make_pair(b1 * v1 + b2 * v2 + b3 * v3, -1);
155 std::sort(v.data(), v.data() + v.size());
158 return search->second;
165 std::sort(v.data(), v.data() + v.size());
179 std::sort(v.data(), v.data() + v.size());
182 return search->second;
189 std::sort(v.data(), v.data() + v.size());
193 edges.emplace_back(v);
194 id =
edges.size() - 1;
203 const int level = (parent < 0) ? 0 :
elements[parent].level + 1;
204 elements.emplace_back(2, v, level, parent);
209 for (
int i = 0; i < v.size(); i++)
213 int edge01 =
get_edge(Eigen::Vector2i(v[0], v[1]));
214 int edge12 =
get_edge(Eigen::Vector2i(v[2], v[1]));
215 int edge20 =
get_edge(Eigen::Vector2i(v[0], v[2]));
217 elements[id].edges << edge01, edge12, edge20;
219 edges[edge01].add_element(
id);
220 edges[edge12].add_element(
id);
221 edges[edge20].add_element(
id);
233 if (elem.is_not_valid())
234 throw std::runtime_error(
"Cannot refine an invalid element!");
236 const auto v = elem.vertices;
237 elem.is_refined =
true;
241 for (
int e = 0; e < 3; e++)
242 edges[elem.edges(e)].remove_element(id_full);
244 for (
int i = 0; i < v.size(); i++)
247 if (elem.children(0) >= 0)
249 for (
int c = 0; c < elem.children.size(); c++)
251 auto &child =
elements[elem.children(c)];
252 child.is_ghost =
false;
254 for (
int le = 0; le < child.edges.size(); le++)
255 edges[child.edges(le)].add_element(child.children(c));
256 for (
int i = 0; i < child.vertices.size(); i++)
257 vertices[child.vertices(i)].n_elem++;
263 const int v01 =
get_vertex(Eigen::Vector2i(v[0], v[1]));
264 const int v12 =
get_vertex(Eigen::Vector2i(v[2], v[1]));
265 const int v20 =
get_vertex(Eigen::Vector2i(v[0], v[2]));
268 for (
int i = 0; i < v.size(); i++)
269 for (
int j = 0; j < i; j++)
281 add_element(Eigen::Vector3i(v[0], v01, v20), id_full);
283 add_element(Eigen::Vector3i(v[1], v12, v01), id_full);
285 add_element(Eigen::Vector3i(v[2], v20, v12), id_full);
287 add_element(Eigen::Vector3i(v12, v20, v01), id_full);
298 std::vector<int> full_ids(ids.size());
299 for (
int i = 0; i < ids.size(); i++)
302 for (
int i : full_ids)
308 const int parent_id =
elements[id_full].parent;
311 for (
int i = 0; i < parent.children.size(); i++)
312 if (
elements[parent.children(i)].is_not_valid())
313 throw std::runtime_error(
"Coarsen operation invalid!");
316 for (
int i = 0; i < parent.children.size(); i++)
318 auto &elem =
elements[parent.children(i)];
319 elem.is_ghost =
true;
321 for (
int le = 0; le < elem.edges.size(); le++)
322 edges[elem.edges(le)].remove_element(parent.children(i));
323 for (
int v = 0; v < elem.vertices.size(); v++)
324 vertices[elem.vertices(v)].n_elem--;
328 parent.is_refined =
false;
330 for (
int le = 0; le < parent.edges.size(); le++)
331 edges[parent.edges(le)].add_element(parent_id);
332 for (
int v = 0; v < parent.vertices.size(); v++)
333 vertices[parent.vertices(v)].n_elem++;
343 for (
int i = 0; i <
vec.size(); i++)
353 for (
auto &edge :
edges)
356 edge.followers.clear();
357 edge.weights.setConstant(-1);
361 std::vector<follower_edge> followers;
362 for (
int e_id = 0; e_id <
elements.size(); e_id++)
364 const auto &element =
elements[e_id];
365 if (element.is_not_valid())
367 for (
int edge_local = 0; edge_local < 3; edge_local++)
369 v << element.vertices[edge_local], element.vertices[(edge_local + 1) % 3];
370 int edge_global = element.edges[edge_local];
371 assert(edge_global >= 0);
373 for (
auto &s : followers)
375 edges[s.id].leader = edge_global;
376 edges[edge_global].followers.push_back(s.id);
377 edges[s.id].weights << s.p1, s.p2;
386 for (
auto &edge :
edges)
388 if (edge.n_elem() == 1)
389 edge.isboundary =
true;
391 edge.isboundary =
false;
394 for (
auto &edge :
edges)
396 if (edge.leader >= 0 && edge.n_elem() > 0 &&
edges[edge.leader].n_elem() > 0)
398 edge.isboundary =
false;
399 edges[edge.leader].isboundary =
false;
404 vert.isboundary =
false;
406 for (
auto &edge :
edges)
408 if (edge.isboundary && edge.n_elem())
410 for (
int j = 0; j < 2; j++)
411 vertices[edge.vertices(j)].isboundary =
true;
416 double line_weight(Eigen::Matrix<double, 2, 2> &e, Eigen::VectorXd &v)
418 assert(v.size() == 2);
419 double w1 = (v(0) - e(0, 0)) / (e(1, 0) - e(0, 0));
420 double w2 = (v(1) - e(0, 1)) / (e(1, 1) - e(0, 1));
421 if (0 <= w1 && w1 <= 1)
435 Eigen::VectorXi vertexEdgeAdjacency;
436 vertexEdgeAdjacency.setConstant(
vertices.size(), 1, -1);
438 for (
int small_edge = 0; small_edge <
edges.size(); small_edge++)
440 if (
edges[small_edge].n_elem() == 0)
443 int large_edge =
edges[small_edge].leader;
447 int large_elem =
edges[large_edge].get_element();
448 for (
int j = 0; j < 2; j++)
450 int v_id =
edges[small_edge].vertices(j);
452 vertexEdgeAdjacency[v_id] = large_edge;
458 if (element.is_not_valid())
460 for (
int v_local = 0; v_local < 3; v_local++)
462 int v_global = element.vertices[v_local];
463 if (vertexEdgeAdjacency[v_global] < 0)
466 auto &large_edge =
edges[vertexEdgeAdjacency[v_global]];
467 auto &large_element =
elements[large_edge.get_element()];
468 vertices[v_global].edge = vertexEdgeAdjacency[v_global];
470 int e_local =
find(large_element.edges,
vertices[v_global].edge);
471 Eigen::Matrix<double, 2, 2> edge;
472 edge.row(0) =
vertices[large_element.vertices[e_local]].pos;
473 edge.row(1) =
vertices[large_element.vertices[(e_local + 1) % 3]].pos;
486 assert(fabs(pos(1)) < 1e-12);
490 assert(fabs(pos(0) + pos(1) - 1) < 1e-12);
494 assert(fabs(pos(0)) < 1e-12);
507 for (
int i = 0, e = 0; i <
elements.size(); i++)
521 for (
int i = 0, j = 0; i <
vertices.size(); i++)
533 for (
int i = 0, j = 0; i <
edges.size(); i++)
535 if (
edges[i].n_elem() == 0)
546 assert(
typeid(mesh) ==
typeid(
NCMesh2D));
559 for (
int i = 0; i < mesh2d.
n_faces(); i++)
561 Eigen::Vector3i face = mesh2d.
elements[i].vertices;
562 face = face.array() + n_v;
571 return std::make_unique<NCMesh2D>(*
this);
577 std::vector<follower_edge> list1, list2;
580 double p_mid = (p1 + p2) / 2;
581 traverse_edge(Eigen::Vector2i(v[0], v_mid), p1, p_mid, depth + 1, list1);
584 std::make_move_iterator(list1.begin()),
585 std::make_move_iterator(list1.end()));
586 traverse_edge(Eigen::Vector2i(v_mid, v[1]), p_mid, p2, depth + 1, list2);
589 std::make_move_iterator(list2.begin()),
590 std::make_move_iterator(list2.end()));
595 if (follower_id >= 0 &&
edges[follower_id].n_elem() > 0)
596 list.emplace_back(follower_id, p1, p2);
607 for (
int d = 0; d < 2; d++)
609 if (v.pos[d] > max[d])
611 if (v.pos[d] < min[d])
636 idx2.
face = idx.face;
637 idx2.
edge = idx.edge;
641 for (
int i = 0; i < edge.vertices.size(); i++)
642 if (edge.vertices(i) != v1)
644 v2 = edge.vertices(i);
659 idx2.
face = idx.face;
664 for (
int i = 0; i < elem.edges.size(); i++)
666 const auto &edge =
edges[elem.edges(i)];
668 if (valid_edge_id != idx.edge &&
find(edge.vertices, full_vertex_id) >= 0)
670 idx2.
edge = valid_edge_id;
681 idx2.
edge = idx.edge;
686 if (edge.n_elem() == 2)
699 auto extent = max - min;
700 double scale = std::max(extent(0), extent(1));
703 v.pos = (v.pos - min.transpose()) / scale;
795 assert(body_ids.size() ==
n_faces());
797 for (
int i = 0; i < body_ids.size(); i++)
805 assert(boundary_ids.size() ==
n_edges());
807 for (
int i = 0; i < boundary_ids.size(); i++)
818 for (
int e = 0; e <
n_faces(); ++e)
830 for (
int e = 0; e <
n_edges(); ++e)
836 std::sort(vs.begin(), vs.end());
RowVectorNd face_barycenter(const int index) const override
face barycenter
Format-independent input used to construct a runtime Mesh.
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
std::vector< ElementType > elements_tag_
list of element types
bool has_boundary_ids() const
checks if surface selections are available
bool has_node_ids() const
checks if points selections are available
virtual void set_body_ids(const std::vector< int > &body_ids)
Set the volume sections.
std::vector< int > boundary_ids_
list of surface labels
void clear_higher_order_data()
std::vector< int > node_ids_
list of node 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 int get_default_boundary_id(const int primitive) const
Get the default boundary selection of an element (face in 3d, edge in 2d)
void filter_element_data(const std::vector< bool > &keep)
virtual void append(const Mesh &mesh)
appends a new mesh to the end of this
virtual void set_boundary_ids(const std::vector< int > &boundary_ids)
Set the boundary selection from a vector.
int find_edge(Eigen::Vector2i v) const
bool is_boundary_element(const int element_global_id) const override
is cell boundary
void traverse_edge(Eigen::Vector2i v, double p1, double p2, int depth, std::vector< follower_edge > &list) const
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
Navigation::Index switch_face(Navigation::Index idx) const override
std::vector< int > valid_to_all_edgeMap
Navigation::Index switch_vertex(Navigation::Index idx) const override
std::unique_ptr< Mesh > copy() const override
Create a copy of the mesh.
void attach_higher_order_nodes(const Eigen::MatrixXd &V, const std::vector< std::vector< int > > &nodes) override
attach high order nodes
int face_edge(const int f_id, const int le_id) const
bool build_topology(const MeshData &data) override
Construct only the dimension-specific topology.
void refine_elements(const std::vector< int > &ids)
void prepare_mesh() override
method used to finalize the mesh.
std::vector< ncVert > vertices
void build_edge_follower_chain()
std::vector< int > all_to_valid_elemMap
static double element_weight_to_edge_weight(const int l, const Eigen::Vector2d &pos)
void refine_element(int id_full)
void set_boundary_ids(const std::vector< int > &boundary_ids) override
Set the boundary selection from a vector.
int n_faces() const override
number of faces
void set_point(const int global_index, const RowVectorNd &p) override
Set the point.
int all_to_valid_vertex(const int id) const
std::vector< ncElem > elements
void set_body_ids(const std::vector< int > &body_ids) override
Set the volume sections.
Navigation::Index switch_edge(Navigation::Index idx) const override
int get_edge(Eigen::Vector2i v)
int add_element(Eigen::Vector3i v, int parent=-1)
void coarsen_element(int id_full)
int get_vertex(Eigen::Vector2i v)
Navigation::Index get_index_from_face(int f, int lv=0) const override
double edge_length(const int gid) const override
edge length
int valid_to_all_edge(const int id) const
int n_vertices() const override
number of vertices
bool is_boundary_edge(const int edge_global_id) const override
is edge boundary
void refine(const int n_refinement, const double t) override
refine the mesh
std::pair< RowVectorNd, int > face_node(const Navigation::Index &index, const int n_new_nodes, const int i, const int j) const override
void normalize() override
normalize the mesh
std::vector< int > refineHistory
int valid_to_all_elem(const int id) const
std::vector< int > valid_to_all_elemMap
int edge_vertex(const int e_id, const int lv_id) const override
id of the edge vertex
std::vector< int > all_to_valid_edgeMap
std::vector< int > all_to_valid_vertexMap
std::unordered_map< Eigen::Vector2i, int, ArrayHasher2D > midpointMap
std::vector< ncBoundary > edges
void compute_elements_tag() override
compute element types, see ElementType
RowVectorNd edge_barycenter(const int index) const override
edge barycenter
int all_to_valid_edge(const int id) const
std::unordered_map< Eigen::Vector2i, int, ArrayHasher2D > edgeMap
int find_vertex(Eigen::Vector2i v) const
void bounding_box(RowVectorNd &min, RowVectorNd &max) const override
computes the bbox of the mesh
int n_face_vertices(const int f_id) const override
number of vertices of a face
int valid_to_all_vertex(const int id) const
void build_element_vertex_adjacency()
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 n_edges() const override
number of edges
std::vector< int > valid_to_all_vertexMap
std::pair< RowVectorNd, int > edge_node(const Navigation::Index &index, const int n_new_nodes, const int i) const override
void update_elements_tag() override
Update elements types.
void build_index_mapping()
void append(const Mesh &mesh) override
appends a new mesh to the end of this
void remove_elements(const std::vector< bool > &keep) override
Remove all top-dimensional elements whose mask entry is false.
int find(const Eigen::VectorXi &vec, int x)
void orient_normals_2d(GEO::Mesh &M)
Orient facets of a 2D mesh so that each connected component has positive volume.
void to_geogram_mesh(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, GEO::Mesh &M)
Converts a triangle mesh to a Geogram mesh.
double line_weight(Eigen::Matrix< double, 2, 2 > &e, Eigen::VectorXd &v)
std::tuple< bool, int, Tree > is_valid(const int dim, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const Eigen::VectorXd &u, const double threshold, const unsigned max_iter)
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd