parry3d/query/point/
point_voxels.rs1use crate::math::{Point, Real, Vector};
2use crate::query::{PointProjection, PointQuery};
3use crate::shape::{Cuboid, FeatureId, Voxels, VoxelsChunkRef};
4
5impl PointQuery for Voxels {
6    #[inline]
7    fn project_local_point(&self, pt: &Point<Real>, solid: bool) -> PointProjection {
8        self.chunk_bvh()
9            .project_point(pt, Real::MAX, |chunk_id, _| {
10                let chunk = self.chunk_ref(chunk_id);
11                chunk
12                    .project_local_point_and_get_vox_id(pt, solid)
13                    .map(|(proj, _)| proj)
14            })
15            .map(|res| res.1 .1)
16            .unwrap_or(PointProjection::new(
17                false,
18                Vector::repeat(Real::MAX).into(),
19            ))
20    }
21
22    #[inline]
23    fn project_local_point_and_get_feature(
24        &self,
25        pt: &Point<Real>,
26    ) -> (PointProjection, FeatureId) {
27        self.chunk_bvh()
28            .project_point_and_get_feature(pt, Real::MAX, |chunk_id, _| {
29                let chunk = self.chunk_ref(chunk_id);
30                chunk
32                    .project_local_point_and_get_vox_id(pt, false)
33                    .map(|(proj, vox)| (proj, FeatureId::Face(vox)))
34            })
35            .map(|res| res.1 .1)
36            .unwrap_or((
37                PointProjection::new(false, Vector::repeat(Real::MAX).into()),
38                FeatureId::Unknown,
39            ))
40    }
41}
42
43impl<'a> VoxelsChunkRef<'a> {
44    #[inline]
45    fn project_local_point_and_get_vox_id(
46        &self,
47        pt: &Point<Real>,
48        solid: bool,
49    ) -> Option<(PointProjection, u32)> {
50        let base_cuboid = Cuboid::new(self.parent.voxel_size() / 2.0);
53        let mut smallest_dist = Real::MAX;
54        let mut result = PointProjection::new(false, *pt);
55        let mut result_vox_id = 0;
56
57        for vox in self.voxels() {
58            let mut candidate = base_cuboid.project_local_point(&(pt - vox.center.coords), solid);
59            candidate.point += vox.center.coords;
60
61            let candidate_dist = (candidate.point - pt).norm();
62            if candidate_dist < smallest_dist {
63                result = candidate;
64                result_vox_id = vox.linear_id.flat_id();
65                smallest_dist = candidate_dist;
66            }
67        }
68
69        (smallest_dist < Real::MAX).then_some((result, result_vox_id as u32))
70    }
71}