1#[cfg(test)]
2mod tests;
3
4use std::ops::RangeInclusive;
5
6use hashbrown::HashSet;
7use itertools::Itertools;
8use tracing::{error, instrument};
9
10use crate::{
11 AddEdge, FaceId, HalfedgeId, MeshGraph, Vertex, VertexId, error_none,
12 ops::{add::AddFace, collapse::CollapseEdge, edit::MergeVertices},
13 utils::unwrap_or_return,
14};
15
16#[derive(Default)]
17pub struct MergeVerticesOneRing {
18 pub removed_vertices: Vec<VertexId>,
19 pub removed_halfedges: Vec<HalfedgeId>,
20 pub removed_faces: Vec<FaceId>,
21
22 pub added_vertices: Vec<VertexId>,
23 pub added_halfedges: Vec<HalfedgeId>,
24 pub added_faces: Vec<FaceId>,
25}
26
27impl MeshGraph {
28 #[instrument(skip(self, marked_halfedges, marked_vertices))]
35 pub fn merge_vertices_one_rings(
36 &mut self,
37 vertex_id1: VertexId,
38 vertex_id2: VertexId,
39 flip_threshold_sqr: f32,
40 marked_halfedges: &mut HashSet<HalfedgeId>,
41 marked_vertices: &mut HashSet<VertexId>,
42 ) -> MergeVerticesOneRing {
43 #[cfg(feature = "instrumentation")]
44 crate::set_current_op("merge_one_ring");
45 #[cfg(feature = "instrumentation")]
46 crate::probe_chain_begin(self);
47 let mut result = MergeVerticesOneRing::default();
48
49 let vertex1 = *unwrap_or_return!(self.vertices.get(vertex_id1), "Vertex not found", result);
50 let vertex2 = *unwrap_or_return!(self.vertices.get(vertex_id2), "Vertex not found", result);
51
52 if vertex_id1 == vertex_id2 {
53 error!("Cannot merge a vertex with itself");
54 return result;
55 }
56
57 let one_ring_he_ids1 = vertex1.one_ring(self).collect_vec();
58 let mut one_ring_he_ids2 = vertex2
59 .one_ring(self)
60 .filter_map(|he_id| {
63 let he = self.halfedges.get(he_id)?;
67 he.twin.or_else(error_none!("Twin not found"))
68 })
69 .collect_vec();
70 one_ring_he_ids2.reverse();
71
72 if one_ring_he_ids1.len() < 3 || one_ring_he_ids2.len() < 3 {
73 error!(
74 "One rings are too small. One ring of {vertex_id1:?} = {}; one ring of {vertex_id2:?} = {}",
75 one_ring_he_ids1.len(),
76 one_ring_he_ids2.len()
77 );
78 return result;
79 }
80
81 let mut one_ring_v_ids1 = one_ring_he_ids1
83 .iter()
84 .filter_map(|he_id| {
85 if self.halfedges.contains_key(*he_id) {
89 Some(self.halfedges[*he_id].end_vertex)
90 } else {
91 None
92 }
93 })
94 .collect_vec();
95 one_ring_v_ids1.rotate_right(1);
96 let mut one_ring_v_ids2 = one_ring_he_ids2
97 .iter()
98 .filter_map(|he_id| {
99 if self.halfedges.contains_key(*he_id) {
100 Some(self.halfedges[*he_id].end_vertex)
101 } else {
102 None
103 }
104 })
105 .collect_vec();
106 one_ring_v_ids2.rotate_right(1);
107
108 if one_ring_v_ids1.len() < 3 || one_ring_v_ids2.len() < 3 {
109 error!("One rings are too small");
110 return result;
111 }
112
113 let one_ring_he_set1 = HashSet::<HalfedgeId>::from_iter(one_ring_he_ids1.iter().copied());
114 let one_ring_he_set2 = HashSet::<HalfedgeId>::from_iter(one_ring_he_ids2.iter().copied());
115 let shared_he_ids = HashSet::<HalfedgeId>::from_iter(
116 one_ring_he_set1.intersection(&one_ring_he_set2).copied(),
117 );
118
119 let one_ring_v_set1 = HashSet::<VertexId>::from_iter(one_ring_v_ids1.iter().copied());
120 let one_ring_v_set2 = HashSet::<VertexId>::from_iter(one_ring_v_ids2.iter().copied());
121 let shared_v_ids =
122 HashSet::<VertexId>::from_iter(one_ring_v_set1.intersection(&one_ring_v_set2).copied());
123
124 tracing::debug!("ring1 (v_ids): {one_ring_v_ids1:?}");
125 tracing::debug!("ring2 (v_ids): {one_ring_v_ids2:?}");
126 tracing::debug!("shared_v_ids: {shared_v_ids:?}");
127
128 if self.check_and_flip_single_shared_he(&shared_he_ids, flip_threshold_sqr, &mut result) {
129 return self.finish_merge(result);
130 }
131
132 self.remove_neighbor_faces(&vertex1, &vertex2, &mut result);
133
134 #[cfg(feature = "rerun")]
135 self.log_rerun();
136
137 let (already_connected_face_ids, connected_v_ids, connected_he_ids) = match self
138 .find_already_connected_pairings(&one_ring_v_ids1, &one_ring_v_ids2, &shared_v_ids)
139 {
140 Some(pairings) => pairings,
141 None => {
142 tracing::error!("Error in find_already_connected_pairings");
143 return self.finish_merge(result);
144 }
145 };
146
147 #[cfg(feature = "rerun")]
148 {
149 self.log_faces_rerun("already_connected", &already_connected_face_ids);
150 self.log_hes_rerun("already_connected", &connected_he_ids);
151 }
152
153 let range_pairs_to_connect = self.compute_range_pairs_to_connect(
154 &one_ring_v_ids1,
155 &one_ring_v_ids2,
156 &one_ring_he_ids1,
157 &one_ring_he_ids2,
158 &shared_v_ids,
159 &shared_he_ids,
160 connected_v_ids,
161 connected_he_ids,
162 );
163
164 if range_pairs_to_connect.is_empty() {
165 error!("No range pairs to connect");
166 return self.finish_merge(result);
167 }
168
169 tracing::debug!("Range pairs to connect: {range_pairs_to_connect:#?}");
170
171 let planned_faces =
172 self.plan_new_faces(&range_pairs_to_connect, &one_ring_v_ids1, &one_ring_v_ids2);
173 tracing::debug!("planned faces: {planned_faces:#?}");
174
175 for face_id in already_connected_face_ids {
176 let (v_ids, he_ids) = self.remove_face(face_id);
177 result.removed_faces.push(face_id);
178 result.removed_halfedges.extend(he_ids);
179 result.removed_vertices.extend(v_ids);
180 }
181
182 self.add_planned_faces(
183 planned_faces,
184 &one_ring_v_set1,
185 &one_ring_v_set2,
186 marked_halfedges,
187 &mut result,
188 );
189
190 #[cfg(feature = "rerun")]
191 self.log_rerun();
192
193 self.cleanup_bookkeeping(
194 &one_ring_v_ids1,
195 &one_ring_v_ids2,
196 marked_vertices,
197 marked_halfedges,
198 &mut result,
199 );
200
201 self.merge_remaining_unconnected(
202 one_ring_v_ids1.clone(),
203 one_ring_v_ids2.clone(),
204 &mut result,
205 );
206
207 self.smooth_vertices(
208 one_ring_v_ids1
209 .iter()
210 .chain(&one_ring_v_ids2)
211 .chain(&result.added_vertices)
212 .copied(),
213 );
214
215 self.finish_merge(result)
216 }
217
218 #[cfg(feature = "instrumentation")]
224 fn finish_merge(&self, result: MergeVerticesOneRing) -> MergeVerticesOneRing {
225 if self.probe_chain_integrity("merge_vertices_one_rings") {
226 crate::state_history_push(self, "merge_vertices_one_rings");
227 }
228 result
229 }
230
231 #[cfg(not(feature = "instrumentation"))]
232 fn finish_merge(&self, result: MergeVerticesOneRing) -> MergeVerticesOneRing {
233 result
234 }
235
236 fn merge_remaining_unconnected(
237 &mut self,
238 mut one_ring_v_ids1: Vec<VertexId>,
239 mut one_ring_v_ids2: Vec<VertexId>,
240 result: &mut MergeVerticesOneRing,
241 ) {
242 while let Some(v_id) = one_ring_v_ids1.pop() {
243 let Some(vert) = self.vertices.get(v_id) else {
244 continue;
245 };
246
247 let mut vertices = vec![];
248
249 for he_id in vert.boundary_halfedgdes(self) {
250 let Some(he) = self.halfedges.get(he_id) else {
251 error!("Halfedge not found: {he_id:?}");
252 continue;
253 };
254
255 vertices.push(he.end_vertex);
256 }
257
258 if !vertices.is_empty() {
259 one_ring_v_ids1.retain(|v_id| !vertices.contains(v_id));
260 one_ring_v_ids2.retain(|v_id| !vertices.contains(v_id));
261
262 let MergeVertices {
263 removed_vertices,
264 removed_halfedges,
265 removed_faces,
266 } = self.merge_vertices(vertices);
267
268 result.removed_vertices.extend(removed_vertices);
269 result.removed_halfedges.extend(removed_halfedges);
270 result.removed_faces.extend(removed_faces);
271 }
272 }
273 }
274
275 fn find_already_connected_pairings(
276 &mut self,
277 one_ring_v_ids1: &[VertexId],
278 one_ring_v_ids2: &[VertexId],
279 shared_v_ids: &HashSet<VertexId>,
280 ) -> Option<(Vec<FaceId>, HashSet<VertexId>, HashSet<HalfedgeId>)> {
281 let mut connected_v_ids = HashSet::new();
282 let mut connected_he_ids = HashSet::new();
283 let mut already_connected_face_ids = vec![];
284
285 let mut strip_found = false;
292
293 for ((idx1, &v_id1), (idx2, &v_id2)) in one_ring_v_ids1
294 .iter()
295 .enumerate()
296 .cartesian_product(one_ring_v_ids2.iter().enumerate())
297 {
298 if shared_v_ids.contains(&v_id1) || shared_v_ids.contains(&v_id2) {
299 continue;
300 }
301
302 if v_id1 == v_id2 {
303 connected_v_ids.insert(v_id1);
304 continue;
305 }
306
307 if connected_v_ids.contains(&v_id1) && connected_v_ids.contains(&v_id2) {
308 continue;
309 }
310
311 if strip_found {
316 continue;
317 }
318
319 if let Some(he_id) = self.halfedge_from_to(v_id1, v_id2) {
320 let pairing = match self.find_triangle_fan(
321 he_id,
322 idx1,
323 idx2,
324 one_ring_v_ids1,
325 one_ring_v_ids2,
326 &mut connected_he_ids,
327 &mut already_connected_face_ids,
328 ) {
329 TriangleFan::Spanning(pairing) => pairing,
330 TriangleFan::NotSpanning => continue,
333 TriangleFan::Failed => return None,
334 };
335
336 #[cfg(feature = "rerun")]
337 pairing.log_rerun(
338 "already_connected_init",
339 [one_ring_v_ids1, one_ring_v_ids2],
340 self,
341 );
342
343 let mut connected_pairings = self.find_connected_triangle_fans(
344 one_ring_v_ids1,
345 one_ring_v_ids2,
346 &pairing,
347 -1,
348 &mut connected_he_ids,
349 &mut already_connected_face_ids,
350 );
351
352 connected_pairings.push(pairing.clone());
353
354 connected_pairings.extend(self.find_connected_triangle_fans(
355 one_ring_v_ids1,
356 one_ring_v_ids2,
357 &pairing,
358 1,
359 &mut connected_he_ids,
360 &mut already_connected_face_ids,
361 ));
362
363 for pairing in &connected_pairings {
364 for v_id in pairing.all_vertex_ids([one_ring_v_ids1, one_ring_v_ids2]) {
365 connected_v_ids.insert(v_id);
366 }
367 }
368
369 strip_found = true;
370 }
371 }
372
373 Some((
374 already_connected_face_ids,
375 connected_v_ids,
376 connected_he_ids,
377 ))
378 }
379
380 fn find_connected_triangle_fans(
381 &self,
382 one_ring_v_ids1: &[VertexId],
383 one_ring_v_ids2: &[VertexId],
384 pairing: &Pairing,
385 idx_step: i32,
386 connected_he_ids: &mut HashSet<HalfedgeId>,
387 connected_face_ids: &mut Vec<FaceId>,
388 ) -> Vec<Pairing> {
389 let (single_v_ids, other_v_ids) = if pairing.single_range_idx == 0 {
390 (one_ring_v_ids1, one_ring_v_ids2)
391 } else {
392 (one_ring_v_ids2, one_ring_v_ids1)
393 };
394
395 let next_single_idx = ((pairing.single_idx_in_range + single_v_ids.len()) as i32 + idx_step)
396 as usize
397 % single_v_ids.len();
398 let next_v_id = single_v_ids[next_single_idx];
399
400 let mut other_idx = if idx_step < 0 {
401 *pairing.other_range.start()
402 } else {
403 *pairing.other_range.end()
404 };
405 other_idx %= other_v_ids.len();
406
407 let current_single_v_id = single_v_ids[pairing.single_idx_in_range];
408
409 let mut pairings = vec![];
410
411 if self
412 .face_with_vertices(next_v_id, current_single_v_id, other_v_ids[other_idx])
413 .is_some()
414 {
415 let mut current_pairing = Pairing::new_triangle(
417 1 - pairing.single_range_idx,
418 other_idx,
419 next_single_idx,
420 pairing.single_idx_in_range,
421 single_v_ids.len(),
422 );
423
424 self.extend_triangle_pairing_fan(
425 one_ring_v_ids1,
426 one_ring_v_ids2,
427 &mut current_pairing,
428 connected_he_ids,
429 connected_face_ids,
430 );
431
432 #[cfg(feature = "rerun")]
433 current_pairing.log_rerun(
434 format!("extended/step_{}", idx_step),
435 [one_ring_v_ids1, one_ring_v_ids2],
436 self,
437 );
438
439 let next_pairings = self.find_connected_triangle_fans(
440 one_ring_v_ids1,
441 one_ring_v_ids2,
442 ¤t_pairing,
443 idx_step,
444 connected_he_ids,
445 connected_face_ids,
446 );
447
448 pairings.push(current_pairing);
449 pairings.extend(next_pairings);
450 }
451
452 pairings
453 }
454
455 #[allow(clippy::too_many_arguments)]
459 fn find_triangle_fan(
460 &self,
461 he_id: HalfedgeId,
462 idx1: usize,
463 idx2: usize,
464 one_ring_v_ids1: &[VertexId],
465 one_ring_v_ids2: &[VertexId],
466 connected_he_ids: &mut HashSet<HalfedgeId>,
467 connected_face_ids: &mut Vec<FaceId>,
468 ) -> TriangleFan {
469 let he = unwrap_or_return!(
470 self.halfedges.get(he_id),
471 "Halfedge not found",
472 TriangleFan::Failed
473 );
474
475 let mut current_pairing = Pairing {
476 single_range_idx: 0,
477 single_idx_in_range: idx1,
478 other_range: idx2..=idx2,
479 };
480
481 let Some(opposite_v_id) = he.opposite_vertex(self) else {
483 return TriangleFan::Spanning(current_pairing);
486 };
487
488 if !self.create_triangle_pairing(
489 one_ring_v_ids1,
490 one_ring_v_ids2,
491 idx1,
492 idx2,
493 opposite_v_id,
494 &mut current_pairing,
495 ) {
496 let twin_id = unwrap_or_return!(he.twin, "Twin not found", TriangleFan::Failed);
497 let twin = unwrap_or_return!(
498 self.halfedges.get(twin_id),
499 "Twin not found",
500 TriangleFan::Failed
501 );
502
503 let Some(opposite_v_id) = twin.opposite_vertex(self) else {
505 return TriangleFan::Spanning(current_pairing);
506 };
507
508 if !self.create_triangle_pairing(
509 one_ring_v_ids1,
510 one_ring_v_ids2,
511 idx1,
512 idx2,
513 opposite_v_id,
514 &mut current_pairing,
515 ) {
516 return TriangleFan::NotSpanning;
517 }
518 }
519
520 self.extend_triangle_pairing_fan(
521 one_ring_v_ids1,
522 one_ring_v_ids2,
523 &mut current_pairing,
524 connected_he_ids,
525 connected_face_ids,
526 );
527
528 TriangleFan::Spanning(current_pairing)
529 }
530
531 fn add_face_to_connected_he_ids(
532 &self,
533 face_id: FaceId,
534 connected_he_ids: &mut HashSet<HalfedgeId>,
535 ) {
536 let face = unwrap_or_return!(
537 self.faces.get(face_id),
538 "failed to get start face for pairing fan"
539 );
540 connected_he_ids.extend(
541 face.halfedges(self)
542 .filter_map(|he_id| {
543 let he = self
544 .halfedges
545 .get(he_id)
546 .or_else(error_none!("Halfedge not found"))?;
547 Some([
548 he_id,
549 he.twin.or_else(error_none!("Twin halfedge not found"))?,
550 ])
551 })
552 .flatten(),
553 );
554 }
555
556 fn extend_triangle_pairing_fan(
557 &self,
558 one_ring_v_ids1: &[VertexId],
559 one_ring_v_ids2: &[VertexId],
560 current_pairing: &mut Pairing,
561 connected_he_ids: &mut HashSet<HalfedgeId>,
562 connected_face_ids: &mut Vec<FaceId>,
563 ) {
564 let (single_ids, other_ids) = if current_pairing.single_range_idx == 0 {
565 (one_ring_v_ids1, one_ring_v_ids2)
566 } else {
567 (one_ring_v_ids2, one_ring_v_ids1)
568 };
569
570 let other_len = other_ids.len();
571 let single_v_id = single_ids[current_pairing.single_idx_in_range % single_ids.len()];
572
573 let mut range_start = *current_pairing.other_range.start();
575
576 let start_face_id = unwrap_or_return!(
577 self.face_with_vertices(
578 single_v_id,
579 other_ids[range_start % other_len],
580 other_ids[*current_pairing.other_range.end() % other_len],
581 ),
582 "failed to find start face for pairing fan"
583 );
584 self.add_face_to_connected_he_ids(start_face_id, connected_he_ids);
585 connected_face_ids.push(start_face_id);
586
587 let mut steps = 0;
590 loop {
591 let prev_idx = (range_start + other_len - 1) % other_len;
593 let prev_v_id = other_ids[prev_idx];
594
595 let boundary_v_id = other_ids[range_start % other_len];
596 if let Some(face_id) = self.face_with_vertices(single_v_id, prev_v_id, boundary_v_id) {
597 if range_start == 0 {
600 range_start = other_len - 1;
601 } else {
602 range_start -= 1;
603 }
604 current_pairing.other_range = range_start..=*current_pairing.other_range.end();
605
606 self.add_face_to_connected_he_ids(face_id, connected_he_ids);
607 connected_face_ids.push(face_id);
608
609 steps += 1;
610 if steps >= other_len {
611 error!("Pairing fan wrapped around the entire one ring");
612 break;
613 }
614 } else {
615 break;
616 }
617 }
618
619 let mut range_end = *current_pairing.other_range.end();
621 let mut steps = 0;
624 loop {
625 let next_idx = (range_end + 1) % other_len;
626 let next_v_id = other_ids[next_idx];
627
628 let boundary_v_id = other_ids[range_end % other_len];
629 if let Some(face_id) = self.face_with_vertices(single_v_id, boundary_v_id, next_v_id) {
630 range_end += 1;
631 current_pairing.other_range = *current_pairing.other_range.start()..=range_end;
632
633 self.add_face_to_connected_he_ids(face_id, connected_he_ids);
634 connected_face_ids.push(face_id);
635
636 steps += 1;
637 if steps >= other_len {
638 error!("Pairing fan wrapped around the entire one ring");
639 break;
640 }
641 } else {
642 break;
643 }
644 }
645 }
646
647 fn create_triangle_pairing(
648 &self,
649 one_ring_v_ids1: &[VertexId],
650 one_ring_v_ids2: &[VertexId],
651 idx1: usize,
652 idx2: usize,
653 third_v_id: VertexId,
654 current_pairing: &mut Pairing,
655 ) -> bool {
656 let (idx1, idx2) =
657 if let Some(idx) = one_ring_v_ids1.iter().position(|v_id| *v_id == third_v_id) {
658 current_pairing.single_range_idx = 1;
659 current_pairing.single_idx_in_range = idx2;
660
661 (idx, idx1)
662 } else if let Some(idx) = one_ring_v_ids2.iter().position(|v_id| *v_id == third_v_id) {
663 (idx, idx2)
664 } else {
665 return false;
666 };
667
668 let other_len = if current_pairing.single_range_idx == 0 {
669 one_ring_v_ids2.len()
670 } else {
671 one_ring_v_ids1.len()
672 };
673
674 *current_pairing = Pairing::new_triangle(
675 current_pairing.single_range_idx,
676 current_pairing.single_idx_in_range,
677 idx1,
678 idx2,
679 other_len,
680 );
681
682 true
683 }
684
685 fn cleanup_bookkeeping(
686 &mut self,
687 one_ring_v_ids1: &[VertexId],
688 one_ring_v_ids2: &[VertexId],
689 marked_vertices: &mut HashSet<VertexId>,
690 marked_halfedges: &mut HashSet<HalfedgeId>,
691 result: &mut MergeVerticesOneRing,
692 ) {
693 for vertex_id in one_ring_v_ids1.iter().chain(one_ring_v_ids2).copied() {
694 if !self.vertices.contains_key(vertex_id) {
695 continue;
696 }
697
698 let cleanup = self.make_vertex_neighborhood_manifold(vertex_id);
699
700 if !cleanup.added_vertices.is_empty() {
701 marked_vertices.insert(vertex_id);
702 }
703
704 result.added_vertices.extend(cleanup.added_vertices.clone());
705 marked_vertices.extend(cleanup.added_vertices);
706
707 for removed_v_id in cleanup.removed_vertices {
708 if result.added_vertices.contains(&removed_v_id) {
709 result.added_vertices.retain(|&v_id| v_id != removed_v_id);
710 } else {
711 result.removed_vertices.push(removed_v_id);
712 }
713
714 marked_vertices.remove(&removed_v_id);
715 }
716
717 for removed_he_id in cleanup.removed_halfedges {
718 if result.added_halfedges.contains(&removed_he_id) {
719 result
720 .added_halfedges
721 .retain(|&he_id| he_id != removed_he_id);
722 } else {
723 result.removed_halfedges.push(removed_he_id);
724 }
725
726 marked_halfedges.remove(&removed_he_id);
727 }
728
729 for removed_face_id in cleanup.removed_faces {
730 if result.added_faces.contains(&removed_face_id) {
731 result
732 .added_faces
733 .retain(|&face_id| face_id != removed_face_id);
734 } else {
735 result.removed_faces.push(removed_face_id);
736 }
737 }
738 }
739 }
740
741 fn add_planned_faces(
742 &mut self,
743 planned_faces: Vec<PlannedFace>,
744 one_ring_set1: &HashSet<VertexId>,
745 one_ring_set2: &HashSet<VertexId>,
746 marked_halfedges: &mut HashSet<HalfedgeId>,
747 result: &mut MergeVerticesOneRing,
748 ) {
749 let mut prev_he = None;
750
751 for planned_face in planned_faces {
752 let inserted = if let Some(prev_he) = prev_he {
753 planned_face.add_to_mesh_graph_and_he(self, prev_he, result)
754 } else {
755 planned_face.add_to_mesh_graph(self, result)
756 };
757
758 let Some(inserted) = inserted else {
759 prev_he = None;
761 continue;
762 };
763
764 prev_he = inserted.0;
765 let inserted = inserted.1;
766
767 for he_id in inserted.halfedge_ids.iter().copied() {
768 let he = self.halfedges[he_id];
770 let start_v_id =
771 unwrap_or_return!(he.start_vertex(self), "Couldn't find start vertex");
772 let end_v_id = he.end_vertex;
773
774 if one_ring_set1.contains(&start_v_id) && one_ring_set2.contains(&end_v_id)
775 || one_ring_set2.contains(&start_v_id) && one_ring_set1.contains(&end_v_id)
776 {
777 marked_halfedges.insert(he_id);
778 }
779 }
780
781 result.added_halfedges.extend(inserted.halfedge_ids);
782 result.added_faces.push(inserted.face_id);
783 }
784 }
785
786 fn remove_neighbor_faces(
787 &mut self,
788 vertex1: &Vertex,
789 vertex2: &Vertex,
790 result: &mut MergeVerticesOneRing,
791 ) {
792 let face_ids1 = vertex1.faces(self).collect_vec();
793 let face_ids2 = vertex2.faces(self).collect_vec();
794
795 for face_id in face_ids1.into_iter().chain(face_ids2) {
796 let (del_v, del_he) = self.remove_face(face_id);
797
798 result.removed_faces.push(face_id);
799 result.removed_vertices.extend(del_v);
800 result.removed_halfedges.extend(del_he);
801 }
802 }
803
804 fn dismantle_faced_member(&mut self, he_id: HalfedgeId, result: &mut MergeVerticesOneRing) {
812 if let Some(he) = self.halfedges.get(he_id)
813 && let Some(face_id) = he.face
814 && self.faces.contains_key(face_id)
815 {
816 let (del_v, del_he) = self.remove_face(face_id);
817 result.removed_faces.push(face_id);
818 result.removed_halfedges.extend(del_he);
819 result.removed_vertices.extend(del_v);
820 }
821 }
822
823 #[instrument(skip_all)]
824 fn flip_and_collapse_single_shared_edge_if_below_threshold(
825 &mut self,
826 single_shared_he_id: HalfedgeId,
827 flip_threshold_sqr: f32,
828 result: &mut MergeVerticesOneRing,
829 ) -> bool {
830 let he = self.halfedges[single_shared_he_id];
832
833 let twin_id = unwrap_or_return!(he.twin, "Twin not found", false);
834 let twin = unwrap_or_return!(self.halfedges.get(twin_id), "Twin not found", false);
835
836 let other_v_id1 =
837 unwrap_or_return!(he.opposite_vertex(self), "Opposite vertex not found", false);
838 let other_v_id2 = unwrap_or_return!(
839 twin.opposite_vertex(self),
840 "Opposite vertex not found",
841 false
842 );
843
844 let pos1 = *unwrap_or_return!(self.positions.get(other_v_id1), "Position not found", false);
845 let pos2 = *unwrap_or_return!(self.positions.get(other_v_id2), "Position not found", false);
846
847 if pos1.distance_squared(pos2) <= flip_threshold_sqr {
848 tracing::debug!("Flipping edge {single_shared_he_id:?}");
849
850 self.flip_edge(single_shared_he_id);
851
852 let CollapseEdge {
853 removed_vertices,
854 removed_halfedges,
855 removed_faces,
856 added_vertices,
857 } = self.collapse_edge(single_shared_he_id);
858
859 result.added_vertices.extend(added_vertices);
860 result.removed_vertices.extend(removed_vertices);
861 result.removed_halfedges.extend(removed_halfedges);
862 result.removed_faces.extend(removed_faces);
863
864 true
865 } else {
866 false
867 }
868 }
869
870 fn plan_new_faces(
871 &self,
872 range_pairs_to_connect: &[ConnectPair],
873 one_ring_v_ids1: &[VertexId],
874 one_ring_v_ids2: &[VertexId],
875 ) -> Vec<PlannedFace> {
876 let mut planned_faces = Vec::with_capacity(one_ring_v_ids1.len());
877
878 for range_pair_to_connect in range_pairs_to_connect {
879 let start_pairing_index = planned_faces.len();
880
881 let pairings = range_pair_to_connect.compute_pairings();
882
883 tracing::debug!("Pairings: {:#?}", pairings);
884
885 if pairings.is_empty() {
886 continue;
887 }
888
889 let mut prev_single_v_id = None;
890 let mut prev_other_v_id = None;
891
892 if matches!(range_pair_to_connect.start_cap, ConnectPairCap::Open) {
893 let last_pairing = pairings.last().unwrap();
894
895 let (s, o) = last_pairing.last_pair([one_ring_v_ids1, one_ring_v_ids2]);
896
897 prev_single_v_id = Some(s);
898 prev_other_v_id = Some(o);
899 }
900
901 for pairing in pairings {
902 if let Some(prev_single_v_id) = prev_single_v_id
903 && let Some(prev_other_v_id) = prev_other_v_id
904 {
905 let (single_v_id, other_v_id) =
907 pairing.first_pair([one_ring_v_ids1, one_ring_v_ids2]);
908
909 let face_order = if prev_single_v_id == prev_other_v_id {
910 PlannedFaceOrder::Start
911 } else if single_v_id == other_v_id {
912 PlannedFaceOrder::End
913 } else {
914 PlannedFaceOrder::Middle
915 };
916
917 if pairing.single_range_idx == 0 {
919 if prev_single_v_id != prev_other_v_id {
920 planned_faces.push(PlannedFace::new(
921 prev_single_v_id,
922 single_v_id,
923 prev_other_v_id,
924 face_order,
925 ));
926 }
927 if single_v_id != other_v_id {
928 planned_faces.push(PlannedFace::new(
929 prev_other_v_id,
930 single_v_id,
931 other_v_id,
932 face_order,
933 ));
934 }
935 } else {
936 if prev_single_v_id != prev_other_v_id {
937 planned_faces.push(PlannedFace::new(
938 prev_single_v_id,
939 prev_other_v_id,
940 single_v_id,
941 face_order,
942 ));
943 }
944 if single_v_id != other_v_id {
945 planned_faces.push(PlannedFace::new(
946 prev_other_v_id,
947 other_v_id,
948 single_v_id,
949 face_order,
950 ));
951 }
952 }
953 }
954
955 planned_faces.extend(pairing.fill_faces([one_ring_v_ids1, one_ring_v_ids2]));
957
958 let (single_v_id, other_v_id) =
959 pairing.last_pair([one_ring_v_ids1, one_ring_v_ids2]);
960
961 prev_single_v_id = Some(single_v_id);
962 prev_other_v_id = Some(other_v_id);
963 }
964
965 if planned_faces.len() == start_pairing_index {
966 continue;
968 }
969
970 if !matches!(
971 range_pair_to_connect.start_cap,
972 ConnectPairCap::AlreadyConnected
973 ) {
974 planned_faces[start_pairing_index].order = PlannedFaceOrder::Start;
975 }
976
977 let len = planned_faces.len();
978 planned_faces[len - 1].order = if len - 1 == start_pairing_index {
979 PlannedFaceOrder::Single
980 } else {
981 PlannedFaceOrder::End
982 };
983 }
984
985 planned_faces
986 }
987
988 #[instrument(skip_all)]
989 fn check_and_flip_single_shared_he(
990 &mut self,
991 shared_he_ids: &HashSet<HalfedgeId>,
992 flip_threshold_sqr: f32,
993 result: &mut MergeVerticesOneRing,
994 ) -> bool {
995 if shared_he_ids.len() == 1 {
996 let shared_he_id = shared_he_ids.iter().copied().next().unwrap();
997
998 #[cfg(feature = "rerun")]
999 self.log_he_rerun("common_one_ring_he", shared_he_id);
1000
1001 return self.flip_and_collapse_single_shared_edge_if_below_threshold(
1002 shared_he_id,
1003 flip_threshold_sqr,
1004 result,
1005 );
1006 }
1007
1008 false
1009 }
1010
1011 #[instrument(skip_all)]
1012 #[allow(clippy::too_many_arguments)]
1013 fn compute_range_pairs_to_connect(
1014 &mut self,
1015 one_ring_v_ids1: &[VertexId],
1016 one_ring_v_ids2: &[VertexId],
1017 one_ring_he_ids1: &[HalfedgeId],
1018 one_ring_he_ids2: &[HalfedgeId],
1019 shared_v_ids: &HashSet<VertexId>,
1020 shared_he_ids: &HashSet<HalfedgeId>,
1021 mut connected_v_ids: HashSet<VertexId>,
1022 mut connected_he_ids: HashSet<HalfedgeId>,
1023 ) -> Vec<ConnectPair> {
1024 let mut range_pairs_to_connect = vec![];
1025
1026 let (orig_start_idx1, orig_start_idx2, orig_start_cap) = unwrap_or_return!(
1027 self.find_start_indices(
1028 one_ring_v_ids1,
1029 one_ring_v_ids2,
1030 one_ring_he_ids1,
1031 one_ring_he_ids2,
1032 shared_v_ids,
1033 shared_he_ids,
1034 &connected_v_ids,
1035 &connected_he_ids,
1036 ),
1037 "Couldn't find start indices",
1038 range_pairs_to_connect
1039 );
1040
1041 tracing::debug!(
1042 "start idx1: {}, start idx2: {}",
1043 orig_start_idx1,
1044 orig_start_idx2
1045 );
1046
1047 let len1 = one_ring_v_ids1.len();
1048 let len2 = one_ring_v_ids2.len();
1049
1050 let mut start_idx1 = orig_start_idx1;
1051 let mut start_idx2 = orig_start_idx2;
1052 let mut start_cap = orig_start_cap;
1053
1054 let mut end_idx1 = (start_idx1 + 1) % len1;
1055 let mut end_idx2 = (start_idx2 + 1) % len2;
1056
1057 #[cfg(feature = "rerun")]
1058 {
1059 self.log_verts_w_labels_rerun(
1060 "pairs_start_idx",
1061 &[one_ring_v_ids1[start_idx1], one_ring_v_ids2[start_idx2]],
1062 &["1", "2"],
1063 );
1064 self.log_vert_rerun("pairs_end_idx1", one_ring_v_ids1[end_idx1]);
1065 self.log_vert_rerun("pairs_end_idx2", one_ring_v_ids2[end_idx2]);
1066 }
1067 let mut v_id1;
1068 let mut v_id2;
1069
1070 while end_idx1 != orig_start_idx1 {
1071 v_id1 = one_ring_v_ids1[end_idx1];
1072 v_id2 = one_ring_v_ids2[end_idx2];
1073
1074 if !self.vertices.contains_key(v_id1) || !self.vertices.contains_key(v_id2) {
1075 break;
1076 }
1077
1078 let mut end_cap = ConnectPairCap::Open;
1079
1080 if shared_v_ids.contains(&v_id1) {
1081 let start_end_idx2 = end_idx2;
1082 while v_id2 != v_id1 {
1083 end_idx2 = (end_idx2 + 1) % len2;
1084 v_id2 = one_ring_v_ids2[end_idx2];
1085
1086 #[cfg(feature = "rerun")]
1087 self.log_vert_rerun("pairs_end_idx2", v_id2);
1088
1089 if end_idx2 == start_end_idx2 {
1090 error!("Full cycle without finding shared vertex in one ring 2");
1091 return range_pairs_to_connect;
1092 }
1093 }
1094
1095 end_cap = ConnectPairCap::Closed;
1096 } else if shared_v_ids.contains(&v_id2) {
1097 let start_end_idx1 = end_idx1;
1098 while v_id1 != v_id2 {
1099 end_idx1 = (end_idx1 + 1) % len1;
1100 v_id1 = one_ring_v_ids1[end_idx1];
1101
1102 #[cfg(feature = "rerun")]
1103 self.log_vert_rerun("pairs_end_idx1", v_id1);
1104
1105 if end_idx1 == start_end_idx1 {
1106 error!("Full cycle without finding shared vertex in one ring 1");
1107 return range_pairs_to_connect;
1108 }
1109 }
1110
1111 end_cap = ConnectPairCap::Closed;
1112 } else if connected_v_ids.contains(&v_id1) {
1113 let start_end_idx2 = end_idx2;
1114 while !connected_v_ids.contains(&v_id2) {
1115 end_idx2 = (end_idx2 + 1) % len2;
1116 v_id2 = one_ring_v_ids2[end_idx2];
1117
1118 #[cfg(feature = "rerun")]
1119 self.log_vert_rerun("pairs_end_idx2", v_id2);
1120
1121 if end_idx2 == start_end_idx2 {
1122 error!("Full cycle without finding connected vertex in one ring 2");
1123 return range_pairs_to_connect;
1124 }
1125 }
1126
1127 end_cap = ConnectPairCap::AlreadyConnected;
1128 } else if connected_v_ids.contains(&v_id2) {
1129 let start_end_idx1 = end_idx1;
1130 while !connected_v_ids.contains(&v_id1) {
1131 end_idx1 = (end_idx1 + 1) % len1;
1132 v_id1 = one_ring_v_ids1[end_idx1];
1133
1134 #[cfg(feature = "rerun")]
1135 self.log_vert_rerun("pairs_end_idx1", v_id1);
1136
1137 if end_idx1 == start_end_idx1 {
1138 error!("Full cycle without finding connected vertex in one ring 1");
1139 return range_pairs_to_connect;
1140 }
1141 }
1142
1143 end_cap = ConnectPairCap::AlreadyConnected;
1144 }
1145
1146 if !matches!(end_cap, ConnectPairCap::Open) {
1147 range_pairs_to_connect.push(ConnectPair::new(
1148 start_idx1..=end_idx1,
1149 len1,
1150 start_idx2..=end_idx2,
1151 len2,
1152 start_cap,
1153 ));
1154
1155 self.remember_range_pair_connections(
1156 start_idx1,
1157 end_idx1,
1158 start_idx2,
1159 end_idx2,
1160 len1,
1161 len2,
1162 one_ring_v_ids1,
1163 one_ring_v_ids2,
1164 one_ring_he_ids1,
1165 one_ring_he_ids2,
1166 &mut connected_v_ids,
1167 &mut connected_he_ids,
1168 );
1169
1170 if let Some((idx1, idx2, start)) = self.find_start_indices(
1171 one_ring_v_ids1,
1172 one_ring_v_ids2,
1173 one_ring_he_ids1,
1174 one_ring_he_ids2,
1175 shared_v_ids,
1176 shared_he_ids,
1177 &connected_v_ids,
1178 &connected_he_ids,
1179 ) {
1180 start_idx1 = idx1;
1181 start_idx2 = idx2;
1182 start_cap = start;
1183 } else {
1184 return range_pairs_to_connect;
1185 }
1186
1187 end_idx1 = (start_idx1 + 1) % len1;
1188 end_idx2 = (start_idx2 + 1) % len2;
1189
1190 #[cfg(feature = "rerun")]
1191 {
1192 self.log_verts_w_labels_rerun(
1193 "pairs_start_idx",
1194 &[one_ring_v_ids1[start_idx1], one_ring_v_ids2[start_idx2]],
1195 &["1", "2"],
1196 );
1197 self.log_vert_rerun("pairs_end_idx1", one_ring_v_ids1[end_idx1]);
1198 self.log_vert_rerun("pairs_end_idx2", one_ring_v_ids2[end_idx2]);
1199 }
1200
1201 if start_idx1 == orig_start_idx1 {
1202 break;
1203 }
1204 } else {
1205 end_idx1 = (end_idx1 + 1) % len1;
1206 end_idx2 = (end_idx2 + 1) % len2;
1207
1208 #[cfg(feature = "rerun")]
1209 {
1210 self.log_vert_rerun("pairs_end_idx1", one_ring_v_ids1[end_idx1]);
1211 self.log_vert_rerun("pairs_end_idx2", one_ring_v_ids2[end_idx2]);
1212 }
1213 }
1214 }
1215
1216 let diff1 = (start_idx1 as i32 - end_idx1 as i32).unsigned_abs() as usize;
1217 let diff1 = diff1.min(len1 - diff1);
1218
1219 let diff2 = (start_idx2 as i32 - end_idx2 as i32).unsigned_abs() as usize;
1220 let diff2 = diff2.min(len2 - diff2);
1221
1222 if range_pairs_to_connect.is_empty() {
1223 let (end1, end2, cap) = if shared_v_ids.is_empty() {
1224 (
1225 (orig_start_idx1 + len1 - 1).rem_euclid(len1),
1226 (orig_start_idx2 + len2 - 1).rem_euclid(len2),
1227 ConnectPairCap::Open,
1228 )
1229 } else {
1230 (orig_start_idx1, orig_start_idx2, ConnectPairCap::Closed)
1231 };
1232
1233 range_pairs_to_connect.push(ConnectPair::new(
1234 orig_start_idx1..=end1,
1235 len1,
1236 orig_start_idx2..=end2,
1237 len2,
1238 cap,
1239 ));
1240 } else if diff1 > 1 || diff2 > 1 {
1241 range_pairs_to_connect.push(ConnectPair::new(
1242 start_idx1..=end_idx1,
1243 len1,
1244 start_idx2..=end_idx2,
1245 len2,
1246 start_cap,
1247 ));
1248 }
1249
1250 #[cfg(feature = "rerun")]
1251 {
1252 for range_pair in &range_pairs_to_connect {
1253 let mut v1s = vec![];
1254 let mut v2s = vec![];
1255 let mut l1s = vec![];
1256 let mut l2s = vec![];
1257
1258 for i in range_pair.ranges[0].clone() {
1259 let v_id = one_ring_v_ids1[i % len1];
1260 v1s.push(v_id);
1261 l1s.push(format!("{i} - {v_id:?}"));
1262 }
1263 for i in range_pair.ranges[1].clone() {
1264 let v_id = one_ring_v_ids2[i % len2];
1265 v2s.push(v_id);
1266 l2s.push(format!("{i} - {v_id:?}"));
1267 }
1268
1269 self.log_verts_w_labels_rerun("range_pair_1", &v1s, &l1s);
1270 self.log_verts_w_labels_rerun("range_pair_2", &v2s, &l2s);
1271 }
1272 }
1273
1274 range_pairs_to_connect
1275 }
1276
1277 #[instrument(skip(self))]
1278 #[allow(clippy::too_many_arguments)]
1279 fn remember_range_pair_connections(
1280 &mut self,
1281 start_idx1: usize,
1282 end_idx1: usize,
1283 start_idx2: usize,
1284 end_idx2: usize,
1285 len1: usize,
1286 len2: usize,
1287 one_ring_v_ids1: &[VertexId],
1288 one_ring_v_ids2: &[VertexId],
1289 one_ring_he_ids1: &[HalfedgeId],
1290 one_ring_he_ids2: &[HalfedgeId],
1291 connected_v_ids: &mut HashSet<VertexId>,
1292 connected_he_ids: &mut HashSet<HalfedgeId>,
1293 ) {
1294 let mut idx = start_idx1;
1295 loop {
1296 connected_v_ids.insert(one_ring_v_ids1[idx]);
1297 if idx == end_idx1 {
1298 break;
1299 }
1300 let he_id = one_ring_he_ids1[idx];
1301 connected_he_ids.insert(he_id);
1302
1303 if let Some(he) = self.halfedges.get(he_id) {
1305 if let Some(twin_id) = he.twin {
1307 connected_he_ids.insert(twin_id);
1308 } else {
1309 error!("halfedge {:?} has no twin", he_id);
1310 }
1311 }
1312
1313 idx = (idx + 1) % len1;
1314 }
1315
1316 idx = start_idx2;
1317 loop {
1318 connected_v_ids.insert(one_ring_v_ids2[idx]);
1319 if idx == end_idx2 {
1320 break;
1321 }
1322 let he_id = one_ring_he_ids2[idx];
1323 connected_he_ids.insert(he_id);
1324
1325 if let Some(he) = self.halfedges.get(he_id) {
1327 if let Some(twin_id) = he.twin {
1329 connected_he_ids.insert(twin_id);
1330 } else {
1331 error!("halfedge {:?} has no twin", he_id);
1332 }
1333 }
1334
1335 idx = (idx + 1) % len2;
1336 }
1337 }
1338
1339 #[instrument(skip(self))]
1340 #[allow(clippy::too_many_arguments)]
1341 fn find_shared_start_indices_from_ring(
1342 &self,
1343 one_ring_v_ids: &[VertexId],
1344 other_one_ring_v_ids: &[VertexId],
1345 one_ring_he_ids: &[HalfedgeId],
1346 other_one_ring_he_ids: &[HalfedgeId],
1347 shared_v_ids: &HashSet<VertexId>,
1348 shared_he_ids: &HashSet<HalfedgeId>,
1349 connected_v_ids: &HashSet<VertexId>,
1350 connected_he_ids: &HashSet<HalfedgeId>,
1351 ) -> Option<(usize, usize, ConnectPairCap)> {
1352 let len = one_ring_v_ids.len();
1353 let other_len = other_one_ring_v_ids.len();
1354
1355 debug_assert_eq!(len, one_ring_he_ids.len());
1356 debug_assert_eq!(other_len, other_one_ring_he_ids.len());
1357
1358 for (he_idx, &he_id1) in one_ring_he_ids.iter().enumerate() {
1359 if self.halfedges.contains_key(he_id1)
1360 && !shared_he_ids.contains(&he_id1)
1361 && !connected_he_ids.contains(&he_id1)
1362 {
1363 let mut start_idx = he_idx;
1366 let mut start_he_id = &one_ring_he_ids[start_idx];
1367
1368 let mut start_v_id = &one_ring_v_ids[start_idx];
1369
1370 while self.halfedges.contains_key(*start_he_id)
1371 && !shared_he_ids.contains(start_he_id)
1372 && !connected_he_ids.contains(start_he_id)
1373 && self.vertices.contains_key(*start_v_id)
1374 && !shared_v_ids.contains(start_v_id)
1375 && !connected_v_ids.contains(start_v_id)
1376 {
1377 start_idx = (start_idx + len - 1) % len;
1378 start_he_id = &one_ring_he_ids[start_idx];
1379 start_v_id = &one_ring_v_ids[start_idx];
1380
1381 if start_idx == he_idx {
1382 return None;
1383 }
1384 }
1385
1386 if let Some(other_idx) = other_one_ring_v_ids
1390 .iter()
1391 .position(|v_id| start_v_id == v_id)
1392 {
1393 return Some((start_idx, other_idx, ConnectPairCap::Closed));
1394 }
1395
1396 for (other_idx, &other_v_id) in other_one_ring_v_ids.iter().enumerate() {
1398 if self.halfedge_from_to(*start_v_id, other_v_id).is_some() {
1399 let other_he_id = &other_one_ring_he_ids[other_idx];
1400
1401 if self.halfedges.contains_key(*other_he_id)
1402 && !shared_he_ids.contains(other_he_id)
1403 && !connected_he_ids.contains(other_he_id)
1404 {
1405 return Some((start_idx, other_idx, ConnectPairCap::AlreadyConnected));
1406 }
1407 }
1408 }
1409 }
1410 }
1411
1412 None
1413 }
1414
1415 #[allow(clippy::too_many_arguments)]
1416 #[instrument(skip(self))]
1417 fn find_start_indices(
1418 &self,
1419 one_ring_v_ids1: &[VertexId],
1420 one_ring_v_ids2: &[VertexId],
1421 one_ring_he_ids1: &[HalfedgeId],
1422 one_ring_he_ids2: &[HalfedgeId],
1423 shared_v_ids: &HashSet<VertexId>,
1424 shared_he_ids: &HashSet<HalfedgeId>,
1425 connected_v_ids: &HashSet<VertexId>,
1426 connected_he_ids: &HashSet<HalfedgeId>,
1427 ) -> Option<(usize, usize, ConnectPairCap)> {
1428 if !shared_v_ids.is_empty() || !connected_v_ids.is_empty() {
1429 self.find_shared_start_indices_from_ring(
1430 one_ring_v_ids1,
1431 one_ring_v_ids2,
1432 one_ring_he_ids1,
1433 one_ring_he_ids2,
1434 shared_v_ids,
1435 shared_he_ids,
1436 connected_v_ids,
1437 connected_he_ids,
1438 )
1439 } else {
1440 let first_v_id = one_ring_v_ids1[0];
1441 let first_pos = *self
1442 .positions
1443 .get(first_v_id)
1444 .or_else(error_none!("Position not found"))?;
1445
1446 let mut min_dist_sqr = f32::INFINITY;
1447 let mut start_idx2 = 0;
1448
1449 for (idx, v_id) in one_ring_v_ids2.iter().enumerate() {
1450 let pos = self
1451 .positions
1452 .get(*v_id)
1453 .or_else(error_none!("Position not found"))?;
1454
1455 let dist_sqr = pos.distance_squared(first_pos);
1456
1457 if dist_sqr < min_dist_sqr {
1458 min_dist_sqr = dist_sqr;
1459 start_idx2 = idx;
1460 }
1461 }
1462
1463 Some((0, start_idx2, ConnectPairCap::Open))
1464 }
1465 }
1466}
1467
1468#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1469enum ConnectPairCap {
1470 Closed,
1472 Open,
1474 AlreadyConnected,
1476}
1477
1478#[derive(Debug)]
1480struct ConnectPair {
1481 start_cap: ConnectPairCap,
1483
1484 ranges: [RangeInclusive<usize>; 2],
1486}
1487
1488impl ConnectPair {
1489 fn new(
1490 mut range1: RangeInclusive<usize>,
1491 len1: usize,
1492 mut range2: RangeInclusive<usize>,
1493 len2: usize,
1494 start_cap: ConnectPairCap,
1495 ) -> Self {
1496 if range1.end() <= range1.start() {
1497 range1 = (*range1.start())..=(*range1.end() + len1);
1498 }
1499 if range2.end() <= range2.start() {
1500 range2 = (*range2.start())..=(*range2.end() + len2);
1501 }
1502
1503 ConnectPair {
1504 start_cap,
1505 ranges: [range1, range2],
1506 }
1507 }
1508
1509 fn compute_pairings(&self) -> Vec<Pairing> {
1511 let range1 = self.ranges[0].clone();
1512 let range2 = self.ranges[1].clone();
1513
1514 let count1 = range1.clone().count() as i32;
1515 let count2 = range2.clone().count() as i32;
1516
1517 let (single_range_idx, single_count, other_count, single_range, other_range) =
1518 if count1 > count2 {
1519 (1, count2, count1, range2, range1)
1520 } else {
1521 (0, count1, count2, range1, range2)
1522 };
1523
1524 let mut single_idx_in_range = *single_range.start();
1525
1526 if single_count == 0 {
1527 return vec![];
1528 }
1529 if single_count == 1 {
1530 return vec![Pairing {
1531 single_range_idx,
1532 single_idx_in_range,
1533 other_range,
1534 }];
1535 }
1536
1537 let mut error = 2 * single_count - other_count;
1538
1539 let mut other_start = *other_range.start();
1540 let mut other_end = other_start;
1541
1542 let mut pairings = Vec::new();
1543
1544 while other_end <= *other_range.end() {
1545 if error > 0 {
1546 pairings.push(Pairing {
1547 single_range_idx,
1548 single_idx_in_range,
1549 other_range: other_start..=other_end,
1550 });
1551
1552 other_start = other_end + 1;
1553 single_idx_in_range += 1;
1554 error += 2 * (single_count - other_count);
1555 } else {
1556 error += 2 * single_count;
1557 }
1558
1559 other_end += 1;
1560 }
1561
1562 if let Some(last_pairing) = pairings.last_mut() {
1563 last_pairing.other_range = *last_pairing.other_range.start()..=*other_range.end();
1564 }
1565
1566 pairings
1567 }
1568}
1569
1570enum TriangleFan {
1572 Spanning(Pairing),
1575
1576 NotSpanning,
1582
1583 Failed,
1585}
1586
1587#[derive(Debug, Clone)]
1589struct Pairing {
1590 single_range_idx: usize,
1593
1594 single_idx_in_range: usize,
1596
1597 other_range: RangeInclusive<usize>,
1599}
1600
1601impl Pairing {
1602 fn new_triangle(
1603 single_range_idx: usize,
1604 single_idx_in_range: usize,
1605 other_idx1: usize,
1606 other_idx2: usize,
1607 other_len: usize,
1608 ) -> Self {
1609 let other_range = if other_idx1 == other_idx2 {
1610 other_idx1..=other_idx2
1611 } else if (other_idx1 as i32 - other_idx2 as i32).abs() == 1 {
1612 other_idx1.min(other_idx2)..=other_idx1.max(other_idx2)
1613 } else {
1614 other_idx1.max(other_idx2)..=other_idx1.min(other_idx2) + other_len
1615 };
1616
1617 Self {
1618 single_range_idx,
1619 single_idx_in_range,
1620 other_range,
1621 }
1622 }
1623
1624 fn all_vertex_ids(&self, v_ids: [&[VertexId]; 2]) -> Vec<VertexId> {
1625 let single_ids = &v_ids[self.single_range_idx];
1626 let other_ids = &v_ids[1 - self.single_range_idx];
1627
1628 let mut all_ids = vec![];
1629
1630 all_ids.push(single_ids[self.single_idx_in_range % single_ids.len()]);
1631
1632 let mut idx = *self.other_range.start() % other_ids.len();
1633 all_ids.push(other_ids[idx]);
1634 while idx != *self.other_range.end() % other_ids.len() {
1635 idx += 1;
1636 idx %= other_ids.len();
1637 all_ids.push(other_ids[idx]);
1638 }
1639
1640 all_ids
1641 }
1642
1643 fn first_pair(&self, v_ids: [&[VertexId]; 2]) -> (VertexId, VertexId) {
1644 let single_ids = &v_ids[self.single_range_idx];
1645 let other_ids = &v_ids[1 - self.single_range_idx];
1646
1647 let single_v_id = single_ids[self.single_idx_in_range % single_ids.len()];
1648 let other_v_id = other_ids[*self.other_range.start() % other_ids.len()];
1649
1650 (single_v_id, other_v_id)
1651 }
1652
1653 fn last_pair(&self, v_ids: [&[VertexId]; 2]) -> (VertexId, VertexId) {
1654 let single_ids = &v_ids[self.single_range_idx];
1655 let other_ids = &v_ids[1 - self.single_range_idx];
1656
1657 let single_v_id = single_ids[self.single_idx_in_range % single_ids.len()];
1658 let other_v_id = other_ids[*self.other_range.end() % other_ids.len()];
1659
1660 (single_v_id, other_v_id)
1661 }
1662
1663 fn fill_faces(&self, v_ids: [&[VertexId]; 2]) -> Vec<PlannedFace> {
1664 let single_ids = v_ids[self.single_range_idx];
1665 let other_ids = v_ids[1 - self.single_range_idx];
1666
1667 let single_v_id = single_ids[self.single_idx_in_range % single_ids.len()];
1668 let mut faces = Vec::<PlannedFace>::new();
1669
1670 let mut others = self.other_range.clone();
1671
1672 if others.start() == others.end() {
1673 return faces;
1674 }
1675
1676 let mut prev_other_v_id = other_ids[others.next().unwrap() % other_ids.len()];
1677 let mut face_order = PlannedFaceOrder::Middle;
1678
1679 if prev_other_v_id == single_v_id {
1680 face_order = PlannedFaceOrder::Start;
1681
1682 if let Some(second_idx) = others.next() {
1683 prev_other_v_id = other_ids[second_idx % other_ids.len()];
1684 } else {
1685 return faces;
1686 }
1687 }
1688
1689 for other_idx in others {
1690 let other_v_id = other_ids[other_idx % other_ids.len()];
1691
1692 if other_v_id == single_v_id {
1693 break;
1694 }
1695
1696 if other_v_id == prev_other_v_id {
1697 prev_other_v_id = other_v_id;
1701 continue;
1702 }
1703
1704 if self.single_range_idx == 0 {
1706 faces.push(PlannedFace::new(
1707 prev_other_v_id,
1708 single_v_id,
1709 other_v_id,
1710 face_order,
1711 ));
1712 } else {
1713 faces.push(PlannedFace::new(
1714 prev_other_v_id,
1715 other_v_id,
1716 single_v_id,
1717 face_order,
1718 ));
1719 }
1720
1721 face_order = PlannedFaceOrder::Middle;
1722 prev_other_v_id = other_v_id;
1723 }
1724
1725 faces
1726 }
1727
1728 #[cfg(feature = "rerun")]
1729 fn log_rerun(
1730 &self,
1731 label: impl AsRef<str>,
1732 v_ids: [&[VertexId]; 2],
1733 mesh_graph: &MeshGraph,
1734 ) -> Option<()> {
1735 use crate::utils::vec3_array;
1736
1737 let single_v_ids = v_ids[self.single_range_idx];
1738 let other_v_ids = v_ids[1 - self.single_range_idx];
1739
1740 let single_v_id = single_v_ids[self.single_idx_in_range];
1741 let single_pos = vec3_array(mesh_graph.positions.get(single_v_id)?);
1742
1743 let mut other_pos = vec![];
1744 let mut idx = self.other_range.start() % other_v_ids.len();
1745
1746 other_pos.push(vec3_array(mesh_graph.positions.get(other_v_ids[idx])?));
1747 while idx != *self.other_range.end() % other_v_ids.len() {
1748 idx += 1;
1749 idx %= other_v_ids.len();
1750 other_pos.push(vec3_array(mesh_graph.positions.get(other_v_ids[idx])?));
1751 }
1752
1753 crate::RR
1754 .log(
1755 format!("pairing/{}/single", label.as_ref()),
1756 &rerun::Points3D::new([single_pos]),
1757 )
1758 .unwrap();
1759 crate::RR
1760 .log(
1761 format!("pairing/{}/other", label.as_ref()),
1762 &rerun::LineStrips3D::new(
1763 other_pos
1764 .into_iter()
1765 .map(|other_pos| [single_pos, other_pos]),
1766 ),
1767 )
1768 .unwrap();
1769
1770 Some(())
1771 }
1772}
1773
1774#[derive(Debug)]
1788struct PlannedFace {
1789 order: PlannedFaceOrder,
1790 v1: VertexId,
1791 new_he_v1: VertexId,
1792 new_he_v2: VertexId,
1793}
1794
1795#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1796enum PlannedFaceOrder {
1797 Start,
1798 Middle,
1799 End,
1800 Single,
1801}
1802
1803impl PlannedFace {
1804 fn new(
1805 v_id1: VertexId,
1806 new_he_v_id1: VertexId,
1807 new_he_v_id2: VertexId,
1808 order: PlannedFaceOrder,
1809 ) -> Self {
1810 PlannedFace {
1811 order,
1812 v1: v_id1,
1813 new_he_v1: new_he_v_id1,
1814 new_he_v2: new_he_v_id2,
1815 }
1816 }
1817
1818 #[instrument(skip(mesh_graph, result))]
1819 fn add_to_mesh_graph(
1820 &self,
1821 mesh_graph: &mut MeshGraph,
1822 result: &mut MergeVerticesOneRing,
1823 ) -> Option<(Option<HalfedgeId>, AddFace)> {
1824 #[cfg(feature = "rerun")]
1825 self.log_rerun("add_to_mesh_graph", mesh_graph);
1826
1827 if self.v1 == self.new_he_v1
1828 || self.v1 == self.new_he_v2
1829 || self.new_he_v1 == self.new_he_v2
1830 {
1831 error!(
1832 "Skipping degenerate planned face with repeated vertices: {:?}",
1833 (self.v1, self.new_he_v1, self.new_he_v2)
1834 );
1835 return None;
1836 }
1837
1838 let add_or_get_edge1 = mesh_graph.add_or_get_boundary_edge(self.v1, self.new_he_v1)?;
1839 let add_or_get_edge2 =
1840 mesh_graph.add_or_get_boundary_edge(self.new_he_v1, self.new_he_v2)?;
1841
1842 for he_id in [
1848 add_or_get_edge1.start_to_end_he_id,
1849 add_or_get_edge2.start_to_end_he_id,
1850 ] {
1851 mesh_graph.dismantle_faced_member(he_id, result);
1852 }
1853
1854 let mut add_face = mesh_graph.add_face_from_halfedges(
1855 add_or_get_edge1.start_to_end_he_id,
1856 add_or_get_edge2.start_to_end_he_id,
1857 )?;
1858
1859 if add_or_get_edge1.new_start_to_end {
1860 add_face
1861 .halfedge_ids
1862 .push(add_or_get_edge1.start_to_end_he_id);
1863 }
1864 if add_or_get_edge1.new_twin {
1865 add_face.halfedge_ids.push(add_or_get_edge1.twin_he_id);
1866 }
1867 if add_or_get_edge2.new_start_to_end {
1868 add_face
1869 .halfedge_ids
1870 .push(add_or_get_edge2.start_to_end_he_id);
1871 }
1872 if add_or_get_edge2.new_twin {
1873 add_face.halfedge_ids.push(add_or_get_edge2.twin_he_id);
1874 }
1875
1876 Some((
1877 if matches!(
1878 self.order,
1879 PlannedFaceOrder::Start | PlannedFaceOrder::Middle
1880 ) && mesh_graph.halfedges[add_or_get_edge2.twin_he_id].is_boundary()
1881 {
1882 Some(add_or_get_edge2.twin_he_id)
1883 } else {
1884 None
1885 },
1886 add_face,
1887 ))
1888 }
1889
1890 #[instrument(skip(mesh_graph, result))]
1891 fn add_to_mesh_graph_and_he(
1892 &self,
1893 mesh_graph: &mut MeshGraph,
1894 existing_he_id: HalfedgeId,
1895 result: &mut MergeVerticesOneRing,
1896 ) -> Option<(Option<HalfedgeId>, AddFace)> {
1897 #[cfg(feature = "rerun")]
1898 self.log_rerun("add_to_mesh_graph_and_he", mesh_graph);
1899
1900 if self.v1 == self.new_he_v1
1901 || self.v1 == self.new_he_v2
1902 || self.new_he_v1 == self.new_he_v2
1903 {
1904 error!(
1905 "Skipping degenerate planned face with repeated vertices: {:?}",
1906 (self.v1, self.new_he_v1, self.new_he_v2)
1907 );
1908 return None;
1909 }
1910
1911 match self.order {
1912 PlannedFaceOrder::Middle => {
1913 let AddEdge {
1914 start_to_end_he_id,
1915 twin_he_id,
1916 } = mesh_graph.add_edge(self.new_he_v1, self.new_he_v2)?;
1917
1918 mesh_graph.dismantle_faced_member(existing_he_id, result);
1925 mesh_graph.dismantle_faced_member(start_to_end_he_id, result);
1926
1927 let mut add_face =
1928 mesh_graph.add_face_from_halfedges(existing_he_id, start_to_end_he_id)?;
1929 add_face.halfedge_ids.push(start_to_end_he_id);
1930 add_face.halfedge_ids.push(twin_he_id);
1931
1932 Some((Some(twin_he_id), add_face))
1933 }
1934 PlannedFaceOrder::End => {
1935 let add_or_get_edge =
1936 mesh_graph.add_or_get_boundary_edge(self.new_he_v1, self.new_he_v2)?;
1937
1938 mesh_graph.dismantle_faced_member(existing_he_id, result);
1939 mesh_graph.dismantle_faced_member(add_or_get_edge.start_to_end_he_id, result);
1940
1941 let mut add_face = mesh_graph
1942 .add_face_from_halfedges(existing_he_id, add_or_get_edge.start_to_end_he_id)?;
1943 if add_or_get_edge.new_start_to_end {
1944 add_face
1945 .halfedge_ids
1946 .push(add_or_get_edge.start_to_end_he_id);
1947 }
1948 if add_or_get_edge.new_twin {
1949 add_face.halfedge_ids.push(add_or_get_edge.twin_he_id);
1950 }
1951
1952 Some((None, add_face))
1953 }
1954 _ => {
1955 error!("Invalid face order {:?}", self.order);
1956 None
1957 }
1958 }
1959 }
1960
1961 #[cfg(feature = "rerun")]
1962 fn log_rerun(&self, label: &str, mesh_graph: &MeshGraph) {
1963 use crate::{RR, utils::vec3_array};
1964
1965 let (positions, labels): (Vec<_>, Vec<_>) =
1966 [(self.v1, "1"), (self.new_he_v1, "2"), (self.new_he_v2, "3")]
1967 .into_iter()
1968 .filter_map(|(v_id, labl)| mesh_graph.positions.get(v_id).map(|a| (a, labl)))
1969 .unzip();
1970
1971 RR.log(
1972 format!("meshgraph/planned_face/{label}/positions"),
1973 &rerun::Points3D::new(positions.iter().map(vec3_array)).with_labels(labels),
1974 )
1975 .unwrap();
1976
1977 RR.log(
1978 format!("meshgraph/planned_face/{label}/edges"),
1979 &rerun::Arrows3D::from_vectors(
1980 positions
1981 .iter()
1982 .circular_array_windows()
1983 .map(|[a, b]| vec3_array(*b - *a)),
1984 )
1985 .with_origins(positions.iter().map(vec3_array)),
1986 )
1987 .unwrap();
1988 }
1989}