Skip to main content

mesh_graph/ops/add/
edge.rs

1use tracing::{error, instrument};
2
3use crate::{Halfedge, HalfedgeId, MeshGraph, VertexId, error_none};
4
5impl MeshGraph {
6    /// Inserts a pair of halfedges and connects them to the given vertices (from and to the halfedge) and each other as twins.
7    /// If the edge already exists or partially exists,
8    /// it returns the existing edge while creating any missing halfedges.
9    ///
10    /// See also [`add_edge`].
11    #[instrument(skip(self))]
12    pub fn add_or_get_edge(
13        &mut self,
14        start_vertex_id: VertexId,
15        end_vertex_id: VertexId,
16    ) -> Option<AddOrGetEdge> {
17        let ret = match self.add_or_get_edge_inner(start_vertex_id, end_vertex_id) {
18            Some(ret) => ret,
19            None => {
20                let start_to_end_he_id = self.add_halfedge(start_vertex_id, end_vertex_id)?;
21                let twin_he_id = self.add_halfedge(end_vertex_id, start_vertex_id)?;
22
23                AddOrGetEdge {
24                    start_to_end_he_id,
25                    twin_he_id,
26                    new_start_to_end: true,
27                    new_twin: true,
28                }
29            }
30        };
31
32        // insert_or_get_edge_inner ensures that both halfedges exist.
33        self.halfedges[ret.start_to_end_he_id].twin = Some(ret.twin_he_id);
34        self.halfedges[ret.twin_he_id].twin = Some(ret.start_to_end_he_id);
35
36        let start_v = self
37            .vertices
38            .get_mut(start_vertex_id)
39            .or_else(error_none!("Vertex not found"))?;
40        start_v.outgoing_halfedge = Some(ret.start_to_end_he_id);
41
42        let end_v = self
43            .vertices
44            .get_mut(end_vertex_id)
45            .or_else(error_none!("Vertex not found"))?;
46        end_v.outgoing_halfedge = Some(ret.twin_he_id);
47
48        Some(ret)
49    }
50
51    /// Adds or gets a boundary edge between two vertices.
52    /// If the edge already exists and the halfedge (start_vertex_id, end_vertex_id) is a boundary halfedge, it is returned;
53    /// otherwise, a new halfedge pair is created.
54    ///
55    /// Note that this can lead to duplicate halfedges if the edge already exists but is not a boundary edge.
56    pub fn add_or_get_boundary_edge(
57        &mut self,
58        start_vertex_id: VertexId,
59        end_vertex_id: VertexId,
60    ) -> Option<AddOrGetEdge> {
61        let existing_he_ids = self.halfedges_from_to(start_vertex_id, end_vertex_id);
62        if let Some(he_id) = existing_he_ids.into_iter().find(|he_id| {
63            // already checked in `halfedges_from_to()`
64            let he = &self.halfedges[*he_id];
65            he.is_boundary() && he.twin.is_some()
66        }) {
67            // already checked in `halfedges_from_to()`
68            let he = self.halfedges[he_id];
69
70            return Some(AddOrGetEdge {
71                start_to_end_he_id: he_id,
72                twin_he_id: he.twin.unwrap(), // checked above
73                new_start_to_end: false,
74                new_twin: false,
75            });
76        }
77
78        let AddEdge {
79            start_to_end_he_id,
80            twin_he_id,
81        } = self.add_edge(start_vertex_id, end_vertex_id)?;
82
83        Some(AddOrGetEdge {
84            start_to_end_he_id,
85            twin_he_id,
86            new_start_to_end: true,
87            new_twin: true,
88        })
89    }
90
91    fn add_or_get_edge_inner(
92        &mut self,
93        start_vertex_id: VertexId,
94        end_vertex_id: VertexId,
95    ) -> Option<AddOrGetEdge> {
96        let mut he1_id = self.halfedge_from_to(start_vertex_id, end_vertex_id);
97        let mut he2_id = self.halfedge_from_to(end_vertex_id, start_vertex_id);
98        let mut new1 = false;
99        let mut new2 = false;
100
101        match (he1_id, he2_id) {
102            (Some(h1_id), Some(h2_id)) => {
103                let h1 = self
104                    .halfedges
105                    .get(h1_id)
106                    .or_else(error_none!("Halfedge not found"))?;
107
108                let h2 = self
109                    .halfedges
110                    .get(h2_id)
111                    .or_else(error_none!("Halfedge not found"))?;
112
113                if h1.twin != Some(h2_id) || h2.twin != Some(h1_id) {
114                    error!("Halfedge twins are not consistent.");
115                }
116            }
117            (Some(_h1_id), None) => {
118                he2_id = Some(self.add_halfedge(end_vertex_id, start_vertex_id)?);
119                new2 = true;
120            }
121            (None, Some(_h2_id)) => {
122                he1_id = Some(self.add_halfedge(start_vertex_id, end_vertex_id)?);
123                new1 = true;
124            }
125            (None, None) => {
126                // the outer method will handle this case
127                return None;
128            }
129        }
130
131        // we just made sure that h1_id and h2_id are Some(_)
132        let start_to_end_he_id = he1_id.unwrap();
133        let twin_he_id = he2_id.unwrap();
134
135        Some(AddOrGetEdge {
136            start_to_end_he_id,
137            twin_he_id,
138            new_start_to_end: new1,
139            new_twin: new2,
140        })
141    }
142
143    /// Inserts a pair of halfedges and connects them to the given vertices (from and to the halfedge) and each other as twins.
144    /// This creates two halfedges wether the vertices already have an edge between them or not.
145    ///
146    /// If you don't want this, consider using [`add_or_get_edge`] instead.
147    pub fn add_edge(&mut self, start_vertex: VertexId, end_vertex: VertexId) -> Option<AddEdge> {
148        let start_to_end_he_id = self.add_halfedge(start_vertex, end_vertex)?;
149        let twin_he_id = self.add_halfedge(end_vertex, start_vertex)?;
150
151        // Just inserted above
152        self.halfedges[start_to_end_he_id].twin = Some(twin_he_id);
153        self.halfedges[twin_he_id].twin = Some(start_to_end_he_id);
154
155        // Vertex existence already checked in `add_halfedge`
156        self.vertices[start_vertex].outgoing_halfedge = Some(start_to_end_he_id);
157        self.vertices[end_vertex].outgoing_halfedge = Some(twin_he_id);
158
159        Some(AddEdge {
160            start_to_end_he_id,
161            twin_he_id,
162        })
163    }
164
165    /// Inserts a halfedge into the mesh graph. It only connects the halfedge to the given end vertex but not the reverse.
166    /// It also doesn't do any other connections.
167    ///
168    /// It does insert into `self.outgoing_halfedges`.
169    ///
170    /// Use [`insert_or_get_edge`] instead of this when you can to lower the chance of creating an invalid graph.
171    #[instrument(skip(self))]
172    pub fn add_halfedge(
173        &mut self,
174        start_vertex: VertexId,
175        end_vertex: VertexId,
176    ) -> Option<HalfedgeId> {
177        let halfedge = Halfedge {
178            end_vertex,
179            next: None,
180            twin: None,
181            face: None,
182        };
183        let he_id = self.halfedges.insert(halfedge);
184
185        self.outgoing_halfedges
186            .entry(start_vertex)
187            .or_else(error_none!("Start vertex not found {start_vertex:?}"))?
188            .or_default()
189            .push(he_id);
190
191        Some(he_id)
192    }
193}
194
195/// Return value of `add_or_get_edge`
196pub struct AddOrGetEdge {
197    /// Id of the halfedge from start vertex to end vertex
198    pub start_to_end_he_id: HalfedgeId,
199    /// Id of the halfedge from end vertex to start vertex
200    pub twin_he_id: HalfedgeId,
201    /// Whether the halfedge from start vertex to end vertex was newly created
202    pub new_start_to_end: bool,
203    /// Whether the halfedge from end vertex to start vertex was newly created
204    pub new_twin: bool,
205}
206
207impl AddOrGetEdge {
208    /// Return the ids of the newly created halfedges
209    pub fn created_he_ids(&self) -> Vec<HalfedgeId> {
210        let mut he_ids = vec![];
211        if self.new_start_to_end {
212            he_ids.push(self.start_to_end_he_id);
213        }
214        if self.new_twin {
215            he_ids.push(self.twin_he_id);
216        }
217        he_ids
218    }
219}
220
221/// Return value of `add_edge`
222pub struct AddEdge {
223    /// Id of the halfedge from start vertex to end vertex
224    pub start_to_end_he_id: HalfedgeId,
225    /// Id of the halfedge from end vertex to start vertex
226    pub twin_he_id: HalfedgeId,
227}