1use glam::Vec3;
2use itertools::Itertools;
3use parry3d::{
4 math::Pose,
5 partitioning::Bvh,
6 query::{
7 PointProjection, PointQuery, PointQueryWithLocation, Ray, RayCast, RayIntersection,
8 details::NormalConstraints,
9 },
10 shape::{CompositeShape, CompositeShapeRef, FeatureId, Shape, Triangle, TypedCompositeShape},
11};
12use tracing::instrument;
13
14use crate::{Face, MeshGraph, error_none, utils::unwrap_or_return};
15
16impl PointQuery for MeshGraph {
17 #[inline]
18 #[instrument(skip(self))]
19 fn project_local_point(&self, point: Vec3, solid: bool) -> PointProjection {
20 self.project_local_point_and_get_location(point, solid).0
21 }
22
23 fn project_local_point_and_get_feature(&self, _point: Vec3) -> (PointProjection, FeatureId) {
24 unimplemented!("Not available")
25 }
26}
27
28impl PointQueryWithLocation for MeshGraph {
29 type Location = Face;
30
31 #[inline]
32 #[instrument(skip(self))]
33 fn project_local_point_and_get_location(
34 &self,
35 point: Vec3,
36 solid: bool,
37 ) -> (PointProjection, Self::Location) {
38 self.project_local_point_and_get_location_with_max_dist(point, solid, f32::MAX)
39 .unwrap()
40 }
41
42 #[instrument(skip(self))]
44 fn project_local_point_and_get_location_with_max_dist(
45 &self,
46 point: Vec3,
47 solid: bool,
48 max_dist: f32,
49 ) -> Option<(PointProjection, Self::Location)> {
50 let (shape_id, (mut proj, _)) =
51 CompositeShapeRef(self).project_local_point_and_get_location(point, max_dist, solid)?;
52
53 let face_id = self
56 .index_to_face_id
57 .get(&shape_id)
58 .or_else(error_none!("Face not found"))?;
59 let face = self
60 .faces
61 .get(*face_id)
62 .or_else(error_none!("Face not found"))?;
63
64 if let Some(vertex_normals) = self.vertex_normals.as_ref() {
65 let he = self
66 .halfedges
67 .get(face.halfedge)
68 .or_else(error_none!("Halfedge not found"))?;
69 let pseudo_normal = vertex_normals
70 .get(he.end_vertex)
71 .or_else(error_none!("Vertex normal not found"))?;
72
73 let dpt = point - proj.point;
74 proj.is_inside =
75 dpt.dot(Vec3::new(pseudo_normal.x, pseudo_normal.y, pseudo_normal.z)) <= 0.0;
76 }
77
78 Some((proj, *face))
79 }
80}
81
82impl RayCast for MeshGraph {
83 #[inline]
84 #[instrument(skip(self))]
85 fn cast_local_ray(&self, ray: &Ray, max_time_of_impact: f32, solid: bool) -> Option<f32> {
86 CompositeShapeRef(self)
87 .cast_local_ray(ray, max_time_of_impact, solid)
88 .map(|hit| hit.1)
89 }
90
91 #[inline]
92 #[instrument(skip(self))]
93 fn cast_local_ray_and_get_normal(
94 &self,
95 ray: &Ray,
96 max_time_of_impact: f32,
97 solid: bool,
98 ) -> Option<RayIntersection> {
99 CompositeShapeRef(self)
100 .cast_local_ray_and_get_normal(ray, max_time_of_impact, solid)
101 .map(|(_, res)| res)
102 }
103}
104
105impl CompositeShape for MeshGraph {
106 #[instrument(skip(self, f))]
107 fn map_part_at(
108 &self,
109 shape_id: u32,
110 f: &mut dyn FnMut(Option<&Pose>, &dyn Shape, Option<&dyn NormalConstraints>),
111 ) {
112 let tri = self.triangle(shape_id);
113 let normal_constraints = Default::default(); f(None, &tri, normal_constraints)
115 }
116
117 fn bvh(&self) -> &Bvh {
118 &self.bvh
119 }
120}
121
122impl TypedCompositeShape for MeshGraph {
123 type PartShape = Triangle;
124 type PartNormalConstraints = ();
125
126 #[instrument(skip(self, f))]
127 fn map_typed_part_at<T>(
128 &self,
129 shape_id: u32,
130 mut f: impl FnMut(Option<&Pose>, &Self::PartShape, Option<&Self::PartNormalConstraints>) -> T,
131 ) -> Option<T> {
132 let tri = self.triangle(shape_id);
133 let pseudo_normals = None; Some(f(None, &tri, pseudo_normals.as_ref()))
135 }
136
137 #[instrument(skip(self, f))]
138 fn map_untyped_part_at<T>(
139 &self,
140 shape_id: u32,
141 mut f: impl FnMut(Option<&Pose>, &dyn Shape, Option<&dyn NormalConstraints>) -> T,
142 ) -> Option<T> {
143 let tri = self.triangle(shape_id);
144 let pseudo_normals = Default::default(); Some(f(None, &tri, pseudo_normals))
146 }
147}
148
149impl MeshGraph {
150 #[instrument(skip(self))]
151 pub fn triangle(&self, shape_id: u32) -> Triangle {
152 let face_id = unwrap_or_return!(
153 self.index_to_face_id.get(&shape_id),
154 "Index not found",
155 Triangle::default()
156 );
157
158 let face = unwrap_or_return!(
159 self.faces.get(*face_id),
160 "Face not found",
161 Triangle::default()
162 );
163
164 let pos = face
165 .vertices(self)
166 .filter_map(|v_id| {
167 self.positions
168 .get(v_id)
169 .or_else(error_none!("Position not found"))
170 })
171 .collect_vec();
172
173 if pos.len() < 3 {
174 return Triangle::default();
175 }
176
177 Triangle::new(
178 Vec3::new(pos[0].x, pos[0].y, pos[0].z),
179 Vec3::new(pos[1].x, pos[1].y, pos[1].z),
180 Vec3::new(pos[2].x, pos[2].y, pos[2].z),
181 )
182 }
183
184 }