6#include <wmtk/utils/TupleUtils.hpp>
7#include <wmtk/utils/TetraQualityUtils.hpp>
9#include <igl/predicates/predicates.h>
18 const size_t num_vertices,
const Eigen::MatrixXi &tetrahedra)
21 p_vertex_attrs = &vertex_attrs;
22 p_edge_attrs = &edge_attrs;
23 p_face_attrs = &boundary_attrs;
24 p_tet_attrs = &element_attrs;
27 std::vector<std::array<size_t, 4>> tets(tetrahedra.rows());
28 for (
int i = 0; i < tetrahedra.rows(); i++)
29 for (
int j = 0; j < tetrahedra.cols(); j++)
30 tets[i][j] = (
size_t)tetrahedra(i, j);
33 wmtk::TetMesh::init(num_vertices, tets);
39 const std::vector<Tuple>
faces = get_faces();
40 FaceMap<int> boundary_ids;
43 const size_t f0 = face.vid(*
this);
44 const size_t f1 = face.switch_vertex(*this).vid(*
this);
45 const size_t f2 = opposite_vertex_on_face(face).vid(*
this);
47 boundary_ids[{{f0, f1, f2}}] = boundary_attrs[face.fid(*
this)].boundary_id;
53 Eigen::MatrixXi WildTetRemesher::boundary_edges()
const
55 const std::vector<Tuple> boundary_face_tuples = boundary_facets();
56 std::vector<Tuple> boundary_edge_tuples;
57 for (
const Tuple &f : boundary_face_tuples)
59 boundary_edge_tuples.push_back(f);
60 boundary_edge_tuples.push_back(
f.switch_edge(*
this));
61 boundary_edge_tuples.push_back(
f.switch_vertex(*this).switch_edge(*
this));
63 wmtk::unique_edge_tuples(*
this, boundary_edge_tuples);
65 Eigen::MatrixXi BE(boundary_edge_tuples.size(), 2);
66 for (
int i = 0; i < BE.rows(); ++i)
68 BE(i, 0) = boundary_edge_tuples[i].vid(*
this);
69 BE(i, 1) = boundary_edge_tuples[i].switch_vertex(*this).vid(*
this);
71 if (obstacle().n_edges() > 0)
72 utils::append_rows(BE, obstacle().
e().array() + vert_capacity());
77 Eigen::MatrixXi WildTetRemesher::boundary_faces()
const
79 const std::vector<Tuple> boundary_face_tuples = boundary_facets();
80 Eigen::MatrixXi BF(boundary_face_tuples.size(), 3);
81 for (
int i = 0; i < BF.rows(); ++i)
83 const std::array<Tuple, 3> vs = get_face_vertices(boundary_face_tuples[i]);
84 for (
int j = 0; j < 3; ++j)
85 BF(i, j) = vs[j].vid(*
this);
87 if (obstacle().n_faces() > 0)
88 utils::append_rows(BF, obstacle().
f().array() + vert_capacity());
93 std::vector<Tuple> WildTetRemesher::get_facets()
const
99 std::vector<Tuple> WildTetRemesher::get_elements()
const
105 bool WildTetRemesher::is_rest_inverted(
const Tuple &loc)
const
108 const std::array<size_t, 4> vids = oriented_tet_vids(loc);
110 igl::predicates::exactinit();
113 const igl::predicates::Orientation orientation = igl::predicates::orient3d(
114 vertex_attrs[vids[0]].rest_position, vertex_attrs[vids[1]].rest_position,
115 vertex_attrs[vids[2]].rest_position, vertex_attrs[vids[3]].rest_position);
118 return orientation != igl::predicates::Orientation::NEGATIVE;
122 bool WildTetRemesher::is_inverted(
const Tuple &loc)
const
125 const std::array<size_t, 4> vids = oriented_tet_vids(loc);
127 igl::predicates::exactinit();
129 for (
int i = 0; i < n_quantities() / 3 + 2; ++i)
132 const igl::predicates::Orientation orientation = igl::predicates::orient3d(
133 vertex_attrs[vids[0]].position_i(i), vertex_attrs[vids[1]].position_i(i),
134 vertex_attrs[vids[2]].position_i(i), vertex_attrs[vids[3]].position_i(i));
137 if (orientation != igl::predicates::Orientation::NEGATIVE)
145 double WildTetRemesher::element_volume(
const Tuple &e)
const
147 const std::array<size_t, 4> vids = oriented_tet_vids(e);
148 return utils::tetrahedron_volume(
149 vertex_attrs[vids[0]].rest_position,
150 vertex_attrs[vids[1]].rest_position,
151 vertex_attrs[vids[2]].rest_position,
152 vertex_attrs[vids[3]].rest_position);
156 size_t WildTetRemesher::facet_id(
const Tuple &t)
const
162 size_t WildTetRemesher::element_id(
const Tuple &t)
const
168 Tuple WildTetRemesher::tuple_from_facet(
size_t elem_id,
int local_facet_id)
const
170 return tuple_from_face(elem_id, local_facet_id);
174 Tuple WildTetRemesher::tuple_from_element(
size_t elem_id)
const
176 return tuple_from_tet(elem_id);
180 bool WildTetRemesher::is_boundary_facet(
const Tuple &t)
const
182 return t.is_boundary_face(*
this);
186 bool WildTetRemesher::is_boundary_vertex(
const Tuple &v)
const
188 for (
const Tuple &t : get_one_ring_tets_for_vertex(v))
190 for (
int fi = 0; fi < FACETS_PER_ELEMENT; ++fi)
192 if (is_boundary_facet(tuple_from_facet(t.tid(*
this), fi)))
200 bool WildTetRemesher::is_body_boundary_vertex(
const Tuple &v)
const
206 bool WildTetRemesher::is_boundary_edge(
const Tuple &e)
const
208 return e.is_boundary_edge(*
this);
212 bool WildTetRemesher::is_body_boundary_edge(
const Tuple &e)
const
214 const size_t tid =
e.tid(*
this);
215 const int body_id = element_attrs[tid].body_id;
217 std::optional<Tuple> t =
e.switch_tetrahedron(*
this);
218 while (t && element_attrs[t->tid(*
this)].body_id == body_id && t->tid(*
this) != tid)
219 t = t->switch_face(*this).switch_tetrahedron(*
this);
221 return !t.has_value() || element_attrs[t->tid(*
this)].body_id != body_id;
225 bool WildTetRemesher::is_boundary_op()
const
227 return op_cache->is_boundary_op();
231 std::array<Tuple, 3> WildTetRemesher::facet_vertices(
const Tuple &t)
const
233 return get_face_vertices(t);
237 std::array<size_t, 3> WildTetRemesher::facet_vids(
const Tuple &t)
const
241 t.switch_vertex(*this).vid(*
this),
242 opposite_vertex_on_face(t).vid(*
this),
247 std::array<Tuple, 4> WildTetRemesher::element_vertices(
const Tuple &t)
const
249 return oriented_tet_vertices(t);
253 std::array<size_t, 4> WildTetRemesher::element_vids(
const Tuple &t)
const
255 return oriented_tet_vids(t);
259 std::array<size_t, 4> WildTetRemesher::orient_preserve_element_reorder(
260 const std::array<size_t, 4> &conn,
const size_t v0)
const
262 return wmtk::orient_preserve_tet_reorder(conn, v0);
266 std::vector<Tuple> WildTetRemesher::get_one_ring_elements_for_vertex(
const Tuple &t)
const
268 return get_one_ring_tets_for_vertex(t);
272 std::vector<Tuple> WildTetRemesher::get_incident_elements_for_edge(
const Tuple &t)
const
274 return get_incident_tets_for_edge(t);
278 std::vector<Tuple> WildTetRemesher::get_one_ring_boundary_faces_for_vertex(
const Tuple &v)
const
280 const size_t vid = v.vid(*
this);
282 std::vector<Tuple>
faces;
283 for (
const Tuple &t : get_one_ring_tets_for_vertex(v))
285 const size_t tid = t.tid(*
this);
286 for (
int fi = 0; fi < 4; ++fi)
288 const Tuple f = tuple_from_face(tid, fi);
290 if (!
f.is_boundary_face(*
this))
294 for (
const Tuple &fv : get_face_vertices(
f))
296 if (fv.vid(*
this) == vid)
304 unique_face_tuples(*
this,
faces);
309 std::vector<Tuple> WildTetRemesher::get_one_ring_boundary_edges_for_vertex(
const Tuple &v)
const
311 const size_t vid = v.vid(*
this);
313 std::vector<Tuple> edges;
314 for (
const Tuple &f : get_one_ring_boundary_faces_for_vertex(v))
316 const size_t fid =
f.fid(*
this);
318 const std::array<Tuple, 3> face_edges{{
320 f.switch_vertex(*this).switch_edge(*
this),
321 f.switch_edge(*
this),
324 for (
const Tuple &e : face_edges)
327 if (
e.vid(*
this) == vid ||
e.switch_vertex(*this).vid(*
this) == vid)
333 unique_edge_tuples(*
this, edges);
338 std::array<Tuple, 2> WildTetRemesher::get_boundary_faces_for_edge(
const Tuple &e)
const
340 assert(
e.is_boundary_edge(*
this));
342 const size_t tid =
e.tid(*
this);
345 std::array<Tuple, 2>
faces{{
e,
e.switch_face(*
this)}};
346 for (Tuple &f :
faces)
350 std::optional st =
f.switch_tetrahedron(*
this);
353 f = st->switch_face(*
this);
354 }
while (
f.tid(*
this) != tid);
355 assert(
f.is_boundary_face(*
this));
357 assert(
faces[0].fid(*
this) !=
faces[1].fid(*
this));
362 CollapseEdgeTo WildTetRemesher::collapse_boundary_edge_to(
const Tuple &e)
const
365 assert(
e.is_boundary_edge(*
this));
367 const std::array<Tuple, 2> boundary_faces = get_boundary_faces_for_edge(e);
369 const Eigen::Vector3d &v0 = vertex_attrs[
e.vid(*
this)].rest_position;
370 const Eigen::Vector3d &v1 = vertex_attrs[
e.switch_vertex(*this).vid(*
this)].rest_position;
371 const Eigen::Vector3d &v2 = vertex_attrs[opposite_vertex_on_face(boundary_faces[0]).vid(*
this)].rest_position;
372 const Eigen::Vector3d &v3 = vertex_attrs[opposite_vertex_on_face(boundary_faces[1]).vid(*
this)].rest_position;
373 assert((v2.array() != v3.array()).any());
375 const int boundary_id0 = boundary_attrs[boundary_faces[0].fid(*
this)].boundary_id;
376 const int boundary_id1 = boundary_attrs[boundary_faces[1].fid(*
this)].boundary_id;
378 const std::vector<Tuple> v0_boundary_faces = get_one_ring_boundary_faces_for_vertex(e);
379 const std::vector<Tuple> v1_boundary_faces = get_one_ring_boundary_faces_for_vertex(
e.switch_vertex(*
this));
381 bool is_v0_movable, is_v1_movable;
382 if (boundary_id0 != boundary_id1 || !utils::are_triangles_coplanar(v0, v1, v2, v0, v1, v3))
384 const auto &is_collinear = [&](
const Tuple &e1) {
385 assert(
e.is_boundary_edge(*
this));
386 return e.eid(*
this) != e1.eid(*
this)
387 && utils::are_edges_collinear(
388 v0, v1, vertex_attrs[e1.vid(*
this)].rest_position,
389 vertex_attrs[e1.switch_vertex(*this).vid(*
this)].rest_position);
392 const auto &is_coplanar = [&](
const Tuple &
f) {
393 assert(
f.is_boundary_face(*
this));
394 const std::array<Tuple, 3> vs = get_face_vertices(f);
395 const Eigen::Vector3d &v4 = vertex_attrs[vs[0].vid(*
this)].rest_position;
396 const Eigen::Vector3d &v5 = vertex_attrs[vs[1].vid(*
this)].rest_position;
397 const Eigen::Vector3d &v6 = vertex_attrs[vs[2].vid(*
this)].rest_position;
398 return (boundary_attrs[
f.fid(*
this)].boundary_id == boundary_id0
399 && utils::are_triangles_coplanar(v0, v1, v2, v4, v5, v6))
400 || (boundary_attrs[
f.fid(*
this)].boundary_id == boundary_id1
401 && utils::are_triangles_coplanar(v0, v1, v3, v4, v5, v6));
404 const std::vector<Tuple> v0_boundary_edges = get_one_ring_boundary_edges_for_vertex(e);
405 is_v0_movable = std::any_of(v0_boundary_edges.begin(), v0_boundary_edges.end(), is_collinear)
406 && std::all_of(v0_boundary_faces.begin(), v0_boundary_faces.end(), is_coplanar);
408 const std::vector<Tuple> v1_boundary_edges = get_one_ring_boundary_edges_for_vertex(
e.switch_vertex(*
this));
409 is_v1_movable = std::any_of(v1_boundary_edges.begin(), v1_boundary_edges.end(), is_collinear)
410 && std::all_of(v1_boundary_faces.begin(), v1_boundary_faces.end(), is_coplanar);
414 const auto &is_coplanar = [&](
const Tuple &
f) {
415 const std::array<Tuple, 3> vs = get_face_vertices(f);
416 const Eigen::Vector3d &v4 = vertex_attrs[vs[0].vid(*
this)].rest_position;
417 const Eigen::Vector3d &v5 = vertex_attrs[vs[1].vid(*
this)].rest_position;
418 const Eigen::Vector3d &v6 = vertex_attrs[vs[2].vid(*
this)].rest_position;
419 return boundary_attrs[
f.fid(*
this)].boundary_id == boundary_id0
420 && utils::are_triangles_coplanar(v0, v1, v2, v4, v5, v6);
423 is_v0_movable = std::all_of(v0_boundary_faces.begin(), v0_boundary_faces.end(), is_coplanar);
424 is_v1_movable = std::all_of(v1_boundary_faces.begin(), v1_boundary_faces.end(), is_coplanar);
427 if (!is_v0_movable && !is_v1_movable)
428 return CollapseEdgeTo::ILLEGAL;
429 else if (!is_v0_movable)
430 return CollapseEdgeTo::V0;
431 else if (!is_v1_movable)
432 return CollapseEdgeTo::V1;
434 return CollapseEdgeTo::MIDPOINT;
438 WildTetRemesher::EdgeAttributes &WildTetRemesher::edge_attr(
const size_t e_id)
440 return edge_attrs[e_id];
444 const WildTetRemesher::EdgeAttributes &WildTetRemesher::edge_attr(
const size_t e_id)
const
446 return edge_attrs[e_id];
std::vector< Eigen::VectorXi > faces
std::variant< EdgeMap< T >, FaceMap< T > > BoundaryMap
void init_attributes_and_connectivity(const size_t num_vertices, const Eigen::MatrixXi &elements) override
Create an internal mesh representation and associate attributes.
typename WMTKMesh::Tuple Tuple
WildTetRemesher::Tuple Tuple
void log_and_throw_error(const std::string &msg)