mesh_graph/elements/
face.rs1use glam::Vec3;
2use itertools::Itertools;
3use parry3d::bounding_volume::Aabb;
4use tracing::{error, instrument};
5
6use crate::{CircularHalfedgesIterator, MeshGraph, error_none};
7
8use super::{FaceId, HalfedgeId, VertexId};
9
10#[derive(Default, Debug, Clone, Copy)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct Face {
13 pub halfedge: HalfedgeId,
16
17 pub index: u32,
19
20 pub id: FaceId,
22}
23
24impl Face {
25 #[instrument(skip(mesh_graph))]
27 pub fn halfedges<'a>(&self, mesh_graph: &'a MeshGraph) -> CircularHalfedgesIterator<'a> {
28 CircularHalfedgesIterator::new(
29 Some(self.halfedge),
30 mesh_graph,
31 |he, mesh_graph| {
32 mesh_graph
33 .halfedges
34 .get(he)
35 .or_else(error_none!("Halfedge not found"))?
36 .next
37 },
38 3,
39 )
40 }
41
42 #[instrument(skip(mesh_graph))]
44 pub fn vertices(&self, mesh_graph: &MeshGraph) -> impl Iterator<Item = VertexId> {
45 self.halfedges(mesh_graph).filter_map(|he| {
46 mesh_graph
47 .halfedges
48 .get(he)
49 .or_else(error_none!("Halfedge not found"))
50 .map(|he| he.end_vertex)
51 })
52 }
53
54 #[instrument(skip(mesh_graph))]
56 pub fn center(&self, mesh_graph: &MeshGraph) -> Vec3 {
57 self.vertex_positions(mesh_graph).sum::<Vec3>() / 3.0
58 }
59
60 #[instrument(skip(mesh_graph))]
62 pub fn aabb(&self, mesh_graph: &MeshGraph) -> Aabb {
63 Aabb::from_points(
64 self.vertex_positions(mesh_graph)
65 .map(|p| Vec3::new(p.x, p.y, p.z)),
66 )
67 }
68
69 #[instrument(skip(mesh_graph))]
71 pub fn vertex_positions(&self, mesh_graph: &MeshGraph) -> impl Iterator<Item = Vec3> {
72 self.vertices(mesh_graph).filter_map(|v| {
73 mesh_graph
74 .positions
75 .get(v)
76 .or_else(error_none!("Position not found"))
77 .copied()
78 })
79 }
80
81 #[instrument(skip(mesh_graph))]
83 pub fn normal(&self, mesh_graph: &MeshGraph) -> Option<Vec3> {
84 let positions = self.vertex_positions(mesh_graph).collect_vec();
85
86 if positions.len() < 3 {
87 error!("Face has less than 3 vertex positions");
88 return None;
89 }
90
91 Some(Self::normal_from_positions(&positions))
92 }
93
94 #[inline]
95 pub fn normal_from_positions(positions: &[Vec3]) -> Vec3 {
96 let a = positions[1] - positions[0];
97 let b = positions[2] - positions[0];
98
99 a.cross(b).normalize()
100 }
101
102 #[instrument(skip(mesh_graph))]
104 pub fn is_degenerate(&self, mesh_graph: &MeshGraph, epsilon_sqr: f32) -> bool {
105 let positions = self.vertex_positions(mesh_graph).collect_vec();
106
107 if positions.len() < 3 {
108 error!("Face has less than 3 vertex positions");
109 return true;
110 }
111
112 let p0 = positions[0];
113 let p1 = positions[1];
114 let p2 = positions[2];
115
116 if p0.distance_squared(p1) < epsilon_sqr
118 || p0.distance_squared(p2) < epsilon_sqr
119 || p1.distance_squared(p2) < epsilon_sqr
120 {
121 return true;
122 }
123
124 let a = p1 - p0;
126 let b = p2 - p0;
127 let cross = a.cross(b);
128
129 cross.length_squared() < epsilon_sqr
131 }
132
133 #[instrument(skip(mesh_graph))]
134 pub fn halfedge_between(
135 &self,
136 vertex_id1: VertexId,
137 vertex_id2: VertexId,
138 mesh_graph: &MeshGraph,
139 ) -> Option<HalfedgeId> {
140 for he_id in self.halfedges(mesh_graph) {
141 let he = mesh_graph
142 .halfedges
143 .get(he_id)
144 .or_else(error_none!("Halfedge not found"))?;
145
146 if he.end_vertex == vertex_id1 || he.end_vertex == vertex_id2 {
147 let prev_he_id = he
148 .prev(mesh_graph)
149 .or_else(error_none!("Prev halfedge not found"))?;
150 let prev_he = mesh_graph
151 .halfedges
152 .get(prev_he_id)
153 .or_else(error_none!("Halfedge not found"))?;
154
155 if prev_he.end_vertex == vertex_id1 || prev_he.end_vertex == vertex_id2 {
156 return Some(he_id);
157 }
158 }
159 }
160
161 None
162 }
163}