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