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