geop_core_topology/euler/
ker.rs1use crate::{
2 CoedgeId, Model,
3 boundary::{BoundaryIndex, BoundaryType},
4};
5use geop_core_math::{
6 geop_error::{GeopError, GeopResult, WithContext},
7 scalars::Scalar,
8};
9
10impl<S: Scalar> Model<S> {
11 pub fn ker(
19 self: &mut Model<S>,
20 coedge_backward: CoedgeId,
21 coedge_forward: CoedgeId,
22 ) -> GeopResult<()> {
23 let ctx = |e: GeopError| {
24 e.with_context(format!(
25 "Model::ker(coedge_backward={coedge_backward}, coedge_forward={coedge_forward})"
26 ))
27 };
28
29 let cb = self.get_coedge(coedge_backward)?.clone();
30 let ca = self.get_coedge(coedge_forward)?.clone();
31 if ca.edge().with_context(&ctx)? != cb.edge().with_context(&ctx)? {
32 return Err(ctx(GeopError::new(
33 "coedge_backward and coedge_forward must belong to the same edge",
34 )));
35 }
36 if ca.face == cb.face {
37 return Err(ctx(GeopError::new(
38 "coedge_backward and coedge_forward must belong to different faces (use kemr to merge two rings of the same face)",
39 )));
40 }
41
42 let moved_face_id = ca.face;
43 let survivor_face_id = cb.face;
44 let remove_index = self
45 .find_boundary_containing(moved_face_id, coedge_forward)
46 .with_context(&ctx)?;
47 let keep_index = self
48 .find_boundary_containing(survivor_face_id, coedge_backward)
49 .with_context(&ctx)?;
50
51 let detach_vertex = self
58 .coedge_start_vertex_id(coedge_forward)
59 .with_context(&ctx)?;
60
61 let survivor = ca.prev;
62
63 self.coedges.get_mut(&ca.prev).unwrap().next = cb.next;
68 self.coedges.get_mut(&cb.next).unwrap().prev = ca.prev;
69 self.coedges.get_mut(&cb.prev).unwrap().next = ca.next;
70 self.coedges.get_mut(&ca.next).unwrap().prev = cb.prev;
71 self.coedges.remove(&coedge_forward);
72 self.coedges.remove(&coedge_backward);
73 self.edges.remove(&ca.edge().with_context(&ctx)?);
74
75 for c in self.iterate_loop_coedges(survivor).collect::<Vec<_>>() {
78 self.coedges.get_mut(&c).unwrap().face = survivor_face_id;
79 }
80
81 self.faces
86 .get_mut(&survivor_face_id)
87 .unwrap()
88 .set_boundary(keep_index, BoundaryType::Loop(survivor));
89 match remove_index {
90 BoundaryIndex::Outer => {
91 self.get_face_mut(moved_face_id).with_context(&ctx)?.outer =
92 BoundaryType::Vertex(detach_vertex);
93 }
94 BoundaryIndex::Hole(_) => {
95 self.remove_boundary(moved_face_id, remove_index)
96 .with_context(&ctx)?;
97 }
98 }
99
100 Ok(())
101 }
102}