PolyFEM
Loading...
Searching...
No Matches
WildTriRemesher.cpp
Go to the documentation of this file.
1#include "WildRemesher.hpp"
2
5
6#include <wmtk/utils/TriQualityUtils.hpp>
7
8#include <igl/predicates/predicates.h>
9
10namespace polyfem::mesh
11{
13
14 template <>
16 const size_t num_vertices, const Eigen::MatrixXi &triangles)
17 {
18 // Register attributes
19 p_vertex_attrs = &vertex_attrs;
20 p_edge_attrs = &boundary_attrs;
21 p_face_attrs = &element_attrs;
22
23 // Convert from eigen to internal representation
24 std::vector<std::array<size_t, 3>> tri(triangles.rows());
25 for (int i = 0; i < triangles.rows(); i++)
26 for (int j = 0; j < triangles.cols(); j++)
27 tri[i][j] = (size_t)triangles(i, j);
28
29 // Initialize the trimesh class which handles connectivity
30 wmtk::TriMesh::create_mesh(num_vertices, tri);
31 }
32
33 template <>
34 WildTriRemesher::BoundaryMap<int> WildTriRemesher::boundary_ids() const
35 {
36 const std::vector<Tuple> edges = get_edges();
37 EdgeMap<int> boundary_ids;
38 for (const Tuple &edge : edges)
39 {
40 const size_t e0 = edge.vid(*this);
41 const size_t e1 = edge.switch_vertex(*this).vid(*this);
42 boundary_ids[{{e0, e1}}] = boundary_attrs[edge.eid(*this)].boundary_id;
43 }
44 return boundary_ids;
45 }
46
47 template <>
48 bool WildTriRemesher::is_rest_inverted(const Tuple &loc) const
49 {
50 // Get the vertices ids
51 const std::array<size_t, 3> vids = oriented_tri_vids(loc);
52
53 igl::predicates::exactinit();
54
55 // Use igl for checking orientation
56 const igl::predicates::Orientation orientation =
57 igl::predicates::orient2d(
58 vertex_attrs[vids[0]].rest_position,
59 vertex_attrs[vids[1]].rest_position,
60 vertex_attrs[vids[2]].rest_position);
61
62 // The element is inverted if it not positive (i.e. it is negative or it is degenerate)
63 return orientation != igl::predicates::Orientation::POSITIVE;
64 }
65
66 template <>
67 bool WildTriRemesher::is_inverted(const Tuple &loc) const
68 {
69 // Get the vertices ids
70 const std::array<size_t, 3> vids = oriented_tri_vids(loc);
71
72 igl::predicates::exactinit();
73
74 for (int i = 0; i < n_quantities() / 3 + 2; ++i)
75 {
76 // Use igl for checking orientation
77 const igl::predicates::Orientation orientation =
78 igl::predicates::orient2d(
79 vertex_attrs[vids[0]].position_i(i),
80 vertex_attrs[vids[1]].position_i(i),
81 vertex_attrs[vids[2]].position_i(i));
82
83 // The element is inverted if it not positive (i.e. it is negative or it is degenerate)
84 if (orientation != igl::predicates::Orientation::POSITIVE)
85 return true;
86 }
87
88 return false;
89 }
90
91 template <>
92 double WildTriRemesher::element_volume(const Tuple &e) const
93 {
94 const std::array<size_t, 3> vids = oriented_tri_vids(e);
95 return utils::triangle_area_2D(
96 vertex_attrs[vids[0]].rest_position,
97 vertex_attrs[vids[1]].rest_position,
98 vertex_attrs[vids[2]].rest_position);
99 }
100
101 template <>
102 size_t WildTriRemesher::facet_id(const Tuple &t) const
103 {
104 return t.eid(*this);
105 }
106
107 template <>
108 size_t WildTriRemesher::element_id(const Tuple &t) const
109 {
110 return t.fid(*this);
111 }
112
113 template <>
114 Tuple WildTriRemesher::tuple_from_element(size_t elem_id) const
115 {
116 return tuple_from_tri(elem_id);
117 }
118
119 template <>
120 Tuple WildTriRemesher::tuple_from_facet(size_t elem_id, int local_facet_id) const
121 {
122 return tuple_from_edge(elem_id, local_facet_id);
123 }
124
125 template <>
126 bool WildTriRemesher::is_boundary_edge(const Tuple &e) const
127 {
128 return TriMesh::is_boundary_edge(e);
129 }
130
131 template <>
132 bool WildTriRemesher::is_body_boundary_edge(const Tuple &e) const
133 {
134 const auto adj_face = e.switch_face(*this);
135 return !adj_face.has_value()
136 || element_attrs[element_id(e)].body_id
137 != element_attrs[element_id(*adj_face)].body_id;
138 }
139
140 template <>
141 bool WildTriRemesher::is_boundary_vertex(const Tuple &v) const
142 {
143 return TriMesh::is_boundary_vertex(v);
144 }
145
146 template <>
147 bool WildTriRemesher::is_body_boundary_vertex(const Tuple &v) const
148 {
149 for (const auto &e : get_one_ring_edges_for_vertex(v))
150 if (is_body_boundary_edge(e))
151 return true;
152 return false;
153 }
154
155 template <>
156 bool WildTriRemesher::is_boundary_facet(const Tuple &t) const
157 {
158 return is_boundary_edge(t);
159 }
160
161 template <>
162 bool WildTriRemesher::is_boundary_op() const
163 {
164 return op_cache->is_boundary_op();
165 }
166
167 template <>
168 Eigen::MatrixXi WildTriRemesher::boundary_edges() const
169 {
170 const std::vector<Tuple> boundary_edge_tuples = boundary_facets();
171 Eigen::MatrixXi BE(boundary_edge_tuples.size(), 2);
172 for (int i = 0; i < BE.rows(); ++i)
173 {
174 BE(i, 0) = boundary_edge_tuples[i].vid(*this);
175 BE(i, 1) = boundary_edge_tuples[i].switch_vertex(*this).vid(*this);
176 }
177 if (obstacle().n_edges() > 0)
178 utils::append_rows(BE, obstacle().e().array() + vert_capacity());
179 return BE;
180 }
181
182 template <>
183 Eigen::MatrixXi WildTriRemesher::boundary_faces() const
184 {
185 return Eigen::MatrixXi();
186 }
187
188 template <>
189 std::vector<Tuple> WildTriRemesher::get_facets() const
190 {
191 return get_edges();
192 }
193
194 template <>
195 std::vector<Tuple> WildTriRemesher::get_elements() const
196 {
197 return get_faces();
198 }
199
200 template <>
201 std::array<Tuple, 2> WildTriRemesher::facet_vertices(const Tuple &t) const
202 {
203 return {{t, t.switch_vertex(*this)}};
204 }
205
206 template <>
207 std::array<size_t, 2> WildTriRemesher::facet_vids(const Tuple &t) const
208 {
209 return {{t.vid(*this), t.switch_vertex(*this).vid(*this)}};
210 }
211
212 template <>
213 std::array<Tuple, 3> WildTriRemesher::element_vertices(const Tuple &t) const
214 {
215 return oriented_tri_vertices(t);
216 }
217
218 template <>
219 std::array<size_t, 3> WildTriRemesher::element_vids(const Tuple &t) const
220 {
221 return oriented_tri_vids(t);
222 }
223
224 template <>
225 std::array<size_t, 3> WildTriRemesher::orient_preserve_element_reorder(
226 const std::array<size_t, 3> &conn, const size_t v0) const
227 {
228 return wmtk::orient_preserve_tri_reorder(conn, v0);
229 }
230
231 template <>
232 std::vector<Tuple> WildTriRemesher::get_one_ring_elements_for_vertex(const Tuple &t) const
233 {
234 return get_one_ring_tris_for_vertex(t);
235 }
236
237 template <>
238 std::vector<Tuple> WildTriRemesher::get_one_ring_boundary_edges_for_vertex(const Tuple &v) const
239 {
240 std::vector<Tuple> edges;
241 for (const auto &e : get_one_ring_edges_for_vertex(v))
242 if (is_boundary_edge(e))
243 edges.push_back(e);
244 return edges;
245 }
246
247 template <>
248 std::vector<Tuple> WildTriRemesher::get_incident_elements_for_edge(const Tuple &t) const
249 {
250 std::vector<Tuple> tris{{t}};
251 if (t.switch_face(*this))
252 tris.push_back(t.switch_face(*this).value());
253 return tris;
254 }
255
256 template <>
257 CollapseEdgeTo WildTriRemesher::collapse_boundary_edge_to(const Tuple &e) const
258 {
259 const int eid = e.eid(*this);
260 const int v0i = e.vid(*this);
261 const int v1i = e.switch_vertex(*this).vid(*this);
262
263 const Eigen::Vector2d &v0 = vertex_attrs[v0i].rest_position;
264 const Eigen::Vector2d &v1 = vertex_attrs[v1i].rest_position;
265
266 const int boundary_id = boundary_attrs[eid].boundary_id;
267
268 const auto is_collinear = [&](const Tuple &e0) {
269 const size_t e0_id = e0.eid(*this);
270 const size_t v2_id = e0.vid(*this);
271 const size_t v3_id = e0.switch_vertex(*this).vid(*this);
272 return e0_id != eid
273 && boundary_attrs[e0_id].boundary_id == boundary_id
274 && is_body_boundary_edge(e0)
275 && utils::are_edges_collinear(
276 v0, v1, vertex_attrs[v2_id].rest_position,
277 vertex_attrs[v3_id].rest_position);
278 };
279
280 const std::vector<Tuple> v0_edges = get_one_ring_edges_for_vertex(e);
281 const bool is_v0_collinear = std::any_of(v0_edges.begin(), v0_edges.end(), is_collinear);
282
283 const std::vector<Tuple> v1_edges = get_one_ring_edges_for_vertex(e.switch_vertex(*this));
284 const bool is_v1_collinear = std::any_of(v1_edges.begin(), v1_edges.end(), is_collinear);
285
286 if (!is_v0_collinear && !is_v1_collinear)
287 return CollapseEdgeTo::ILLEGAL; // only collapse boundary edges that have collinear neighbors
288 else if (!is_v0_collinear)
289 return CollapseEdgeTo::V0;
290 else if (!is_v1_collinear)
291 return CollapseEdgeTo::V1;
292 else
293 return CollapseEdgeTo::MIDPOINT; // collapse to midpoint if both points are collinear
294 }
295
296 template <>
297 WildTriRemesher::EdgeAttributes &WildTriRemesher::edge_attr(const size_t e_id)
298 {
299 return boundary_attrs[e_id];
300 }
301
302 template <>
303 const WildTriRemesher::EdgeAttributes &WildTriRemesher::edge_attr(const size_t e_id) const
304 {
305 return boundary_attrs[e_id];
306 }
307
308} // namespace polyfem::mesh
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