Wildmeshing Toolkit
Loading...
Searching...
No Matches
TriMeshOperationExecutor.cpp
Go to the documentation of this file.
1// kills a gcc-13 warning
2#if defined(__GNUG__) && !defined(__clang__)
3#pragma GCC diagnostic push
4// this warning only exists for gcc >= 13.0
5#if __GNUC__ > 12
6#pragma GCC diagnostic ignored "-Wdangling-pointer"
7#endif // check gnu version
8#endif
9// clang-format off
10#include <Eigen/Core>
11
12#include <Eigen/src/Core/MapBase.h>
13// clang-format on
14
15#if defined(__GNUG__) && !defined(__clang__)
16#pragma GCC diagnostic pop
17#endif
18
28
30
31namespace wmtk {
32
33constexpr static PrimitiveType PV = PrimitiveType::Vertex;
34constexpr static PrimitiveType PE = PrimitiveType::Edge;
36{
37 return m_mesh.switch_tuples(tuple, {PV, PE});
38}
40{
41 return m_mesh.switch_tuples(tuple, {PE, PV});
42}
44{
45 /* / \
46 // ear1 / \ ear2
47 // / \
48 // / \
49 // X----t----
50 */
51
52 // make sure that edge and vertex of the tuple are the same
53 for (int i = 0; i < 3; ++i) {
55 m_mesh,
56 simplex::Simplex::edge(m_mesh, t),
57 simplex::Simplex::edge(m_mesh, m_operating_tuple))) {
58 break;
59 }
60 t = next_edge(t);
61 }
63 m_mesh,
64 simplex::Simplex::edge(m_mesh, t),
65 simplex::Simplex::edge(m_mesh, m_operating_tuple)));
66
68 m_mesh,
69 simplex::Simplex::vertex(m_mesh, t),
70 simplex::Simplex::vertex(m_mesh, m_operating_tuple))) {
71 t = m_mesh.switch_vertex(t);
72 }
74 m_mesh,
75 simplex::Simplex::vertex(m_mesh, t),
76 simplex::Simplex::vertex(m_mesh, m_operating_tuple)));
77
78 const std::array<Tuple, 2> ear_edges{
79 {m_mesh.switch_edge(t), m_mesh.switch_edge(m_mesh.switch_vertex(t))}};
80
81 IncidentFaceData face_data;
82 face_data.local_operating_tuple = t;
83 face_data.fid = m_mesh.id_face(t);
84 face_data.opposite_vid = m_mesh.id_vertex(m_mesh.switch_vertex(ear_edges[0]));
85
86 std::transform(
87 ear_edges.begin(),
88 ear_edges.end(),
89 face_data.ears.begin(),
90 [&](const Tuple& edge) {
91 // accessing ear face id through FF to make it work also at boundaries
92 const int64_t ear_fid = ff_accessor.const_vector_attribute(edge)[edge.local_eid()];
93
94 return EarData{
95 /*.fid = */ ear_fid,
96 /*.eid = */ m_mesh.id_edge(edge)};
97 });
98
99 return face_data;
100}
101
102// constructor
104 TriMesh& m,
105 const Tuple& operating_tuple)
107 , ff_accessor(*m.m_ff_accessor)
108 , fe_accessor(*m.m_fe_accessor)
109 , fv_accessor(*m.m_fv_accessor)
110 , vf_accessor(*m.m_vf_accessor)
111 , ef_accessor(*m.m_ef_accessor)
112 , m_mesh(m)
113
114{
115 assert(m.is_connectivity_valid());
116 m_operating_tuple = operating_tuple;
117 // store ids of edge and incident vertices
118 m_operating_edge_id = m_mesh.id_edge(m_operating_tuple);
119 m_spine_vids[0] = m_mesh.id_vertex(m_operating_tuple);
120 m_spine_vids[1] = m_mesh.id_vertex(m_mesh.switch_vertex(m_operating_tuple));
121}
122
124{
125 for (size_t d = 0; d < simplex_ids_to_delete.size(); ++d) {
126 wmtk::logger().trace(
127 "Deleting {} {}-simplices [{}]",
128 simplex_ids_to_delete[d].size(),
129 d,
130 fmt::join(simplex_ids_to_delete[d], ","));
131 for (const int64_t id : simplex_ids_to_delete[d]) {
132 flag_accessors[d].index_access().deactivate(id);
133 }
134 }
135}
136
137
138const std::array<std::vector<int64_t>, 3>
140 const Tuple& tuple,
141 const TriMesh& m)
142{
144 std::array<std::vector<int64_t>, 3> ids;
145 for (const simplex::Simplex& s : sc) {
146 ids[get_primitive_type_id(s.primitive_type())].emplace_back(m.id(s));
147 }
148
149 return ids;
150}
151
152const std::array<std::vector<int64_t>, 3>
154 const Tuple& tuple,
155 const TriMesh& m)
156{
157 std::array<std::vector<int64_t>, 3> ids;
158 if (m.is_free()) {
159 auto get_sc = [&]() -> simplex::SimplexCollection {
161
163 sc.add(simp);
164 return sc;
165 };
166 for (const simplex::Simplex& s : get_sc()) {
167 ids[get_primitive_type_id(s.primitive_type())].emplace_back(m.id(s));
168 }
169 } else {
170 const simplex::Simplex v(m, PrimitiveType::Vertex, tuple);
171 const simplex::Simplex e(m, PrimitiveType::Edge, tuple);
172 ids[0].emplace_back(m.id(v));
173 ids[1].emplace_back(m.id(e));
174 /* `top_dimension_cofaces_iterable()` preserves the tuple as much as possible. It always
175 * contains the edge and the vertex.
176 */
178 ids[2].emplace_back(m.id(t, PrimitiveType::Triangle));
179 t = m.switch_edge(t);
180 ids[1].emplace_back(m.id(t, PrimitiveType::Edge));
181 }
182 for (size_t i = 0; i < ids.size(); ++i) {
183 std::sort(ids[i].begin(), ids[i].end());
184 }
185 }
186
187 return ids;
188}
189
200 const EarData& ear,
201 const int64_t new_fid,
202 const int64_t old_fid)
203{
204 // /|
205 // ear / |
206 // / new_face
207 // / |
208 // -----
209 if (ear.fid < 0) {
210 return;
211 }
212
213 auto ear_ff = ff_accessor.index_access().vector_attribute(ear.fid);
214 auto ear_fe = fe_accessor.index_access().vector_attribute(ear.fid);
215 for (int i = 0; i < 3; ++i) {
216 if (ear_ff[i] == old_fid) {
217 ear_ff[i] = new_fid;
218 ear_fe[i] = ear.eid;
219 break;
220 }
221 }
222
223 ef_accessor.index_access().scalar_attribute(ear.eid) = ear.fid;
224}
225
227{
228 assert(!m_incident_face_datas.empty());
229
230 // ---------v2--------
231 // | / \ |
232 // | ef0 / \ ef1 |
233 // | / \ |
234 // | / \ |
235 // | ee0 ee1 |
236 // | / f_old \ |
237 // | / \ |
238 // | / \ |
239 // v0------ --> ------v1
240 // deleting: v0, ee0, f
241
242 for (auto& face_data : m_incident_face_datas) {
243 const EarData& ear0 = face_data.ears[0];
244 const EarData& ear1 = face_data.ears[1];
245 const int64_t& f_old = face_data.fid;
246 const int64_t& v1 = m_spine_vids[1];
247
248 // TODO: should be detected by link condition
249 assert(ear0.fid > -1 || ear1.fid > -1);
250 // check manifoldness
251 assert(ear0.fid != ear1.fid);
252
253 // change face for v2
254 int64_t& new_opp_vf = vf_accessor.index_access().scalar_attribute(face_data.opposite_vid);
255 // use ef0 if it exists
256 new_opp_vf = (ear0.fid < 0) ? ear1.fid : ear0.fid;
257
258 face_data.new_edge_id = ear1.eid;
259 // for multimesh update
260 face_data.merged_edge_fid = new_opp_vf;
261
262 int64_t& ef_val = ef_accessor.index_access().scalar_attribute(ear1.eid);
263 int64_t& vf_val = vf_accessor.index_access().scalar_attribute(v1);
264
265
266 ef_val = new_opp_vf;
267 vf_val = new_opp_vf;
268
269
270 EarData new_f0_ear{ear0.fid, ear1.eid};
271 // change FF and FE for ears
272 update_ids_in_ear(new_f0_ear, ear1.fid, f_old);
273 update_ids_in_ear(ear1, ear0.fid, f_old);
274 }
275}
276
278{
279 // find the local eid of the spine of the two side of faces
280 assert(m_incident_face_datas.size() == 2);
281 const int64_t f_old_top = m_incident_face_datas[0].fid;
282 const int64_t f0_top = m_incident_face_datas[0].split_f[0];
283 const int64_t f1_top = m_incident_face_datas[0].split_f[1];
284 const int64_t f_old_bottom = m_incident_face_datas[1].fid;
285 const int64_t f0_bottom = m_incident_face_datas[1].split_f[0];
286 const int64_t f1_bottom = m_incident_face_datas[1].split_f[1];
287 auto ff_old_top = ff_accessor.index_access().const_vector_attribute(f_old_top);
288 auto ff_old_bottom = ff_accessor.index_access().const_vector_attribute(f_old_bottom);
289 assert(m_mesh.capacity(PrimitiveType::Triangle) > f0_top);
290 assert(m_mesh.capacity(PrimitiveType::Triangle) > f1_top);
291 assert(m_mesh.capacity(PrimitiveType::Triangle) > f0_bottom);
292 assert(m_mesh.capacity(PrimitiveType::Triangle) > f1_bottom);
293
294 // local edge ids are the same for both, f1 and f2
295 int64_t local_eid_top = -1;
296 int64_t local_eid_bottom = -1;
297 for (size_t i = 0; i < 3; ++i) {
298 if (ff_old_top[i] == f_old_bottom) {
299 local_eid_top = i;
300 }
301 if (ff_old_bottom[i] == f_old_top) {
302 local_eid_bottom = i;
303 }
304 }
305 assert(local_eid_top > -1);
306 assert(local_eid_bottom > -1);
307 // TODO write test for assumming top and bottom new fids are in right correspondence
308 ff_accessor.index_access().vector_attribute(f0_top)[local_eid_top] = f0_bottom;
309 ff_accessor.index_access().vector_attribute(f0_bottom)[local_eid_bottom] = f0_top;
310 ff_accessor.index_access().vector_attribute(f1_top)[local_eid_top] = f1_bottom;
311 ff_accessor.index_access().vector_attribute(f1_bottom)[local_eid_bottom] = f1_top;
312}
313
315{
316 const auto& new_fids = face_data.split_f;
317 logger().trace(
318 "TriSplitreplacing topology of face {} with {}",
319 face_data.fid,
320 fmt::join(new_fids, ","));
321
322 if (!m_mesh.is_free()) {
323 std::vector<int64_t> splitting_edges =
325 assert(splitting_edges[0] > -1); // TODO: is this assert reasonable at all?
326 int64_t& split_edge_eid = face_data.new_edge_id;
327 split_edge_eid = splitting_edges[0];
328 }
329
330 // ---------v2--------
331 // | /|\ |
332 // | ef0 / | \ ef1 |
333 // | / | \ |
334 // | / oe \ |
335 // | ee0 | ee1 |
336 // | / | \ |
337 // | / f0 | f1 \ |
338 // | / | \ |
339 // v0--se0-v_new-se1--v1
340
341 const int64_t v_opp = face_data.opposite_vid; // opposite vertex
342 const int64_t f_old = face_data.fid; // old face
343 auto old_fv = fv_accessor.index_access().const_vector_attribute(f_old).eval();
344 auto old_fe = fe_accessor.index_access().const_vector_attribute(f_old).eval();
345 auto old_ff = ff_accessor.index_access().const_vector_attribute(f_old).eval();
346
347 // f0
348 for (int j = 0; j < 2; ++j) {
349 int other_index = 1 - j;
350 const int64_t f = face_data.split_f[j]; // new face to insert
351 const auto& ear = face_data.ears[j];
352
353 const auto& other_ear = face_data.ears[other_index];
354
355 const int64_t other_f = face_data.split_f[other_index];
356 const int64_t other_v =
357 m_spine_vids[other_index]; // v from the original spine that needs to be replaced
358 const int64_t se = split_spine_eids[j]; // new spine edge to replace
359
360 assert(se != -1);
361
362 update_ids_in_ear(ear, f, f_old);
363
364 auto fv = fv_accessor.index_access().vector_attribute(f);
365 auto fe = fe_accessor.index_access().vector_attribute(f);
366 auto ff = ff_accessor.index_access().vector_attribute(f);
367 fv = old_fv;
368 fe = old_fe;
369 ff = old_ff;
370 // correct old connectivity
371 for (size_t i = 0; i < 3; ++i) {
372 // if the original face edge was the other ear's edge then we replace it with thee
373 // spline
374 if (fe[i] == other_ear.eid) {
375 if (m_mesh.is_free()) {
376 fe[i] = m_free_split_e[j];
377 } else {
378 const int64_t& split_edge_eid = face_data.new_edge_id;
379 ff[i] = other_f;
380 fe[i] = split_edge_eid;
381 logger().trace("ff[{},{}] = {}", f, i, other_f);
382 logger().trace("fe[{},{}] = {}", f, i, split_edge_eid);
383 }
384 }
385
386 // replace the input edge iwth the new edge for this triangle
387 if (fe[i] == m_operating_edge_id) {
388 logger().trace("fe[{},{}] = {}", f, i, se);
389 fe[i] = se;
390 }
391
392 // if i find the other vertex then i set it to be the new vertex
393 if (fv[i] == other_v) {
394 if (m_mesh.is_free()) {
395 fv[i] = m_free_split_v[j];
396 } else {
397 fv[i] = split_new_vid;
398 }
399 }
400 }
401 logger().trace("ef[{}] = {}", ear.eid, f);
402 logger().trace("ef[{}] = {}", se, f);
403 // assign each edge one face
404 ef_accessor.index_access().scalar_attribute(ear.eid) = f;
405 ef_accessor.index_access().scalar_attribute(se) = f;
406 // assign each vertex one face
407 logger().trace("vf[{}] = {}", m_spine_vids[j], f);
408 vf_accessor.index_access().scalar_attribute(m_spine_vids[j]) = f;
409 }
410
411 vf_accessor.index_access().scalar_attribute(v_opp) = new_fids[0];
412
413 if (m_mesh.is_free()) {
414 for (size_t j = 0; j < 2; ++j) {
415 ef_accessor.index_access().scalar_attribute(m_free_split_e[j]) = new_fids[j];
416 vf_accessor.index_access().scalar_attribute(m_free_split_v[j]) = new_fids[j];
417 }
418
419 const int64_t f = face_data.split_f[1]; // new face to insert
420 auto fv = fv_accessor.index_access().vector_attribute(f);
421 for (int j = 0; j < 3; ++j) {
422 if (fv(j) == face_data.opposite_vid) {
423 logger().trace("fv[{},{}] = {}", f, j, split_new_vid);
424 fv(j) = split_new_vid;
425
426 logger().trace("vf[{}] = {}", split_new_vid, new_fids[1]);
427 vf_accessor.index_access().scalar_attribute(split_new_vid) = new_fids[1];
428 }
429 }
430
431 } else {
432 const int64_t& split_edge_eid = face_data.new_edge_id;
433 logger().trace("ef[{}] = {}", split_edge_eid, new_fids[0]);
434 logger().trace("vf[{}] = {}", split_new_vid, new_fids[0]);
435 ef_accessor.index_access().scalar_attribute(split_edge_eid) = new_fids[0];
436 vf_accessor.index_access().scalar_attribute(split_new_vid) = new_fids[0];
437 }
438
439 // face neighbors on the other side of the spine are updated separately
440
441 return;
442}
443
445{
446 set_split();
447 // need to write:
448 // * global_ids_to_potential_tuples
449 // * m_incident_face_datas
450 // * simplex_ids_to_delete
451 simplex_ids_to_delete = get_split_simplices_to_delete(m_operating_tuple, m_mesh);
452
453 std::vector<Tuple> adjacent_facets = wmtk::simplex::top_dimension_cofaces_tuples(
454 m_mesh,
455 simplex::Simplex::edge(m_mesh, m_operating_tuple));
456
457 assert(m_operating_tuple == adjacent_facets[0]);
458
459 assert(m_incident_face_datas.empty());
460
461 std::transform(
462 adjacent_facets.begin(),
463 adjacent_facets.end(),
464 std::back_inserter(m_incident_face_datas),
465 [&](const Tuple& t) { return get_incident_face_data(t); });
466
467 assert(m_incident_face_datas[0].fid == m_mesh.id_face(m_operating_tuple));
468 assert(m_incident_face_datas[0].local_operating_tuple == m_operating_tuple);
469
470 std::vector<std::vector<Tuple>> bsc(2);
471 if (m_mesh.has_child_mesh_in_dimension(0)) {
472 auto& this_bsc = bsc[0];
473 this_bsc.reserve(m_incident_face_datas.size() + 2);
474
475 this_bsc.emplace_back(m_operating_tuple);
476 this_bsc.emplace_back(m_mesh.switch_vertex(m_operating_tuple));
477 for (const auto& data : m_incident_face_datas) {
478 this_bsc.emplace_back(m_mesh.switch_tuples(
479 data.local_operating_tuple,
480 {PrimitiveType::Edge, PrimitiveType::Vertex}));
481 }
482 }
483 if (m_mesh.has_child_mesh_in_dimension(1)) {
484 auto& this_bsc = bsc[1];
485 /*
486 this_bsc.reserve(3 * m_incident_face_datas.size());
487 for(const auto& facet: m_incident_face_datas) {
488 auto f = wmtk::simplex::faces(m_mesh, f, false);
489 std::copy(f.begin(),f.end(), std::back_inserter(this_bsc));
490 }
491 std::sort(this_bsc.begin(),this_bsc.end());
492 this_bsc.erase(std::unique(this_bsc.begin(),this_bsc.end()),this_bsc.end());
493 }
494 */
495 }
496
497
498 const simplex::SimplexCollection edge_closed_star =
499 simplex::closed_star(m_mesh, simplex::Simplex::edge(m_mesh, m_operating_tuple));
500
501
502 // update hash on all faces in the two-ring neighborhood
503 simplex::SimplexCollection hash_update_region(m_mesh);
504 for (const simplex::Simplex& v : edge_closed_star.simplex_vector(PrimitiveType::Vertex)) {
505 const simplex::SimplexCollection v_closed_star = simplex::top_dimension_cofaces(m_mesh, v);
506 hash_update_region.add(v_closed_star);
507 }
508 hash_update_region.sort_and_clean();
509
510 global_ids_to_potential_tuples.resize(3);
511 simplex::SimplexCollection faces(m_mesh);
512
513 for (const simplex::Simplex& f : hash_update_region.simplex_vector(PrimitiveType::Triangle)) {
514 faces.add(wmtk::simplex::faces(m_mesh, f, false));
515 faces.add(f);
516 }
517
518 faces.sort_and_clean();
519 for (const auto& s : faces) {
520 const int64_t index = static_cast<int64_t>(s.primitive_type());
521 if (!m_mesh.has_child_mesh_in_dimension(index)) continue;
522 global_ids_to_potential_tuples.at(index).emplace_back(
523 m_mesh.id(s),
525 }
526
527 create_spine_simplices();
528 fill_split_facet_data();
529}
530
532{
533 {
534 const size_t facet_size = m_incident_face_datas.size();
535 std::vector<int64_t> new_facet_ids =
537 assert(new_facet_ids.size() == 2 * facet_size);
538 for (size_t j = 0; j < facet_size; ++j) {
539 std::array<int64_t, 2> arr;
540 std::copy(
541 new_facet_ids.begin() + 2 * j,
542 new_facet_ids.begin() + 2 * (j + 1),
543 arr.begin());
544 // const auto& data =
545 split_facet_data().add_facet(m_mesh, m_operating_tuple, arr);
546 m_incident_face_datas[j].split_f = arr;
547 }
548 }
549}
551{
552 split_edge_precompute();
553
554 assert(m_incident_face_datas.size() <= 2);
555
556
557 for (IncidentFaceData& face_data : m_incident_face_datas) {
558 replace_incident_face(face_data);
559 }
560 if (m_incident_face_datas.size() > 1) {
561 connect_faces_across_spine();
562 }
563
564
565 // ---------v2--------
566 // | /|\ |
567 // | ef0 / | \ ef1 |
568 // | / | \ |
569 // | / oe \ |
570 // | ee0 | ee1 |
571 // | / | \ |
572 // | / f0 | f1 \ |
573 // | / | \ |
574 // v0--se0-v_new-se1--v1
575
576 // return Tuple new_fid, new_vid that points
577 const int64_t new_tuple_fid = m_incident_face_datas[0].split_f[1];
578 if (m_mesh.is_free()) {
579 m_output_tuple =
580 m_mesh.tuple_from_global_ids(new_tuple_fid, split_spine_eids[1], m_free_split_v[1]);
581 assert(m_mesh.id_vertex(m_output_tuple) == m_free_split_v[1]);
582 } else {
583 m_output_tuple =
584 m_mesh.tuple_from_global_ids(new_tuple_fid, split_spine_eids[1], split_new_vid);
585 assert(m_mesh.id_vertex(m_output_tuple) == split_new_vid);
586 }
587 assert(m_mesh.id_face(m_output_tuple) == new_tuple_fid);
588 assert(m_mesh.is_valid(m_output_tuple));
589
590 delete_simplices();
591}
592
594{
595 if (m_mesh.is_free()) {
596 // create new vertex (center)
597 std::vector<int64_t> new_vids = this->request_simplex_indices(PrimitiveType::Vertex, 3);
598 assert(new_vids.size() == 3);
599
600 std::copy(new_vids.begin() + 1, new_vids.end(), m_free_split_v.begin());
601 split_new_vid = new_vids[0];
602
603 // create new edges (spine)
604 std::vector<int64_t> new_eids = this->request_simplex_indices(PrimitiveType::Edge, 4);
605 assert(new_eids.size() == 4);
606
607 auto midpoint = new_eids.begin() + 2;
608 std::copy(new_eids.begin(), midpoint, split_spine_eids.begin());
609 std::copy(midpoint, new_eids.end(), m_free_split_e.begin());
610
611 } else {
612 // create new vertex (center)
613 std::vector<int64_t> new_vids = this->request_simplex_indices(PrimitiveType::Vertex, 1);
614 assert(new_vids.size() == 1);
615 split_new_vid = new_vids[0];
616 logger().trace("new split vid {}", split_new_vid);
617
618 // create new edges (spine)
619 std::vector<int64_t> new_eids = this->request_simplex_indices(PrimitiveType::Edge, 2);
620 assert(new_eids.size() == 2);
621
622 std::copy(new_eids.begin(), new_eids.end(), split_spine_eids.begin());
623 logger().trace("new split eids {}", fmt::join(split_spine_eids, ","));
624 }
625}
626
628{
629 set_collapse();
630 is_collapse = true;
631
632 const simplex::Simplex edge_operating(m_mesh, PrimitiveType::Edge, m_operating_tuple);
633
634 // get all faces incident to the edge
635 for (const Tuple& f : simplex::top_dimension_cofaces_iterable(m_mesh, edge_operating)) {
636 m_incident_face_datas.emplace_back(get_incident_face_data(f));
637 }
638
639 assert(m_incident_face_datas.size() <= 2);
640 if (m_incident_face_datas[0].fid != m_mesh.id_face(m_operating_tuple)) {
641 assert(m_incident_face_datas.size() == 2);
642 std::swap(m_incident_face_datas[0], m_incident_face_datas[1]);
643 }
644
645 if (m_mesh.has_child_mesh()) {
646 global_ids_to_potential_tuples.resize(3);
647
648 simplex::IdSimplexCollection faces(m_mesh);
649 {
650 const simplex::Simplex v0(m_mesh, PrimitiveType::Vertex, m_operating_tuple);
651 const simplex::Simplex v1(
652 m_mesh,
654 m_mesh.switch_vertex(m_operating_tuple));
655 std::array<simplex::internal::VisitedArray<wmtk::simplex::IdSimplex>, 3> visited;
656
657 for (const simplex::IdSimplex& s : simplex::closed_star_iterable(m_mesh, v0)) {
658 visited[get_primitive_type_id(s.primitive_type())].is_visited(s);
659 }
660 for (const simplex::IdSimplex& s : simplex::closed_star_iterable(m_mesh, v1)) {
661 visited[get_primitive_type_id(s.primitive_type())].is_visited(s);
662 }
663 faces.reserve(
664 visited[0].visited_array().size() + visited[1].visited_array().size() +
665 visited[2].visited_array().size());
666 for (size_t j = 0; j < visited.size(); ++j) {
667 if (!m_mesh.has_child_mesh_in_dimension(j)) {
668 continue;
669 }
670 const auto& arr = visited[j];
671 for (size_t i = 0; i < arr.visited_array().size(); ++i) {
672 faces.add(arr.visited_array()[i]);
673 }
674 }
675 }
676
677 for (const simplex::IdSimplex& s : faces) {
678 const int64_t index = static_cast<int64_t>(s.primitive_type());
679
680 global_ids_to_potential_tuples.at(index).emplace_back(
681 m_mesh.id(s),
682 wmtk::simplex::top_dimension_cofaces_tuples(m_mesh, m_mesh.get_simplex(s)));
683 }
684 }
685
686 simplex_ids_to_delete = get_collapse_simplices_to_delete(m_operating_tuple, m_mesh);
687}
688
689
691{
692 collapse_edge_precompute();
693
694 if (!m_mesh.is_free()) {
695 // must collect star before changing connectivity
696 const simplex::Simplex v0_simplex(m_mesh, PrimitiveType::Vertex, m_operating_tuple);
698 for (const Tuple& t : simplex::top_dimension_cofaces_iterable(m_mesh, v0_simplex)) {
699 v0_neighbors.emplace_back(m_mesh.id(t, PrimitiveType::Triangle));
700 }
701
702
703 connect_ears();
704
705 const int64_t& v0 = m_spine_vids[0];
706 const int64_t& v1 = m_spine_vids[1];
707
708 // replace v0 by v1 in incident faces
709 for (const int64_t fid : v0_neighbors) {
710 bool is_fid_deleted = false;
711 for (int64_t i = 0; i < m_incident_face_datas.size(); ++i) {
712 if (m_incident_face_datas[i].fid == fid) {
713 is_fid_deleted = true;
714 break;
715 }
716 }
717 if (is_fid_deleted) {
718 continue;
719 }
720 auto fv = fv_accessor.index_access().vector_attribute(fid);
721 for (int64_t i = 0; i < 3; ++i) {
722 if (fv[i] == v0) {
723 fv[i] = v1;
724 break;
725 }
726 }
727 }
728
729 const int64_t& ret_eid = m_incident_face_datas[0].ears[1].eid;
730 const int64_t& ret_vid = m_spine_vids[1];
731 const int64_t& ef0 = m_incident_face_datas[0].ears[0].fid;
732 const int64_t& ef1 = m_incident_face_datas[0].ears[1].fid;
733
734 const int64_t new_tuple_fid = (ef0 > -1) ? ef0 : ef1;
735
736
737 m_output_tuple = m_mesh.edge_tuple_from_id(ret_eid);
738
739 // auto faces =
740 // simplex::top_dimension_cofaces_tuples(m_mesh,
741 // simplex::Simplex::edge(m_output_tuple));
742
743 // assert(faces.size() == m_incident_face_datas.size());
744 if (m_mesh.id_vertex(m_output_tuple) != ret_vid) {
745 m_output_tuple = m_mesh.switch_vertex(m_output_tuple);
746 }
747 assert(m_mesh.id_vertex(m_output_tuple) == ret_vid);
748 if (m_mesh.id_face(m_output_tuple) != new_tuple_fid) {
749 m_output_tuple = m_mesh.switch_face(m_output_tuple);
750 }
751 assert(m_mesh.id_face(m_output_tuple) == new_tuple_fid);
752 assert(m_mesh.is_valid(m_output_tuple));
753 }
754
755 delete_simplices();
756
757
758 // return a ccw tuple from left ear if it exists, otherwise return a ccw tuple from right ear
759 // return m_mesh.tuple_from_id(PrimitiveType::Vertex, v1);
760}
761
763 const PrimitiveType type,
764 int64_t count)
765{
766 return EdgeOperationData::request_simplex_indices(m_mesh, type, count);
767}
768
769} // namespace wmtk
Tuple switch_tuples(const Tuple &tuple, const ContainerType &op_sequence) const
Performs a sequence of switch_tuple operations in the order specified in op_sequence.
Definition MeshCRTP.hpp:136
bool is_free() const
Definition Mesh.hpp:973
std::vector< int64_t > request_simplex_indices(PrimitiveType type, int64_t count)
const attribute::FlagAccessor< Mesh > get_flag_accessor(PrimitiveType type) const
Definition Mesh.cpp:159
static const std::array< std::vector< int64_t >, 3 > get_split_simplices_to_delete(const Tuple &tuple, const TriMesh &m)
gather all simplices that are deleted in a split
static const std::array< std::vector< int64_t >, 3 > get_collapse_simplices_to_delete(const Tuple &tuple, const TriMesh &m)
gather all simplices that are deleted in a collapse
TriMeshOperationExecutor(TriMesh &m, const Tuple &operating_tuple)
Tuple next_edge(const Tuple &tuple) const
jump to the next edge
std::vector< int64_t > request_simplex_indices(const PrimitiveType type, int64_t count)
Tuple prev_edge(const Tuple &tuple) const
jump to the previous edge
void replace_incident_face(IncidentFaceData &face_data)
void update_ids_in_ear(const EarData &ear, const int64_t new_fid, const int64_t old_fid)
handling the topology glueing of ear to non-ear face, transfering data from ear-oldface to ear-newfac...
Tuple switch_edge(const Tuple &tuple) const
Definition TriMesh.hpp:117
int64_t id(const Tuple &tuple, PrimitiveType type) const
Definition TriMesh.hpp:125
The Tuple is the basic navigation tool in our mesh data structure.
Definition Tuple.hpp:19
void reserve(const size_t new_cap)
void add(const Simplex &simplex)
Add simplex to the collection.
const std::vector< Simplex > & simplex_vector() const
Return const reference to the simplex vector.
void sort_and_clean()
Sort simplex vector and remove duplicates.
static Simplex edge(const Mesh &m, const Tuple &t)
Definition Simplex.hpp:61
static Simplex vertex(const Mesh &m, const Tuple &t)
Definition Simplex.hpp:56
static bool equal(const Mesh &m, const Simplex &s0, const Simplex &s1)
void emplace_back(const T &val)
void top_dimension_cofaces_tuples(const PointMesh &mesh, const Simplex &simplex, SimplexCollection &collection)
TopDimensionCofacesIterable top_dimension_cofaces_iterable(const Mesh &mesh, const Simplex &simplex)
SimplexCollection open_star(const Mesh &mesh, const Simplex &simplex, const bool sort_and_clean)
Definition open_star.cpp:12
SimplexCollection closed_star(const Mesh &mesh, const Simplex &simplex, const bool sort_and_clean)
The closed star contains the input simplex, all its top dimension cofaces, and their faces.
void top_dimension_cofaces(const Simplex &simplex, SimplexCollection &simplex_collection, const bool sort_and_clean)
Get all top dimension cofaces of the given simplex.
ClosedStarIterable closed_star_iterable(const Mesh &mesh, const Simplex &simplex)
SimplexCollection faces(const Mesh &mesh, const Simplex &simplex, const bool sort_and_clean)
Returns all faces of a simplex.
Definition faces.cpp:10
constexpr PrimitiveType PE
constexpr int8_t get_primitive_type_id(PrimitiveType t)
Get a unique integer id corresponding to each primitive type.
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:58
constexpr PrimitiveType PV
An ear is a face that is adjacent to a face that is incident to the edge on which the operation is pe...
Data on the incident face relevant for performing operations.