Wildmeshing Toolkit
Loading...
Searching...
No Matches
InsertTriangleUtils.hpp
1#pragma once
2
3#include <wmtk/TetMesh.h>
4#include <wmtk/utils/GeoUtils.h>
5#include <wmtk/threading/concurrent_map.hpp>
6
7#include <Eigen/Core>
8#include <array>
9#include <queue>
10#include <vector>
11#include <wmtk/Types.hpp>
12
13namespace wmtk {
21void match_tet_faces_to_triangles(
22 const wmtk::TetMesh& m,
23 const std::vector<std::array<size_t, 3>>& faces,
24 std::vector<bool>& is_matched,
25 wmtk::threading::concurrent_map<std::array<size_t, 3>, std::vector<int>>& tet_face_tags);
26
27bool remove_duplicates(
28 std::vector<Vector3d>& vertices,
29 std::vector<std::array<size_t, 3>>& faces,
30 const double epsilon);
31
32template <typename rational>
33auto triangle_insert_prepare_info(
34 const wmtk::TetMesh& m,
35 const std::array<size_t, 3>& face_v,
36 std::vector<std::array<size_t, 3>>& marking_tet_faces,
37 const std::function<bool(const std::array<size_t, 3>&)>& try_acquire_triangle,
38 const std::function<bool(const std::vector<wmtk::TetMesh::Tuple>&)>& try_acquire_tetra,
39 const std::function<Eigen::Matrix<rational, 3, 1>(size_t)>& vertex_pos_r)
40{
41 using Vector3r = Eigen::Matrix<rational, 3, 1>;
42 using Vector2r = Eigen::Matrix<rational, 2, 1>;
43 using Tuple = wmtk::TetMesh::Tuple;
44 constexpr int EMPTY_INTERSECTION = 0;
45 constexpr int TRI_INTERSECTION = 1;
46 constexpr int PLN_INTERSECTION = 2;
47
48 static constexpr std::array<std::array<int, 2>, 6> map_leid2lfids = {
49 {{{0, 2}}, {{0, 3}}, {{0, 1}}, {{1, 2}}, {{2, 3}}, {{1, 3}}}};
50 static constexpr std::array<std::array<int, 3>, 4> local_faces = {
51 {{{0, 1, 2}}, {{0, 2, 3}}, {{0, 1, 3}}, {{1, 2, 3}}}};
52 static constexpr std::array<std::array<int, 2>, 6> local_edges = {
53 {{{0, 1}}, {{1, 2}}, {{0, 2}}, {{0, 3}}, {{1, 3}}, {{2, 3}}}};
54
55 bool success_flag = false;
56 std::set<size_t> visited;
57
58 std::array<Vector3r, 3> tri = {
59 {vertex_pos_r(face_v[0]), vertex_pos_r(face_v[1]), vertex_pos_r(face_v[2])}};
60 //
61 Vector3r tri_normal = (tri[1] - tri[0]).cross(tri[2] - tri[0]);
62 //
63 std::array<Vector2r, 3> tri2;
64 int squeeze_to_2d_dir = wmtk::project_triangle_to_2d(tri, tri2);
65
66 std::vector<Tuple> intersected_tets;
67 std::map<std::array<size_t, 2>, std::tuple<int, Vector3r, size_t, int>> map_edge2point;
68 std::map<std::array<size_t, 3>, bool> map_face2intersected;
69 // e = (e0, e1) ==> (intersection_status, intersection_point, edge's_tid,
70 // local_eid_in_tet)
71 std::set<std::array<size_t, 2>> intersected_tet_edges;
72 //
73 std::queue<Tuple> tet_queue;
74
75 if (!try_acquire_triangle(face_v)) {
76 return std::tuple(
77 success_flag,
78 std::vector<Tuple>(),
79 std::vector<Tuple>(),
80 std::vector<Vector3r>());
81 }
82
83 for (int j = 0; j < 3; j++) {
84 auto loc = m.tuple_from_vertex(face_v[j]);
85 auto conn_tets = m.get_one_ring_tets_for_vertex(loc);
86 for (const auto& t : conn_tets) {
87 if (visited.find(t.tid(m)) != visited.end()) continue;
88 tet_queue.push(t);
89 visited.insert(t.tid(m));
90 }
91 }
92 //
93 constexpr auto is_seg_cut_tri_2 = [](const std::array<Vector2r, 2>& seg2d,
94 const std::array<Vector2r, 3>& tri2d) {
95 // overlap == seg has one endpoint inside tri OR seg intersect with tri edges
96 bool is_inside = wmtk::is_point_inside_triangle(seg2d[0], tri2d) ||
97 wmtk::is_point_inside_triangle(seg2d[1], tri2d);
98 if (is_inside) {
99 return true;
100 } else {
101 for (int j = 0; j < 3; j++) {
102 std::array<Vector2r, 2> tri_seg2 = {{tri2d[j], tri2d[(j + 1) % 3]}};
103 rational _;
104 bool is_intersected =
105 wmtk::open_segment_open_segment_intersection_2d(seg2d, tri_seg2, _);
106 if (is_intersected) {
107 return true;
108 }
109 }
110 }
111 return false;
112 };
113 //
114 // BFS
115 while (!tet_queue.empty()) {
116 auto tet = tet_queue.front();
117 tet_queue.pop();
118
119 std::array<bool, 4> is_tet_face_intersected = {{false, false, false, false}};
120
122 int cnt_pos = 0;
123 int cnt_neg = 0;
124 std::map<size_t, int> vertex_sides;
125 std::vector<int> coplanar_f_lvids;
126 //
127 auto vs = m.oriented_tet_vertices(tet);
128
129 auto retry_flag = !try_acquire_tetra(std::vector<Tuple>{{tet}});
130 if (retry_flag) {
131 return std::tuple(
132 success_flag,
133 std::vector<Tuple>(),
134 std::vector<Tuple>(),
135 std::vector<Vector3r>());
136 }
137
138 std::array<size_t, 4> vertex_vids;
139 for (int j = 0; j < 4; j++) {
140 vertex_vids[j] = vs[j].vid(m);
141 Vector3r dir = vertex_pos_r(vertex_vids[j]) - tri[0];
142 auto side = dir.dot(tri_normal);
143 if (side > 0) {
144 cnt_pos++;
145 vertex_sides[vertex_vids[j]] = 1;
146 } else if (side < 0) {
147 cnt_neg++;
148 vertex_sides[vertex_vids[j]] = -1;
149 } else {
150 coplanar_f_lvids.push_back(j);
151 vertex_sides[vertex_vids[j]] = 0;
152 }
153 }
154 //
155 if (coplanar_f_lvids.size() == 1) {
156 int lvid = coplanar_f_lvids[0];
157 size_t vid = vertex_vids[lvid];
158 auto p = wmtk::project_point_to_2d(vertex_pos_r(vid), squeeze_to_2d_dir);
159 bool is_inside = wmtk::is_point_inside_triangle(p, tri2);
160 //
161 if (is_inside) {
162 auto conn_tets = m.get_one_ring_tets_for_vertex(vs[lvid]);
163 for (auto& t : conn_tets) {
164 if (visited.find(t.tid(m)) != visited.end()) continue;
165 visited.insert(t.tid(m));
166 tet_queue.push(t);
167 }
168 }
169 } else if (coplanar_f_lvids.size() == 2) {
170 std::array<Vector2r, 2> seg2;
171 seg2[0] = wmtk::project_point_to_2d(
172 vertex_pos_r(vertex_vids[coplanar_f_lvids[0]]),
173 squeeze_to_2d_dir);
174 seg2[1] = wmtk::project_point_to_2d(
175 vertex_pos_r(vertex_vids[coplanar_f_lvids[1]]),
176 squeeze_to_2d_dir);
177 if (is_seg_cut_tri_2(seg2, tri2)) {
178 std::array<int, 2> le = {{coplanar_f_lvids[0], coplanar_f_lvids[1]}};
179 if (le[0] > le[1]) std::swap(le[0], le[1]);
180 int leid =
181 std::find(local_edges.begin(), local_edges.end(), le) - local_edges.begin();
182 is_tet_face_intersected[map_leid2lfids[leid][0]] = true;
183 is_tet_face_intersected[map_leid2lfids[leid][1]] = true;
184 //
185 for (int j = 0; j < 2; j++) {
186 auto conn_tets = m.get_one_ring_tets_for_vertex(vs[coplanar_f_lvids[j]]);
187 for (auto& t : conn_tets) {
188 if (visited.find(t.tid(m)) != visited.end()) continue;
189 visited.insert(t.tid(m));
190 // add lock
191 tet_queue.push(t);
192 }
193 }
194 }
195 } else if (coplanar_f_lvids.size() == 3) {
196 bool is_cut = false;
197 for (int i = 0; i < 3; i++) {
198 std::array<Vector2r, 2> seg2;
199 seg2[0] = wmtk::project_point_to_2d(
200 vertex_pos_r(vertex_vids[coplanar_f_lvids[i]]),
201 squeeze_to_2d_dir);
202 seg2[1] = wmtk::project_point_to_2d(
203 vertex_pos_r(vertex_vids[coplanar_f_lvids[(i + 1) % 3]]),
204 squeeze_to_2d_dir);
205 if (is_seg_cut_tri_2(seg2, tri2)) {
206 is_cut = true;
207 break;
208 }
209 }
210 if (is_cut) {
211 std::array<size_t, 3> f = {
212 {vertex_vids[coplanar_f_lvids[0]],
213 vertex_vids[coplanar_f_lvids[1]],
214 vertex_vids[coplanar_f_lvids[2]]}};
215 std::sort(f.begin(), f.end());
216 marking_tet_faces.push_back(f);
217 // tet_face_tags[f].push_back(face_id);
218 //
219 for (int j = 0; j < 3; j++) {
220 auto conn_tets = m.get_one_ring_tets_for_vertex(vs[coplanar_f_lvids[j]]);
221 for (auto& t : conn_tets) {
222 if (visited.find(t.tid(m)) != visited.end()) continue;
223 visited.insert(t.tid(m));
224 // add lock
225 tet_queue.push(t);
226 }
227 }
228 }
229 }
230 //
231 if (cnt_pos == 0 || cnt_neg == 0) {
232 continue;
233 }
234
236 std::array<Tuple, 6> edges = m.tet_edges(tet);
237 //
238 std::vector<std::array<size_t, 2>> edge_vids;
239 for (auto& loc : edges) {
240 size_t v1_id = loc.vid(m);
241 auto tmp = m.switch_vertex(loc);
242 size_t v2_id = tmp.vid(m);
243 std::array<size_t, 2> e = {{v1_id, v2_id}};
244 if (e[0] > e[1]) std::swap(e[0], e[1]);
245 edge_vids.push_back(e);
246 }
247
249 bool need_subdivision = false;
250 for (int l_eid = 0; l_eid < edges.size(); l_eid++) {
251 const std::array<size_t, 2>& e = edge_vids[l_eid];
252 if (vertex_sides[e[0]] * vertex_sides[e[1]] >= 0) continue;
253
254 if (map_edge2point.find(e) != map_edge2point.end()) {
255 if (std::get<0>(map_edge2point[e]) == TRI_INTERSECTION) {
256 for (int k = 0; k < 2; k++)
257 is_tet_face_intersected[map_leid2lfids[l_eid][k]] = true;
258 need_subdivision = true;
259 }
260 continue;
261 }
262
263 std::array<Vector3r, 2> seg = {{vertex_pos_r(e[0]), vertex_pos_r(e[1])}};
264 Vector3r p(0, 0, 0);
265 int intersection_status = EMPTY_INTERSECTION;
266 bool is_inside_tri = false;
267 bool is_intersected_plane =
268 wmtk::open_segment_plane_intersection_3d(seg, tri, p, is_inside_tri);
269 if (is_intersected_plane && is_inside_tri) {
270 intersection_status = TRI_INTERSECTION;
271 } else if (is_intersected_plane) {
272 intersection_status = PLN_INTERSECTION;
273 }
274
275 map_edge2point[e] = std::make_tuple(intersection_status, p, tet.tid(m), l_eid);
276 if (intersection_status == EMPTY_INTERSECTION) {
277 continue;
278 } else if (intersection_status == TRI_INTERSECTION) {
279 for (int k = 0; k < 2; k++)
280 is_tet_face_intersected[map_leid2lfids[l_eid][k]] = true;
281 need_subdivision = true;
282 }
283
284 // add new tets
285 if (need_subdivision) {
286 auto incident_tets = m.get_incident_tets_for_edge(edges[l_eid]);
287 for (const auto& t : incident_tets) {
288 size_t tid = t.tid(m);
289 if (visited.find(tid) != visited.end()) {
290 continue;
291 }
292
293 tet_queue.push(t);
294 visited.insert(tid);
295 }
296 }
297 }
298
300 for (int j = 0; j < 4; j++) { // for each tet face
301 if (is_tet_face_intersected[j]) continue;
302 std::array<size_t, 3> f = {
303 {vs[local_faces[j][0]].vid(m),
304 vs[local_faces[j][1]].vid(m),
305 vs[local_faces[j][2]].vid(m)}};
306 std::sort(f.begin(), f.end());
307 auto it = map_face2intersected.find(f);
308 if (it != map_face2intersected.end()) {
309 if (it->second) need_subdivision = true;
310 continue;
311 }
312
313 {
314 int cnt_pos1 = 0;
315 int cnt_neg1 = 0;
316 for (int k = 0; k < 3; k++) {
317 if (vertex_sides[f[k]] > 0)
318 cnt_pos1++;
319 else if (vertex_sides[f[k]] < 0)
320 cnt_neg1++;
321 }
322 if (cnt_pos1 == 0 || cnt_neg1 == 0) continue;
323 }
324
325 std::array<Vector3r, 3> tet_tri = {
326 {vertex_pos_r(f[0]), vertex_pos_r(f[1]), vertex_pos_r(f[2])}};
327 //
328 std::array<int, 3> tet_tri_v_sides;
329 Vector3r tet_tri_normal = (tet_tri[1] - tet_tri[0]).cross(tet_tri[2] - tet_tri[0]);
330 for (int k = 0; k < 3; k++) {
331 Vector3r dir = tri[k] - tet_tri[0];
332 auto side = dir.dot(tet_tri_normal);
333 if (side == 0)
334 tet_tri_v_sides[k] = 0;
335 else if (side > 0)
336 tet_tri_v_sides[k] = 1;
337 else
338 tet_tri_v_sides[k] = -1;
339 }
340
341 bool is_intersected = false;
342 for (int k = 0; k < 3; k++) { // check intersection
343 if ((tet_tri_v_sides[k] >= 0 && tet_tri_v_sides[(k + 1) % 3] >= 0) ||
344 (tet_tri_v_sides[k] <= 0 && tet_tri_v_sides[(k + 1) % 3] <= 0))
345 continue;
346 Vector3r _p;
347 is_intersected = wmtk::open_segment_triangle_intersection_3d(
348 {{tri[k], tri[(k + 1) % 3]}},
349 tet_tri,
350 _p);
351 if (is_intersected) {
352 need_subdivision = true; // is recorded
353 break;
354 }
355 }
356 map_face2intersected[f] = is_intersected;
357
358 if (is_intersected) {
359 auto res = m.switch_tetrahedron(m.tuple_from_face(tet.tid(m), j));
360 if (res.has_value()) {
361 auto n_tet = res.value();
362 size_t tid = n_tet.tid(m);
363 if (visited.find(tid) != visited.end()) {
364 continue;
365 }
366 // add lock
367 tet_queue.push(n_tet);
368 visited.insert(tid);
369 }
370 }
371 }
372
373
375 if (need_subdivision) {
376 intersected_tets.push_back(tet);
377 //
378 for (auto& e : edge_vids) {
379 intersected_tet_edges.insert(e);
380 }
381 }
382 } // End BFS while (!tet_queue.empty())
383
384 // erase edge without intersections OR edge with intersection but not belong to
385 // intersected tets
386 for (auto it = map_edge2point.begin(), ite = map_edge2point.end(); it != ite;) {
387 if (std::get<0>(it->second) == EMPTY_INTERSECTION ||
388 intersected_tet_edges.find(it->first) == intersected_tet_edges.end())
389 it = map_edge2point.erase(it);
390 else
391 ++it;
392 }
393 success_flag = true;
394 std::vector<TetMesh::Tuple> intersected_edges;
395 std::vector<Vector3r> intersected_pos;
396 for (auto& info : map_edge2point) {
397 auto& [_, p, tid, l_eid] = info.second;
398 intersected_edges.push_back(m.tuple_from_edge(tid, l_eid));
399 intersected_pos.push_back(p);
400 }
401 return std::tuple(success_flag, intersected_tets, intersected_edges, intersected_pos);
402}
403} // namespace wmtk
a Tuple refers to a global vid and a global tet id, and a local edge id and local face id
Definition TetMesh.h:49
size_t vid(const TetMesh &m) const
Definition TetMeshTuple.cpp:106
Definition TetMesh.h:24
std::array< Tuple, 6 > tet_edges(const Tuple &t) const
get the 6 edges of a tet represented by Tuples
Definition TetMesh.cpp:750
std::array< Tuple, 4 > oriented_tet_vertices(const Tuple &t) const
Definition TetMesh.cpp:710
std::vector< Tuple > get_incident_tets_for_edge(const Tuple &t) const
Get the incident tets for edge.
Definition TetMesh.cpp:859
Tuple tuple_from_vertex(size_t vid) const
get a Tuple from global vertex index
Definition TetMesh.cpp:627
std::optional< Tuple > switch_tetrahedron(const Tuple &t) const
wrapper function from Tuple::switch_tetrahedron
Definition TetMesh.h:1070
Tuple tuple_from_edge(size_t tid, int local_eid) const
get a Tuple from global tetra index and local edge index (from 0-5).
Definition TetMesh.cpp:377
Tuple switch_vertex(const Tuple &t) const
wrapper function from Tuple::switch_vertex
Definition TetMesh.h:1043
Tuple tuple_from_face(size_t tid, int local_fid) const
get a Tuple from global tetra index and local face index (from 0-3).
Definition TetMesh.cpp:387
std::vector< Tuple > get_one_ring_tets_for_vertex(const Tuple &t) const
Get the one ring tets for a vertex.
Definition TetMesh.cpp:776
Definition concurrent_map.hpp:66