Wildmeshing Toolkit
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 
23 #include <wmtk/simplex/faces.hpp>
28 
30 
31 namespace wmtk {
32 
33 constexpr static PrimitiveType PV = PrimitiveType::Vertex;
34 constexpr 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.m_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().scalar_attribute(id) = 0;
133  }
134  }
135 }
136 
137 
138 const 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 
152 const 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);
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 
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 =
536  this->request_simplex_indices(PrimitiveType::Triangle, 2 * facet_size);
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 
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:135
bool is_free() const
Definition: Mesh.hpp:987
std::vector< int64_t > request_simplex_indices(PrimitiveType type, int64_t count)
const attribute::Accessor< char > get_flag_accessor(PrimitiveType type) const
Definition: Mesh.cpp:158
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
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.
Definition: closed_star.cpp:13
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
Definition: Accessor.hpp:6
constexpr PrimitiveType PV
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 PE
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.