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 fn project_local_point(&self, point: &Point<f32>, solid: bool) -> PointProjection {
18 self.project_local_point_and_get_location(point, solid).0
19 }
20
21 fn project_local_point_and_get_feature(
22 &self,
23 _point: &Point<f32>,
24 ) -> (PointProjection, FeatureId) {
25 unimplemented!("Not available")
26 }
27}
28
29impl PointQueryWithLocation for MeshGraph {
30 type Location = Face;
31
32 #[inline]
33 fn project_local_point_and_get_location(
34 &self,
35 point: &Point<f32>,
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 fn project_local_point_and_get_location_with_max_dist(
44 &self,
45 point: &Point<f32>,
46 solid: bool,
47 max_dist: f32,
48 ) -> Option<(PointProjection, Self::Location)> {
49 let (shape_id, (mut proj, _)) =
50 CompositeShapeRef(self).project_local_point_and_get_location(point, max_dist, solid)?;
51
52 let face_id = self
55 .index_to_face_id
56 .get(shape_id as usize)
57 .or_else(error_none!("Face not found"))?;
58 let face = self
59 .faces
60 .get(*face_id)
61 .or_else(error_none!("Face not found"))?;
62
63 let vertex_normals = self.vertex_normals.as_ref()?;
64 let he = self
65 .halfedges
66 .get(face.halfedge)
67 .or_else(error_none!("Halfedge not found"))?;
68 let pseudo_normal = vertex_normals
69 .get(he.end_vertex)
70 .or_else(error_none!("Vertex normal not found"))?;
71
72 let dpt = point - proj.point;
73 proj.is_inside = dpt.dot(&Vector::new(
74 pseudo_normal.x,
75 pseudo_normal.y,
76 pseudo_normal.z,
77 )) <= 0.0;
78
79 Some((proj, *face))
80 }
81}
82
83impl RayCast for MeshGraph {
84 #[inline]
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 fn cast_local_ray_and_get_normal(
93 &self,
94 ray: &Ray,
95 max_time_of_impact: f32,
96 solid: bool,
97 ) -> Option<RayIntersection> {
98 CompositeShapeRef(self)
99 .cast_local_ray_and_get_normal(ray, max_time_of_impact, solid)
100 .map(|(_, res)| res)
101 }
102}
103
104impl CompositeShape for MeshGraph {
105 fn map_part_at(
106 &self,
107 shape_id: u32,
108 f: &mut dyn FnMut(Option<&Isometry<f32>>, &dyn Shape, Option<&dyn NormalConstraints>),
109 ) {
110 let tri = self.triangle(shape_id);
111 let normal_constraints = Default::default(); f(None, &tri, normal_constraints)
113 }
114
115 fn bvh(&self) -> &Bvh {
116 &self.bvh
117 }
118}
119
120impl TypedCompositeShape for MeshGraph {
121 type PartShape = Triangle;
122 type PartNormalConstraints = ();
123
124 fn map_typed_part_at<T>(
125 &self,
126 shape_id: u32,
127 mut f: impl FnMut(
128 Option<&Isometry<f32>>,
129 &Self::PartShape,
130 Option<&Self::PartNormalConstraints>,
131 ) -> T,
132 ) -> Option<T> {
133 let tri = self.triangle(shape_id);
134 let pseudo_normals = None; Some(f(None, &tri, pseudo_normals.as_ref()))
136 }
137
138 fn map_untyped_part_at<T>(
139 &self,
140 shape_id: u32,
141 mut f: impl FnMut(Option<&Isometry<f32>>, &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 as usize),
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 Point::new(pos[0].x, pos[0].y, pos[0].z),
179 Point::new(pos[1].x, pos[1].y, pos[1].z),
180 Point::new(pos[2].x, pos[2].y, pos[2].z),
181 )
182 }
183
184 }