Skip to main content

mesh_graph/
access.rs

1use tracing::instrument;
2
3use crate::{FaceId, HalfedgeId, MeshGraph, VertexId, error_none, utils::unwrap_or_return};
4
5impl MeshGraph {
6    /// Return the halfedge or it's twin depending on which one is boundary, or `None` if both are not boundary.
7    #[instrument(skip(self))]
8    pub fn boundary_he(&self, he_id: HalfedgeId) -> Option<HalfedgeId> {
9        let he = *self
10            .halfedges
11            .get(he_id)
12            .or_else(error_none!("Halfedge not found"))?;
13
14        if he.is_boundary() {
15            return Some(he_id);
16        }
17
18        let twin_id = he.twin.or_else(error_none!("Twin missing"))?;
19
20        let twin_he = self
21            .halfedges
22            .get(twin_id)
23            .or_else(error_none!("Twin not found"))?;
24
25        if twin_he.is_boundary() {
26            return Some(twin_id);
27        }
28
29        None
30    }
31
32    /// Returns the vertex order of the boundary halfedge between two vertices.
33    /// Useful when adding faces on boundaries.
34    ///
35    /// If the edge is not boundary, it always returns `[v_id2, v_id1]`.
36    #[instrument(skip(self))]
37    pub fn boundary_vertex_order(&mut self, v_id1: VertexId, v_id2: VertexId) -> [VertexId; 2] {
38        let he_id = unwrap_or_return!(
39            self.halfedge_from_to(v_id1, v_id2),
40            "Couldn't find halfedge between {v_id1:?} and {v_id2:?}",
41            [v_id1, v_id2]
42        );
43
44        // already checked that the halfedge exists in `halfedge_from_to()`
45        let he = self.halfedges[he_id];
46
47        if he.is_boundary() {
48            [v_id1, v_id2]
49        } else {
50            [v_id2, v_id1]
51        }
52    }
53
54    /// Returns the halfedge from the start vertex to the end vertex, if it exists. `None` otherwise.
55    #[instrument(skip(self))]
56    pub fn halfedge_from_to(
57        &self,
58        start_vertex_id: VertexId,
59        end_vertex_id: VertexId,
60    ) -> Option<HalfedgeId> {
61        let out_hes = self
62            .outgoing_halfedges
63            .get(start_vertex_id)
64            .or_else(error_none!("Start vertex not found"))?;
65
66        out_hes.iter().copied().find(|he_id| {
67            self.halfedges
68                .get(*he_id)
69                .is_some_and(|he| he.end_vertex == end_vertex_id)
70        })
71    }
72
73    /// Returns the face with the given vertices, if it exists. `None` otherwise.
74    pub fn face_with_vertices(
75        &self,
76        v_id1: VertexId,
77        v_id2: VertexId,
78        v_id3: VertexId,
79    ) -> Option<FaceId> {
80        let he_id = self.halfedge_from_to(v_id1, v_id2)?;
81        let he = self
82            .halfedges
83            .get(he_id)
84            .or_else(error_none!("Halfedge not found"))?;
85
86        if Some(v_id3) == he.opposite_vertex(self) {
87            return he.face.or_else(error_none!("No face"));
88        }
89
90        let twin_id = he.twin.or_else(error_none!("No twin"))?;
91        let twin = self
92            .halfedges
93            .get(twin_id)
94            .or_else(error_none!("Twin not found"))?;
95
96        if Some(v_id3) == twin.opposite_vertex(self) {
97            return twin.face.or_else(error_none!("No face"));
98        }
99
100        None
101    }
102}