1use crate::math::{Isometry, Point, Real};
2use crate::shape::FeatureId;
3use na;
4
5#[cfg(feature = "rkyv")]
6use rkyv::{bytecheck, CheckBytes};
7
8#[derive(Copy, Clone, Debug, Default)]
10#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11#[cfg_attr(
12 feature = "rkyv",
13 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
14 archive(as = "Self")
15)]
16pub struct PointProjection {
17 pub is_inside: bool,
19 pub point: Point<Real>,
21}
22
23impl PointProjection {
24 pub fn new(is_inside: bool, point: Point<Real>) -> Self {
26 PointProjection { is_inside, point }
27 }
28
29 pub fn transform_by(&self, pos: &Isometry<Real>) -> Self {
31 PointProjection {
32 is_inside: self.is_inside,
33 point: pos * self.point,
34 }
35 }
36
37 pub fn is_inside_eps(&self, original_point: &Point<Real>, min_dist: Real) -> bool {
39 self.is_inside || na::distance_squared(original_point, &self.point) < min_dist * min_dist
40 }
41}
42
43pub trait PointQuery {
45 fn project_local_point_with_max_dist(
49 &self,
50 pt: &Point<Real>,
51 solid: bool,
52 max_dist: Real,
53 ) -> Option<PointProjection> {
54 let proj = self.project_local_point(pt, solid);
55 if na::distance(&proj.point, pt) > max_dist {
56 None
57 } else {
58 Some(proj)
59 }
60 }
61
62 fn project_point_with_max_dist(
64 &self,
65 m: &Isometry<Real>,
66 pt: &Point<Real>,
67 solid: bool,
68 max_dist: Real,
69 ) -> Option<PointProjection> {
70 self.project_local_point_with_max_dist(&m.inverse_transform_point(pt), solid, max_dist)
71 .map(|proj| proj.transform_by(m))
72 }
73
74 fn project_local_point(&self, pt: &Point<Real>, solid: bool) -> PointProjection;
78
79 fn project_local_point_and_get_feature(&self, pt: &Point<Real>)
82 -> (PointProjection, FeatureId);
83
84 fn distance_to_local_point(&self, pt: &Point<Real>, solid: bool) -> Real {
86 let proj = self.project_local_point(pt, solid);
87 let dist = na::distance(pt, &proj.point);
88
89 if solid || !proj.is_inside {
90 dist
91 } else {
92 -dist
93 }
94 }
95
96 fn contains_local_point(&self, pt: &Point<Real>) -> bool {
98 self.project_local_point(pt, true).is_inside
99 }
100
101 fn project_point(&self, m: &Isometry<Real>, pt: &Point<Real>, solid: bool) -> PointProjection {
103 self.project_local_point(&m.inverse_transform_point(pt), solid)
104 .transform_by(m)
105 }
106
107 #[inline]
109 fn distance_to_point(&self, m: &Isometry<Real>, pt: &Point<Real>, solid: bool) -> Real {
110 self.distance_to_local_point(&m.inverse_transform_point(pt), solid)
111 }
112
113 fn project_point_and_get_feature(
116 &self,
117 m: &Isometry<Real>,
118 pt: &Point<Real>,
119 ) -> (PointProjection, FeatureId) {
120 let res = self.project_local_point_and_get_feature(&m.inverse_transform_point(pt));
121 (res.0.transform_by(m), res.1)
122 }
123
124 #[inline]
126 fn contains_point(&self, m: &Isometry<Real>, pt: &Point<Real>) -> bool {
127 self.contains_local_point(&m.inverse_transform_point(pt))
128 }
129}
130
131pub trait PointQueryWithLocation {
146 type Location;
153
154 fn project_local_point_and_get_location(
156 &self,
157 pt: &Point<Real>,
158 solid: bool,
159 ) -> (PointProjection, Self::Location);
160
161 fn project_point_and_get_location(
163 &self,
164 m: &Isometry<Real>,
165 pt: &Point<Real>,
166 solid: bool,
167 ) -> (PointProjection, Self::Location) {
168 let res = self.project_local_point_and_get_location(&m.inverse_transform_point(pt), solid);
169 (res.0.transform_by(m), res.1)
170 }
171
172 fn project_local_point_and_get_location_with_max_dist(
174 &self,
175 pt: &Point<Real>,
176 solid: bool,
177 max_dist: Real,
178 ) -> Option<(PointProjection, Self::Location)> {
179 let (proj, location) = self.project_local_point_and_get_location(pt, solid);
180 if na::distance(&proj.point, pt) > max_dist {
181 None
182 } else {
183 Some((proj, location))
184 }
185 }
186
187 fn project_point_and_get_location_with_max_dist(
189 &self,
190 m: &Isometry<Real>,
191 pt: &Point<Real>,
192 solid: bool,
193 max_dist: Real,
194 ) -> Option<(PointProjection, Self::Location)> {
195 self.project_local_point_and_get_location_with_max_dist(
196 &m.inverse_transform_point(pt),
197 solid,
198 max_dist,
199 )
200 .map(|res| (res.0.transform_by(m), res.1))
201 }
202}