1#[cfg(test)]
2mod tests;
3
4use std::{f32, ops::RangeInclusive};
5
6use hashbrown::HashSet;
7use itertools::Itertools;
8use tracing::{error, instrument};
9
10use crate::{
11 AddEdge, AddOrGetEdge, FaceId, HalfedgeId, MeshGraph, Vertex, VertexId, error_none,
12 ops::{add::AddFace, collapse::CollapseEdge},
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 let mut result = MergeVerticesOneRing::default();
44
45 let vertex1 = *unwrap_or_return!(self.vertices.get(vertex_id1), "Vertex not found", result);
46 let vertex2 = *unwrap_or_return!(self.vertices.get(vertex_id2), "Vertex not found", result);
47
48 let one_ring_v_ids1 = vertex1
50 .one_ring(self)
51 .map(|he_id| self.halfedges[he_id].end_vertex)
52 .collect_vec();
53 let mut one_ring_v_ids2 = vertex2
54 .one_ring(self)
55 .map(|he_id| self.halfedges[he_id].end_vertex)
56 .collect_vec();
57 one_ring_v_ids2.reverse();
58
59 if one_ring_v_ids1.len() < 3 || one_ring_v_ids2.len() < 3 {
60 error!("One rings are too small");
61 return result;
62 }
63
64 let one_ring_set1 = HashSet::<VertexId>::from_iter(one_ring_v_ids1.iter().copied());
65 let one_ring_set2 = HashSet::<VertexId>::from_iter(one_ring_v_ids2.iter().copied());
66 let shared_v_ids =
67 HashSet::<VertexId>::from_iter(one_ring_set1.intersection(&one_ring_set2).copied());
68
69 if self.check_and_flip_single_shared_he(
70 &one_ring_v_ids1,
71 &one_ring_v_ids2,
72 &shared_v_ids,
73 flip_threshold_sqr,
74 &mut result,
75 ) {
76 return result;
77 }
78
79 self.remove_neighbour_faces(&vertex1, &vertex2, &mut result);
80
81 #[cfg(feature = "rerun")]
82 self.log_rerun();
83
84 let range_pairs_to_connect =
85 self.compute_range_pairs_to_connect(&one_ring_v_ids1, &one_ring_v_ids2, &shared_v_ids);
86
87 if range_pairs_to_connect.is_empty() {
88 error!("No range pairs to connect");
89 return result;
90 }
91
92 tracing::info!("Range pairs to connect: {range_pairs_to_connect:#?}");
93
94 let planned_faces =
95 self.plan_new_faces(&range_pairs_to_connect, &one_ring_v_ids1, &one_ring_v_ids2);
96
97 self.add_planned_faces(
98 planned_faces,
99 &one_ring_set1,
100 &one_ring_set2,
101 marked_halfedges,
102 &mut result,
103 );
104
105 #[cfg(feature = "rerun")]
106 self.log_rerun();
107
108 self.cleanup_bookkeeping(
109 &one_ring_v_ids1,
110 &one_ring_v_ids2,
111 marked_vertices,
112 marked_halfedges,
113 &mut result,
114 );
115
116 tracing::info!("smoothing vertices");
117 self.smooth_vertices(
118 one_ring_v_ids1
119 .iter()
120 .chain(&one_ring_v_ids2)
121 .chain(&result.added_vertices)
122 .copied(),
123 );
124
125 result
126 }
127
128 fn cleanup_bookkeeping(
129 &mut self,
130 one_ring_v_ids1: &[VertexId],
131 one_ring_v_ids2: &[VertexId],
132 marked_vertices: &mut HashSet<VertexId>,
133 marked_halfedges: &mut HashSet<HalfedgeId>,
134 result: &mut MergeVerticesOneRing,
135 ) {
136 for vertex_id in one_ring_v_ids1.iter().chain(one_ring_v_ids2).copied() {
137 if !self.vertices.contains_key(vertex_id) {
138 continue;
139 }
140
141 let cleanup = self.make_vertex_neighborhood_manifold(vertex_id);
142
143 if !cleanup.added_vertices.is_empty() {
144 marked_vertices.insert(vertex_id);
145 }
146
147 result.added_vertices.extend(cleanup.added_vertices.clone());
148 marked_vertices.extend(cleanup.added_vertices);
149
150 for removed_v_id in cleanup.removed_vertices {
151 if result.added_vertices.contains(&removed_v_id) {
152 result.added_vertices.retain(|&v_id| v_id != removed_v_id);
153 } else {
154 result.removed_vertices.push(removed_v_id);
155 }
156
157 marked_vertices.remove(&removed_v_id);
158 }
159
160 for removed_he_id in cleanup.removed_halfedges {
161 if result.added_halfedges.contains(&removed_he_id) {
162 result
163 .added_halfedges
164 .retain(|&he_id| he_id != removed_he_id);
165 } else {
166 result.removed_halfedges.push(removed_he_id);
167 }
168
169 marked_halfedges.remove(&removed_he_id);
170 }
171
172 for removed_face_id in cleanup.removed_faces {
173 if result.added_faces.contains(&removed_face_id) {
174 result
175 .added_faces
176 .retain(|&face_id| face_id != removed_face_id);
177 } else {
178 result.removed_faces.push(removed_face_id);
179 }
180 }
181 }
182 }
183
184 fn add_planned_faces(
185 &mut self,
186 planned_faces: Vec<PlannedFace>,
187 one_ring_set1: &HashSet<VertexId>,
188 one_ring_set2: &HashSet<VertexId>,
189 marked_halfedges: &mut HashSet<HalfedgeId>,
190 result: &mut MergeVerticesOneRing,
191 ) {
192 let mut prev_he = None;
193
194 for planned_face in planned_faces {
195 let inserted = if let Some(prev_he) = prev_he {
196 planned_face.add_to_meshgraph_and_he(self, prev_he)
197 } else {
198 planned_face.add_to_meshgraph(self)
199 };
200
201 let inserted = unwrap_or_return!(inserted, "Failed to add face");
202
203 prev_he = inserted.0;
204 let inserted = inserted.1;
205
206 for he_id in inserted.halfedge_ids.iter().copied() {
207 let he = self.halfedges[he_id];
209 let start_v_id =
210 unwrap_or_return!(he.start_vertex(self), "Couldn't find start vertex");
211 let end_v_id = he.end_vertex;
212
213 if one_ring_set1.contains(&start_v_id) && one_ring_set2.contains(&end_v_id)
214 || one_ring_set2.contains(&start_v_id) && one_ring_set1.contains(&end_v_id)
215 {
216 marked_halfedges.insert(he_id);
217 }
218 }
219
220 result.added_halfedges.extend(inserted.halfedge_ids);
221 result.added_faces.push(inserted.face_id);
222 }
223 }
224
225 fn remove_neighbour_faces(
226 &mut self,
227 vertex1: &Vertex,
228 vertex2: &Vertex,
229 result: &mut MergeVerticesOneRing,
230 ) {
231 let face_ids1 = vertex1.faces(self).collect_vec();
232 let face_ids2 = vertex2.faces(self).collect_vec();
233
234 for face_id in face_ids1.into_iter().chain(face_ids2) {
235 let (del_v, del_he) = self.remove_face(face_id);
236
237 result.removed_faces.push(face_id);
238 result.removed_vertices.extend(del_v);
239 result.removed_halfedges.extend(del_he);
240 }
241 }
242
243 #[instrument(skip_all)]
244 fn flip_and_collapse_single_shared_edge_if_below_threshold(
245 &mut self,
246 single_shared_he_id: HalfedgeId,
247 flip_threshold_sqr: f32,
248 result: &mut MergeVerticesOneRing,
249 ) -> bool {
250 let he = self.halfedges[single_shared_he_id];
251
252 let twin_id = unwrap_or_return!(he.twin, "Twin not found", false);
253 let twin = unwrap_or_return!(self.halfedges.get(twin_id), "Twin not found", false);
254
255 let other_v_id1 =
256 unwrap_or_return!(he.opposite_vertex(self), "Opposite vertex not found", false);
257 let other_v_id2 = unwrap_or_return!(
258 twin.opposite_vertex(self),
259 "Opposite vertex not found",
260 false
261 );
262
263 let pos1 = *unwrap_or_return!(self.positions.get(other_v_id1), "Position not found", false);
264 let pos2 = *unwrap_or_return!(self.positions.get(other_v_id2), "Position not found", false);
265
266 if pos1.distance_squared(pos2) <= flip_threshold_sqr {
267 tracing::info!("Flipping edge {single_shared_he_id:?}");
268
269 self.flip_edge(single_shared_he_id);
270
271 let CollapseEdge {
272 removed_vertices,
273 removed_halfedges,
274 removed_faces,
275 added_vertices,
276 } = self.collapse_edge(single_shared_he_id);
277
278 result.added_vertices.extend(added_vertices);
279 result.removed_vertices.extend(removed_vertices);
280 result.removed_halfedges.extend(removed_halfedges);
281 result.removed_faces.extend(removed_faces);
282
283 true
284 } else {
285 false
286 }
287 }
288
289 fn plan_new_faces(
290 &self,
291 range_pairs_to_connect: &[ConnectPair],
292 one_ring_v_ids1: &[VertexId],
293 one_ring_v_ids2: &[VertexId],
294 ) -> Vec<PlannedFace> {
295 let mut planned_faces = Vec::with_capacity(one_ring_v_ids1.len());
296
297 for range_pair_to_connect in range_pairs_to_connect {
298 let start_pairing_index = planned_faces.len();
299
300 let pairings = range_pair_to_connect.compute_pairings();
301
302 tracing::info!("Pairings: {:#?}", pairings);
303
304 if pairings.is_empty() {
305 continue;
306 }
307
308 let mut prev_single_v_id = None;
309 let mut prev_other_v_id = None;
310
311 if !range_pair_to_connect.closed {
312 let last_pairing = pairings.last().unwrap();
313
314 let (s, o) = last_pairing.last_pair([one_ring_v_ids1, one_ring_v_ids2]);
315
316 prev_single_v_id = Some(s);
317 prev_other_v_id = Some(o);
318 }
319
320 for pairing in pairings {
321 if let Some(prev_single_v_id) = prev_single_v_id
322 && let Some(prev_other_v_id) = prev_other_v_id
323 {
324 let (single_v_id, other_v_id) =
326 pairing.first_pair([one_ring_v_ids1, one_ring_v_ids2]);
327
328 let face_order = if prev_single_v_id == prev_other_v_id {
329 PlannedFaceOrder::Start
330 } else if single_v_id == other_v_id {
331 PlannedFaceOrder::End
332 } else {
333 PlannedFaceOrder::Middle
334 };
335
336 if pairing.single_range_idx == 0 {
338 if prev_single_v_id != prev_other_v_id {
339 planned_faces.push(PlannedFace::new(
340 prev_single_v_id,
341 single_v_id,
342 prev_other_v_id,
343 face_order,
344 ));
345 }
346 if single_v_id != other_v_id {
347 planned_faces.push(PlannedFace::new(
348 prev_other_v_id,
349 single_v_id,
350 other_v_id,
351 face_order,
352 ));
353 }
354 } else {
355 if prev_single_v_id != prev_other_v_id {
356 planned_faces.push(PlannedFace::new(
357 prev_single_v_id,
358 prev_other_v_id,
359 single_v_id,
360 face_order,
361 ));
362 }
363 if single_v_id != other_v_id {
364 planned_faces.push(PlannedFace::new(
365 prev_other_v_id,
366 other_v_id,
367 single_v_id,
368 face_order,
369 ));
370 }
371 }
372 }
373
374 planned_faces.extend(pairing.fill_faces([one_ring_v_ids1, one_ring_v_ids2]));
376
377 let (single_v_id, other_v_id) =
378 pairing.last_pair([one_ring_v_ids1, one_ring_v_ids2]);
379
380 prev_single_v_id = Some(single_v_id);
381 prev_other_v_id = Some(other_v_id);
382 }
383
384 planned_faces[start_pairing_index].order = PlannedFaceOrder::Start;
385
386 let len = planned_faces.len();
387 planned_faces[len - 1].order = if len - 1 == start_pairing_index {
388 PlannedFaceOrder::Single
389 } else {
390 PlannedFaceOrder::End
391 };
392 }
393
394 planned_faces
395 }
396
397 #[instrument(skip_all)]
398 fn check_and_flip_single_shared_he(
399 &mut self,
400 one_ring_v_ids1: &[VertexId],
401 one_ring_v_ids2: &[VertexId],
402 shared_v_ids: &HashSet<VertexId>,
403 flip_threshold_sqr: f32,
404 result: &mut MergeVerticesOneRing,
405 ) -> bool {
406 if shared_v_ids.len() == 2 {
407 let (first_v_id, second_v_id) = shared_v_ids.iter().copied().collect_tuple().unwrap();
408
409 let first_pos1 = one_ring_v_ids1
410 .iter()
411 .position(|v_id| *v_id == first_v_id)
412 .unwrap() as i64;
413 let second_pos1 = one_ring_v_ids1
414 .iter()
415 .position(|v_id| *v_id == second_v_id)
416 .unwrap() as i64;
417
418 let first_pos2 = one_ring_v_ids2
419 .iter()
420 .position(|v_id| *v_id == first_v_id)
421 .unwrap() as i64;
422 let second_pos2 = one_ring_v_ids2
423 .iter()
424 .position(|v_id| *v_id == second_v_id)
425 .unwrap() as i64;
426
427 if (first_pos1 - second_pos1).abs() != 1 || (first_pos2 - second_pos2).abs() != 1 {
428 return false;
429 }
430
431 #[cfg(feature = "rerun")]
432 self.log_verts_rerun("common_one_ring", &[first_v_id, second_v_id]);
433
434 if let Some(he_id) = self.halfedge_from_to(first_v_id, second_v_id) {
435 #[cfg(feature = "rerun")]
436 self.log_he_rerun("common_one_ring_he", he_id);
437
438 return self.flip_and_collapse_single_shared_edge_if_below_threshold(
439 he_id,
440 flip_threshold_sqr,
441 result,
442 );
443 }
444 }
445
446 false
447 }
448
449 #[instrument(skip_all)]
450 fn compute_range_pairs_to_connect(
451 &mut self,
452 one_ring_v_ids1: &[VertexId],
453 one_ring_v_ids2: &[VertexId],
454 shared_v_ids: &HashSet<VertexId>,
455 ) -> Vec<ConnectPair> {
456 let mut range_pairs_to_connect = vec![];
457
458 let mut connected_v_ids = HashSet::new();
459
460 let (orig_start_idx1, orig_start_idx2) = unwrap_or_return!(
461 self.find_start_indices(
462 one_ring_v_ids1,
463 one_ring_v_ids2,
464 shared_v_ids,
465 &connected_v_ids
466 ),
467 "Couldn't find start indices",
468 range_pairs_to_connect
469 );
470
471 tracing::info!(
472 "start idx1: {}, start idx2: {}",
473 orig_start_idx1,
474 orig_start_idx2
475 );
476
477 let len1 = one_ring_v_ids1.len();
478 let len2 = one_ring_v_ids2.len();
479
480 let mut start_idx1 = orig_start_idx1;
481 let mut start_idx2 = orig_start_idx2;
482
483 let mut end_idx1 = (start_idx1 + 1) % len1;
484 let mut end_idx2 = (start_idx2 + 1) % len2;
485
486 #[cfg(feature = "rerun")]
487 {
488 self.log_verts_w_labels_rerun(
489 "pairs_start_idx",
490 &[one_ring_v_ids1[start_idx1], one_ring_v_ids2[start_idx2]],
491 &["1", "2"],
492 );
493 self.log_vert_rerun("pairs_end_idx1", one_ring_v_ids1[end_idx1]);
494 self.log_vert_rerun("pairs_end_idx2", one_ring_v_ids2[end_idx2]);
495 }
496 let mut v_id1;
497 let mut v_id2;
498
499 while end_idx1 != orig_start_idx1 {
500 v_id1 = one_ring_v_ids1[end_idx1];
501 v_id2 = one_ring_v_ids2[end_idx2];
502
503 let mut shared = false;
504
505 if shared_v_ids.contains(&v_id1) {
506 while v_id2 != v_id1 {
507 end_idx2 = (end_idx2 + 1) % len2;
508 v_id2 = one_ring_v_ids2[end_idx2];
509
510 #[cfg(feature = "rerun")]
511 self.log_vert_rerun("pairs_end_idx2", v_id2);
512 }
513
514 shared = true;
515 } else if shared_v_ids.contains(&v_id2) {
516 while v_id1 != v_id2 {
517 end_idx1 = (end_idx1 + 1) % len1;
518 v_id1 = one_ring_v_ids1[end_idx1];
519
520 #[cfg(feature = "rerun")]
521 self.log_vert_rerun("pairs_end_idx1", v_id1);
522 }
523
524 shared = true;
525 }
526
527 if shared {
528 range_pairs_to_connect.push(ConnectPair::new(
529 start_idx1..=end_idx1,
530 len1,
531 start_idx2..=end_idx2,
532 len2,
533 true,
534 ));
535
536 let mut idx = start_idx1;
537 while idx != end_idx1 {
538 connected_v_ids.insert(one_ring_v_ids1[idx]);
539 idx = (idx + 1) % len1;
540 }
541 idx = start_idx2;
542 while idx != end_idx2 {
543 connected_v_ids.insert(one_ring_v_ids2[idx]);
544 idx = (idx + 1) % len2;
545 }
546
547 if let Some((idx1, idx2)) = self.find_start_indices(
548 one_ring_v_ids1,
549 one_ring_v_ids2,
550 shared_v_ids,
551 &connected_v_ids,
552 ) {
553 start_idx1 = idx1;
554 start_idx2 = idx2;
555 } else {
556 return range_pairs_to_connect;
557 }
558
559 end_idx1 = (start_idx1 + 1) % len1;
560 end_idx2 = (start_idx2 + 1) % len2;
561
562 #[cfg(feature = "rerun")]
563 {
564 self.log_verts_w_labels_rerun(
565 "pairs_start_idx",
566 &[one_ring_v_ids1[start_idx1], one_ring_v_ids2[start_idx2]],
567 &["1", "2"],
568 );
569 self.log_vert_rerun("pairs_end_idx1", one_ring_v_ids1[end_idx1]);
570 self.log_vert_rerun("pairs_end_idx2", one_ring_v_ids2[end_idx2]);
571 }
572
573 if start_idx1 == orig_start_idx1 {
574 break;
575 }
576 } else {
577 end_idx1 = (end_idx1 + 1) % len1;
578 end_idx2 = (end_idx2 + 1) % len2;
579
580 #[cfg(feature = "rerun")]
581 {
582 self.log_vert_rerun("pairs_end_idx1", one_ring_v_ids1[end_idx1]);
583 self.log_vert_rerun("pairs_end_idx2", one_ring_v_ids2[end_idx2]);
584 }
585 }
586 }
587
588 let diff1 = (start_idx1 as i32 - end_idx1 as i32).unsigned_abs() as usize;
589 let diff1 = diff1.min(len1 - diff1);
590
591 let diff2 = (start_idx2 as i32 - end_idx2 as i32).unsigned_abs() as usize;
592 let diff2 = diff2.min(len2 - diff2);
593
594 let closed = !shared_v_ids.is_empty();
595
596 if range_pairs_to_connect.is_empty() {
597 let (end1, end2) = if closed {
598 (orig_start_idx1, orig_start_idx2)
599 } else {
600 (
601 (orig_start_idx1 + len1 - 1).rem_euclid(len1),
602 (orig_start_idx2 + len2 - 1).rem_euclid(len2),
603 )
604 };
605
606 range_pairs_to_connect.push(ConnectPair::new(
607 orig_start_idx1..=end1,
608 len1,
609 orig_start_idx2..=end2,
610 len2,
611 closed,
612 ));
613 } else if diff1 > 1 || diff2 > 1 || range_pairs_to_connect.is_empty() {
614 range_pairs_to_connect.push(ConnectPair::new(
615 start_idx1..=end_idx1,
616 len1,
617 start_idx2..=end_idx2,
618 len2,
619 closed,
620 ));
621 }
622
623 #[cfg(feature = "rerun")]
624 {
625 for range_pair in &range_pairs_to_connect {
626 let mut v1s = vec![];
627 let mut v2s = vec![];
628 let mut l1s = vec![];
629 let mut l2s = vec![];
630
631 for i in range_pair.ranges[0].clone() {
632 let v_id = one_ring_v_ids1[i % len1];
633 v1s.push(v_id);
634 l1s.push(format!("{i} - {v_id:?}"));
635 }
636 for i in range_pair.ranges[1].clone() {
637 let v_id = one_ring_v_ids2[i % len2];
638 v2s.push(v_id);
639 l2s.push(format!("{i} - {v_id:?}"));
640 }
641
642 self.log_verts_w_labels_rerun("range_pair_1", &v1s, &l1s);
643 self.log_verts_w_labels_rerun("range_pair_2", &v2s, &l2s);
644 }
645 }
646
647 range_pairs_to_connect
648 }
649
650 #[instrument(skip(self))]
651 fn find_shared_start_indices_from_ring(
652 &self,
653 one_ring_v_ids: &[VertexId],
654 other_one_ring_v_ids: &[VertexId],
655 shared_v_ids: &HashSet<VertexId>,
656 connected_v_ids: &HashSet<VertexId>,
657 ) -> Option<(usize, usize)> {
658 let len = one_ring_v_ids.len();
659
660 for (idx, &v_id1) in one_ring_v_ids.iter().enumerate() {
661 if self.vertices.contains_key(v_id1)
662 && !shared_v_ids.contains(&v_id1)
663 && !connected_v_ids.contains(&v_id1)
664 {
665 let mut start_idx = idx;
666 let mut start_v_id = &v_id1;
667
668 while self.vertices.contains_key(*start_v_id)
669 && !shared_v_ids.contains(start_v_id)
670 && !connected_v_ids.contains(start_v_id)
671 {
672 start_idx = (start_idx + len - 1) % len;
673 start_v_id = &one_ring_v_ids[start_idx];
674
675 if start_idx == idx {
676 return None;
677 }
678 }
679
680 return Some((
681 start_idx,
682 other_one_ring_v_ids
683 .iter()
684 .position(|v_id| start_v_id == v_id)
685 .unwrap(),
686 ));
687 }
688 }
689
690 None
691 }
692
693 #[instrument(skip(self))]
694 fn find_start_indices(
695 &self,
696 one_ring_v_ids1: &[VertexId],
697 one_ring_v_ids2: &[VertexId],
698 shared_v_ids: &HashSet<VertexId>,
699 connected_v_ids: &HashSet<VertexId>,
700 ) -> Option<(usize, usize)> {
701 if !shared_v_ids.is_empty() {
702 if let Some(indices) = self.find_shared_start_indices_from_ring(
703 one_ring_v_ids1,
704 one_ring_v_ids2,
705 shared_v_ids,
706 connected_v_ids,
707 ) {
708 Some(indices)
709 } else if let Some((idx2, idx1)) = self.find_shared_start_indices_from_ring(
710 one_ring_v_ids2,
711 one_ring_v_ids1,
712 shared_v_ids,
713 connected_v_ids,
714 ) {
715 Some((idx1, idx2))
716 } else {
717 None
718 }
719 } else {
720 for (idx1, &v_id1) in one_ring_v_ids1.iter().enumerate() {
721 for (idx2, &v_id2) in one_ring_v_ids2.iter().enumerate() {
722 if self.halfedge_from_to(v_id1, v_id2).is_some() {
723 tracing::info!(
724 "Found common edge between vertices {idx1} (id {v_id1:?}) and {idx2} (id {v_id2:?})"
725 );
726 return Some((idx1, idx2));
727 }
728 }
729 }
730
731 let first_v_id = one_ring_v_ids1[0];
732 let first_pos = *self
733 .positions
734 .get(first_v_id)
735 .or_else(error_none!("Position not found"))?;
736
737 let mut min_dist_sqr = f32::INFINITY;
738 let mut start_idx2 = 0;
739
740 for (idx, v_id) in one_ring_v_ids2.iter().enumerate() {
741 let pos = self
742 .positions
743 .get(*v_id)
744 .or_else(error_none!("Position not found"))?;
745
746 let dist_sqr = pos.distance_squared(first_pos);
747
748 if dist_sqr < min_dist_sqr {
749 min_dist_sqr = dist_sqr;
750 start_idx2 = idx;
751 }
752 }
753
754 Some((0, start_idx2))
755 }
756 }
757}
758
759#[derive(Debug)]
761struct ConnectPair {
762 closed: bool,
764
765 ranges: [RangeInclusive<usize>; 2],
767}
768
769impl ConnectPair {
770 fn new(
771 mut range1: RangeInclusive<usize>,
772 len1: usize,
773 mut range2: RangeInclusive<usize>,
774 len2: usize,
775 closed: bool,
776 ) -> Self {
777 if range1.end() <= range1.start() {
778 range1 = (*range1.start())..=(*range1.end() + len1);
779 }
780 if range2.end() <= range2.start() {
781 range2 = (*range2.start())..=(*range2.end() + len2);
782 }
783
784 ConnectPair {
785 closed,
786 ranges: [range1, range2],
787 }
788 }
789
790 fn compute_pairings(&self) -> Vec<Pairing> {
792 let range1 = self.ranges[0].clone();
793 let range2 = self.ranges[1].clone();
794
795 let count1 = range1.clone().count() as i32;
796 let count2 = range2.clone().count() as i32;
797
798 let (single_range_idx, single_count, other_count, single_range, other_range) =
799 if count1 > count2 {
800 (1, count2, count1, range2, range1)
801 } else {
802 (0, count1, count2, range1, range2)
803 };
804
805 let mut single_idx_in_range = *single_range.start();
806
807 if single_count == 0 {
808 return vec![];
809 }
810 if single_count == 1 {
811 return vec![Pairing {
812 single_range_idx,
813 single_idx_in_range,
814 other_range,
815 }];
816 }
817
818 let mut error = 2 * single_count - other_count;
819
820 let mut other_start = *other_range.start();
821 let mut other_end = other_start;
822
823 let mut pairings = Vec::new();
824
825 while other_end <= *other_range.end() {
826 if error > 0 {
827 pairings.push(Pairing {
828 single_range_idx,
829 single_idx_in_range,
830 other_range: other_start..=other_end,
831 });
832
833 other_start = other_end + 1;
834 single_idx_in_range += 1;
835 error += 2 * (single_count - other_count);
836 } else {
837 error += 2 * single_count;
838 }
839
840 other_end += 1;
841 }
842
843 if let Some(last_pairing) = pairings.last_mut() {
844 last_pairing.other_range = *last_pairing.other_range.start()..=*other_range.end();
845 }
846
847 pairings
848 }
849}
850
851#[derive(Debug)]
853struct Pairing {
854 single_range_idx: usize,
857
858 single_idx_in_range: usize,
860
861 other_range: RangeInclusive<usize>,
863}
864
865impl Pairing {
866 fn first_pair(&self, v_ids: [&[VertexId]; 2]) -> (VertexId, VertexId) {
867 let single_ids = &v_ids[self.single_range_idx];
868 let other_ids = &v_ids[1 - self.single_range_idx];
869
870 let single_v_id = single_ids[self.single_idx_in_range % single_ids.len()];
871 let other_v_id = other_ids[*self.other_range.start() % other_ids.len()];
872
873 (single_v_id, other_v_id)
874 }
875
876 fn last_pair(&self, v_ids: [&[VertexId]; 2]) -> (VertexId, VertexId) {
877 let single_ids = &v_ids[self.single_range_idx];
878 let other_ids = &v_ids[1 - self.single_range_idx];
879
880 let single_v_id = single_ids[self.single_idx_in_range % single_ids.len()];
881 let other_v_id = other_ids[*self.other_range.end() % other_ids.len()];
882
883 (single_v_id, other_v_id)
884 }
885
886 fn fill_faces(&self, v_ids: [&[VertexId]; 2]) -> Vec<PlannedFace> {
887 let single_ids = &v_ids[self.single_range_idx];
888 let other_ids = &v_ids[1 - self.single_range_idx];
889
890 let single_v_id = single_ids[self.single_idx_in_range % single_ids.len()];
891 let mut faces = Vec::<PlannedFace>::new();
892
893 let mut others = self.other_range.clone();
894
895 let mut prev_other_v_id = other_ids[others.next().unwrap() % other_ids.len()];
896 let mut face_order = PlannedFaceOrder::Middle;
897
898 if prev_other_v_id == single_v_id {
899 face_order = PlannedFaceOrder::Start;
900
901 if let Some(second_idx) = others.next() {
902 prev_other_v_id = other_ids[second_idx % other_ids.len()];
903 } else {
904 return faces;
905 }
906 }
907
908 for other_idx in others {
909 let other_v_id = other_ids[other_idx % other_ids.len()];
910
911 if other_v_id == single_v_id {
912 break;
913 }
914
915 if self.single_range_idx == 0 {
917 faces.push(PlannedFace::new(
918 prev_other_v_id,
919 single_v_id,
920 other_v_id,
921 face_order,
922 ));
923 } else {
924 faces.push(PlannedFace::new(
925 prev_other_v_id,
926 other_v_id,
927 single_v_id,
928 face_order,
929 ));
930 }
931
932 face_order = PlannedFaceOrder::Middle;
933 prev_other_v_id = other_v_id;
934 }
935
936 faces
937 }
938}
939
940#[derive(Debug)]
941struct PlannedFace {
942 order: PlannedFaceOrder,
943 v1: VertexId,
944 new_he_v1: VertexId,
945 new_he_v2: VertexId,
946}
947
948#[derive(Debug, Copy, Clone, Eq, PartialEq)]
949enum PlannedFaceOrder {
950 Start,
951 Middle,
952 End,
953 Single,
954}
955
956impl PlannedFace {
957 fn new(
958 v_id1: VertexId,
959 new_he_v_id1: VertexId,
960 new_he_v_id2: VertexId,
961 order: PlannedFaceOrder,
962 ) -> Self {
963 PlannedFace {
964 order,
965 v1: v_id1,
966 new_he_v1: new_he_v_id1,
967 new_he_v2: new_he_v_id2,
968 }
969 }
970
971 #[instrument(skip(mesh_graph))]
972 fn add_to_meshgraph(
973 &self,
974 mesh_graph: &mut MeshGraph,
975 ) -> Option<(Option<HalfedgeId>, AddFace)> {
976 #[cfg(feature = "rerun")]
977 mesh_graph.log_verts_w_labels_rerun(
978 "add_to_meshgraph",
979 &[self.v1, self.new_he_v1, self.new_he_v2],
980 &["1", "2", "3"],
981 );
982
983 let add_or_get_edge = mesh_graph.add_or_get_edge(self.v1, self.new_he_v1);
984
985 let (start_to_end_he_id, twin_he_id) = match self.order {
986 PlannedFaceOrder::Start => {
987 let AddEdge {
988 start_to_end_he_id,
989 twin_he_id,
990 } = mesh_graph.add_edge(self.new_he_v1, self.new_he_v2);
991
992 (start_to_end_he_id, twin_he_id)
993 }
994 PlannedFaceOrder::Single => (
995 mesh_graph.halfedge_from_to(self.new_he_v1, self.new_he_v2)?,
996 mesh_graph.halfedge_from_to(self.new_he_v2, self.new_he_v1)?,
997 ),
998 _ => {
999 error!("Invalid face order {:?}", self.order);
1000 return None;
1001 }
1002 };
1003
1004 let he = mesh_graph
1005 .halfedges
1006 .get(add_or_get_edge.start_to_end_he_id)
1007 .or_else(error_none!("Halfedge not found"))?;
1008
1009 let add_or_get_edge = if he.is_boundary() {
1010 add_or_get_edge
1011 } else {
1012 let AddEdge {
1013 start_to_end_he_id,
1014 twin_he_id,
1015 } = mesh_graph.add_edge(self.v1, self.new_he_v1);
1016
1017 AddOrGetEdge {
1018 start_to_end_he_id,
1019 twin_he_id,
1020 new_start_to_end: true,
1021 new_twin: true,
1022 }
1023 };
1024
1025 let mut add_face = mesh_graph
1026 .add_face_from_halfedges(add_or_get_edge.start_to_end_he_id, start_to_end_he_id)?;
1027
1028 add_face.halfedge_ids.push(start_to_end_he_id);
1029 add_face.halfedge_ids.push(twin_he_id);
1030
1031 if add_or_get_edge.new_start_to_end {
1032 add_face
1033 .halfedge_ids
1034 .push(add_or_get_edge.start_to_end_he_id);
1035 }
1036 if add_or_get_edge.new_twin {
1037 add_face.halfedge_ids.push(add_or_get_edge.twin_he_id);
1038 }
1039
1040 Some((
1041 if matches!(self.order, PlannedFaceOrder::Start) {
1042 Some(twin_he_id)
1043 } else {
1044 None
1045 },
1046 add_face,
1047 ))
1048 }
1049
1050 #[instrument(skip(mesh_graph))]
1051 fn add_to_meshgraph_and_he(
1052 &self,
1053 mesh_graph: &mut MeshGraph,
1054 existing_he_id: HalfedgeId,
1055 ) -> Option<(Option<HalfedgeId>, AddFace)> {
1056 #[cfg(feature = "rerun")]
1057 {
1058 mesh_graph.log_he_rerun("add_meshgraph_and_he", existing_he_id);
1059 mesh_graph.log_verts_w_labels_rerun(
1060 "add_to_meshgraph_and_he",
1061 &[self.v1, self.new_he_v1, self.new_he_v2],
1062 &["1", "2", "3"],
1063 );
1064 }
1065
1066 match self.order {
1067 PlannedFaceOrder::Middle => {
1068 let AddEdge {
1069 start_to_end_he_id,
1070 twin_he_id,
1071 } = mesh_graph.add_edge(self.new_he_v1, self.new_he_v2);
1072
1073 let mut add_face =
1074 mesh_graph.add_face_from_halfedges(existing_he_id, start_to_end_he_id)?;
1075 add_face.halfedge_ids.push(start_to_end_he_id);
1076 add_face.halfedge_ids.push(twin_he_id);
1077
1078 Some((Some(twin_he_id), add_face))
1079 }
1080 PlannedFaceOrder::End => {
1081 let end_he = mesh_graph
1082 .halfedge_from_to(self.new_he_v1, self.new_he_v2)
1083 .or_else(error_none!("Final halfedge not found"))?;
1084
1085 let add_face = mesh_graph.add_face_from_halfedges(existing_he_id, end_he)?;
1086
1087 Some((None, add_face))
1088 }
1089 _ => {
1090 error!("Invalid face order {:?}", self.order);
1091 None
1092 }
1093 }
1094 }
1095}