geop_core_topology/edit/merge_edge.rs
1use crate::{CoedgeGeometry, EdgeId, Model};
2use geop_core_math::geop_error::{GeopError, GeopResult};
3
4impl Model {
5 /// Merges `edge_deleted_id` into `edge_into_id`: repoints every coedge
6 /// tracing the deleted edge to the surviving one, then drops the
7 /// now-unreferenced edge. `reversed` says whether the deleted edge ran
8 /// start<->end the *other* way round relative to the surviving one — if
9 /// so, every repointed coedge's `sense` is flipped so it keeps tracing
10 /// the same physical direction it always did.
11 ///
12 /// TODO: `edge_into_id`'s own curve currently stays exactly as it was —
13 /// it should instead be widened (unioned) to certainly contain the
14 /// deleted edge's curve too, so the kept edge's geometry honestly
15 /// reflects both original edges' combined tolerance instead of silently
16 /// favoring whichever one happened to survive.
17 pub fn merge_edge(
18 &mut self,
19 edge_into_id: EdgeId,
20 edge_deleted_id: EdgeId,
21 reversed: bool,
22 ) -> GeopResult<()> {
23 // Same self-merge hazard as `merge_vertex` — always a caller bug
24 // (typically: acting on a stale edge snapshot), rejected rather than
25 // silently absorbed.
26 if edge_into_id == edge_deleted_id {
27 return Err(GeopError::new(format!(
28 "Model::merge_edge: edge_into_id and edge_deleted_id are both {edge_into_id} — refusing to merge an edge into itself"
29 )));
30 }
31
32 // Only the coedges of the deleted edge are touched, so that a model
33 // sharing its arenas with a copy copies only those.
34 for id in self.coedges_of_edge(edge_deleted_id) {
35 let coedge = self.get_coedge_mut(id)?;
36 coedge.geometry = CoedgeGeometry::Edge(edge_into_id);
37 if reversed {
38 coedge.sense = coedge.sense.opposite();
39 }
40 }
41
42 self.edges.remove(&edge_deleted_id);
43
44 Ok(())
45 }
46}