1use tracing::instrument;
2
3use crate::{FaceId, HalfedgeId, MeshGraph, VertexId, error_none, utils::unwrap_or_return};
4
5impl MeshGraph {
6 #[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 #[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 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 #[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 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}