parry3d/query/point/
point_voxels.rs

1use crate::math::{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: Vector, 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(false, Vector::splat(Real::MAX)))
17    }
18
19    #[inline]
20    fn project_local_point_and_get_feature(&self, pt: Vector) -> (PointProjection, FeatureId) {
21        self.chunk_bvh()
22            .project_point_and_get_feature(pt, Real::MAX, |chunk_id, _| {
23                let chunk = self.chunk_ref(chunk_id);
24                // TODO: we need a way to return both the voxel id, and the feature on the voxel.
25                chunk
26                    .project_local_point_and_get_vox_id(pt, false)
27                    .map(|(proj, vox)| (proj, FeatureId::Face(vox)))
28            })
29            .map(|res| res.1 .1)
30            .unwrap_or((
31                PointProjection::new(false, Vector::splat(Real::MAX)),
32                FeatureId::Unknown,
33            ))
34    }
35}
36
37impl<'a> VoxelsChunkRef<'a> {
38    #[inline]
39    fn project_local_point_and_get_vox_id(
40        &self,
41        pt: Vector,
42        solid: bool,
43    ) -> Option<(PointProjection, u32)> {
44        // TODO: optimize this naive implementation that just iterates on all the voxels
45        //       from this chunk.
46        let base_cuboid = Cuboid::new(self.parent.voxel_size() / 2.0);
47        let mut smallest_dist = Real::MAX;
48        let mut result = PointProjection::new(false, pt);
49        let mut result_vox_id = 0;
50
51        for vox in self.voxels() {
52            let mut candidate = base_cuboid.project_local_point(pt - vox.center, solid);
53            candidate.point += vox.center;
54
55            let candidate_dist = (candidate.point - pt).length();
56            if candidate_dist < smallest_dist {
57                result = candidate;
58                result_vox_id = vox.linear_id.flat_id();
59                smallest_dist = candidate_dist;
60            }
61        }
62
63        (smallest_dist < Real::MAX).then_some((result, result_vox_id as u32))
64    }
65}