PolyFEM
Loading...
Searching...
No Matches
WildTetRemesher.cpp
Go to the documentation of this file.
1#include "WildRemesher.hpp"
2
5
6#include <wmtk/utils/TupleUtils.hpp>
7#include <wmtk/utils/TetraQualityUtils.hpp>
8
9#include <igl/predicates/predicates.h>
10#include <igl/edges.h>
11
12namespace polyfem::mesh
13{
15
16 template <>
18 const size_t num_vertices, const Eigen::MatrixXi &tetrahedra)
19 {
20 // Register attributes
21 p_vertex_attrs = &vertex_attrs;
22 p_edge_attrs = &edge_attrs;
23 p_face_attrs = &boundary_attrs;
24 p_tet_attrs = &element_attrs;
25
26 // Convert from eigen to internal representation
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);
31
32 // Initialize the trimesh class which handles connectivity
33 wmtk::TetMesh::init(num_vertices, tets);
34 }
35
36 template <>
37 WildTetRemesher::BoundaryMap<int> WildTetRemesher::boundary_ids() const
38 {
39 const std::vector<Tuple> faces = get_faces();
40 FaceMap<int> boundary_ids;
41 for (const Tuple &face : faces)
42 {
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);
46
47 boundary_ids[{{f0, f1, f2}}] = boundary_attrs[face.fid(*this)].boundary_id;
48 }
49 return boundary_ids;
50 }
51
52 template <>
53 Eigen::MatrixXi WildTetRemesher::boundary_edges() const
54 {
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)
58 {
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));
62 }
63 wmtk::unique_edge_tuples(*this, boundary_edge_tuples);
64
65 Eigen::MatrixXi BE(boundary_edge_tuples.size(), 2);
66 for (int i = 0; i < BE.rows(); ++i)
67 {
68 BE(i, 0) = boundary_edge_tuples[i].vid(*this);
69 BE(i, 1) = boundary_edge_tuples[i].switch_vertex(*this).vid(*this);
70 }
71 if (obstacle().n_edges() > 0)
72 utils::append_rows(BE, obstacle().e().array() + vert_capacity());
73 return BE;
74 }
75
76 template <>
77 Eigen::MatrixXi WildTetRemesher::boundary_faces() const
78 {
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)
82 {
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);
86 }
87 if (obstacle().n_faces() > 0)
88 utils::append_rows(BF, obstacle().f().array() + vert_capacity());
89 return BF;
90 }
91
92 template <>
93 std::vector<Tuple> WildTetRemesher::get_facets() const
94 {
95 return get_faces();
96 }
97
98 template <>
99 std::vector<Tuple> WildTetRemesher::get_elements() const
100 {
101 return get_tets();
102 }
103
104 template <>
105 bool WildTetRemesher::is_rest_inverted(const Tuple &loc) const
106 {
107 // Get the vertices ids
108 const std::array<size_t, 4> vids = oriented_tet_vids(loc);
109
110 igl::predicates::exactinit();
111
112 // Use igl for checking orientation
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);
116
117 // neg result == pos tet (tet origin from geogram delaunay)
118 return orientation != igl::predicates::Orientation::NEGATIVE;
119 }
120
121 template <>
122 bool WildTetRemesher::is_inverted(const Tuple &loc) const
123 {
124 // Get the vertices ids
125 const std::array<size_t, 4> vids = oriented_tet_vids(loc);
126
127 igl::predicates::exactinit();
128
129 for (int i = 0; i < n_quantities() / 3 + 2; ++i)
130 {
131 // Use igl for checking orientation
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));
135
136 // neg result == pos tet (tet origin from geogram delaunay)
137 if (orientation != igl::predicates::Orientation::NEGATIVE)
138 return true;
139 }
140
141 return false;
142 }
143
144 template <>
145 double WildTetRemesher::element_volume(const Tuple &e) const
146 {
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);
153 }
154
155 template <>
156 size_t WildTetRemesher::facet_id(const Tuple &t) const
157 {
158 return t.fid(*this);
159 }
160
161 template <>
162 size_t WildTetRemesher::element_id(const Tuple &t) const
163 {
164 return t.tid(*this);
165 }
166
167 template <>
168 Tuple WildTetRemesher::tuple_from_facet(size_t elem_id, int local_facet_id) const
169 {
170 return tuple_from_face(elem_id, local_facet_id);
171 }
172
173 template <>
174 Tuple WildTetRemesher::tuple_from_element(size_t elem_id) const
175 {
176 return tuple_from_tet(elem_id);
177 }
178
179 template <>
180 bool WildTetRemesher::is_boundary_facet(const Tuple &t) const
181 {
182 return t.is_boundary_face(*this);
183 }
184
185 template <>
186 bool WildTetRemesher::is_boundary_vertex(const Tuple &v) const
187 {
188 for (const Tuple &t : get_one_ring_tets_for_vertex(v))
189 {
190 for (int fi = 0; fi < FACETS_PER_ELEMENT; ++fi)
191 {
192 if (is_boundary_facet(tuple_from_facet(t.tid(*this), fi)))
193 return true;
194 }
195 }
196 return false;
197 }
198
199 template <>
200 bool WildTetRemesher::is_body_boundary_vertex(const Tuple &v) const
201 {
202 log_and_throw_error("WildTetRemesher::is_body_boundary_vertex() not implemented!");
203 }
204
205 template <>
206 bool WildTetRemesher::is_boundary_edge(const Tuple &e) const
207 {
208 return e.is_boundary_edge(*this);
209 }
210
211 template <>
212 bool WildTetRemesher::is_body_boundary_edge(const Tuple &e) const
213 {
214 const size_t tid = e.tid(*this);
215 const int body_id = element_attrs[tid].body_id;
216
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);
220
221 return !t.has_value() || element_attrs[t->tid(*this)].body_id != body_id;
222 }
223
224 template <>
225 bool WildTetRemesher::is_boundary_op() const
226 {
227 return op_cache->is_boundary_op();
228 }
229
230 template <>
231 std::array<Tuple, 3> WildTetRemesher::facet_vertices(const Tuple &t) const
232 {
233 return get_face_vertices(t);
234 }
235
236 template <>
237 std::array<size_t, 3> WildTetRemesher::facet_vids(const Tuple &t) const
238 {
239 return {{
240 t.vid(*this),
241 t.switch_vertex(*this).vid(*this),
242 opposite_vertex_on_face(t).vid(*this),
243 }};
244 }
245
246 template <>
247 std::array<Tuple, 4> WildTetRemesher::element_vertices(const Tuple &t) const
248 {
249 return oriented_tet_vertices(t);
250 }
251
252 template <>
253 std::array<size_t, 4> WildTetRemesher::element_vids(const Tuple &t) const
254 {
255 return oriented_tet_vids(t);
256 }
257
258 template <>
259 std::array<size_t, 4> WildTetRemesher::orient_preserve_element_reorder(
260 const std::array<size_t, 4> &conn, const size_t v0) const
261 {
262 return wmtk::orient_preserve_tet_reorder(conn, v0);
263 }
264
265 template <>
266 std::vector<Tuple> WildTetRemesher::get_one_ring_elements_for_vertex(const Tuple &t) const
267 {
268 return get_one_ring_tets_for_vertex(t);
269 }
270
271 template <>
272 std::vector<Tuple> WildTetRemesher::get_incident_elements_for_edge(const Tuple &t) const
273 {
274 return get_incident_tets_for_edge(t);
275 }
276
277 template <>
278 std::vector<Tuple> WildTetRemesher::get_one_ring_boundary_faces_for_vertex(const Tuple &v) const
279 {
280 const size_t vid = v.vid(*this);
281
282 std::vector<Tuple> faces;
283 for (const Tuple &t : get_one_ring_tets_for_vertex(v))
284 {
285 const size_t tid = t.tid(*this);
286 for (int fi = 0; fi < 4; ++fi)
287 {
288 const Tuple f = tuple_from_face(tid, fi);
289
290 if (!f.is_boundary_face(*this))
291 continue;
292
293 // check if the face contains the vertex
294 for (const Tuple &fv : get_face_vertices(f))
295 {
296 if (fv.vid(*this) == vid)
297 {
298 faces.push_back(f);
299 break;
300 }
301 }
302 }
303 }
304 unique_face_tuples(*this, faces);
305 return faces;
306 }
307
308 template <>
309 std::vector<Tuple> WildTetRemesher::get_one_ring_boundary_edges_for_vertex(const Tuple &v) const
310 {
311 const size_t vid = v.vid(*this);
312
313 std::vector<Tuple> edges;
314 for (const Tuple &f : get_one_ring_boundary_faces_for_vertex(v))
315 {
316 const size_t fid = f.fid(*this);
317
318 const std::array<Tuple, 3> face_edges{{
319 f,
320 f.switch_vertex(*this).switch_edge(*this),
321 f.switch_edge(*this),
322 }};
323
324 for (const Tuple &e : face_edges)
325 {
326 // check if the edge contains the vertex
327 if (e.vid(*this) == vid || e.switch_vertex(*this).vid(*this) == vid)
328 {
329 edges.push_back(e);
330 }
331 }
332 }
333 unique_edge_tuples(*this, edges);
334 return edges;
335 }
336
337 template <>
338 std::array<Tuple, 2> WildTetRemesher::get_boundary_faces_for_edge(const Tuple &e) const
339 {
340 assert(e.is_boundary_edge(*this));
341
342 const size_t tid = e.tid(*this);
343
344 // Find the two boundary faces that the edge belongs to
345 std::array<Tuple, 2> faces{{e, e.switch_face(*this)}};
346 for (Tuple &f : faces)
347 {
348 do
349 {
350 std::optional st = f.switch_tetrahedron(*this);
351 if (!st)
352 break;
353 f = st->switch_face(*this);
354 } while (f.tid(*this) != tid);
355 assert(f.is_boundary_face(*this));
356 }
357 assert(faces[0].fid(*this) != faces[1].fid(*this));
358 return faces;
359 }
360
361 template <>
362 CollapseEdgeTo WildTetRemesher::collapse_boundary_edge_to(const Tuple &e) const
363 {
364 // TODO: handle body boundary edges
365 assert(e.is_boundary_edge(*this));
366
367 const std::array<Tuple, 2> boundary_faces = get_boundary_faces_for_edge(e);
368
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());
374
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;
377
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));
380
381 bool is_v0_movable, is_v1_movable;
382 if (boundary_id0 != boundary_id1 || !utils::are_triangles_coplanar(v0, v1, v2, v0, v1, v3))
383 {
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);
390 };
391
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));
402 };
403
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);
407
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);
411 }
412 else
413 {
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);
421 };
422
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);
425 }
426
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;
433 else
434 return CollapseEdgeTo::MIDPOINT; // collapse to midpoint if both points are movable
435 }
436
437 template <>
438 WildTetRemesher::EdgeAttributes &WildTetRemesher::edge_attr(const size_t e_id)
439 {
440 return edge_attrs[e_id];
441 }
442
443 template <>
444 const WildTetRemesher::EdgeAttributes &WildTetRemesher::edge_attr(const size_t e_id) const
445 {
446 return edge_attrs[e_id];
447 }
448
449} // namespace polyfem::mesh
std::vector< Eigen::VectorXi > faces
std::variant< EdgeMap< T >, FaceMap< T > > BoundaryMap
Definition Remesher.hpp:42
void init_attributes_and_connectivity(const size_t num_vertices, const Eigen::MatrixXi &elements) override
Create an internal mesh representation and associate attributes.
WildTetRemesher::Tuple Tuple
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:71