bevy_rapier3d/geometry/shape_views/
voxels.rs

1use rapier::prelude::{Aabb, VoxelData, VoxelState, Voxels};
2
3use crate::math::{IVect, Vect};
4
5#[cfg(feature = "dim2")]
6use bevy::math::bounding::Aabb2d as BevyAabb;
7#[cfg(feature = "dim3")]
8use bevy::math::bounding::Aabb3d as BevyAabb;
9
10fn aabb_na_from_bevy(aabb: &BevyAabb) -> Aabb {
11    rapier::parry::bounding_volume::Aabb::new(aabb.min.into(), aabb.max.into())
12}
13
14fn aabb_bevy_from_na(aabb: &Aabb) -> BevyAabb {
15    BevyAabb {
16        min: aabb.mins.into(),
17        max: aabb.maxs.into(),
18    }
19}
20
21/// Read-only access to the properties of a [`Voxels`] shape.
22#[derive(Copy, Clone)]
23pub struct VoxelsView<'a> {
24    /// The raw shape from Rapier.
25    pub raw: &'a Voxels,
26}
27
28// TODO: implement those on VoxelsViewMut too.
29macro_rules! impl_ref_methods(
30    ($View: ident) => {
31        impl<'a> $View<'a> {
32            /// Shortcut to [`Voxels::total_memory_size`].
33            pub fn total_memory_size(&self) -> usize {
34                self.raw.total_memory_size()
35            }
36
37            /// Shortcut to [`Voxels::heap_memory_size`].
38            pub fn heap_memory_size(&self) -> usize {
39                self.raw.heap_memory_size()
40            }
41
42            /// Shortcut to [`Voxels::local_aabb`].
43            pub fn extents(&self) -> Vect {
44                self.raw.local_aabb().extents().into()
45            }
46
47            /// Shortcut to [`Voxels::local_aabb`].
48            pub fn domain_center(&self) -> Vect {
49                self.raw.local_aabb().center().coords.into()
50            }
51
52            /// Shortcut to [`Voxels::domain`].
53            pub fn is_voxel_in_bounds(&self, key: IVect) -> bool {
54                let [mins, maxs] = self.raw.domain();
55                #[cfg(feature = "dim2")]
56                {
57                    key.x >= mins.x && key.y >= mins.y && key.x < maxs.x && key.y < maxs.y
58                }
59                #[cfg(feature = "dim3")]
60                {
61                    key.x >= mins.x
62                        && key.y >= mins.y
63                        && key.z >= mins.z
64                        && key.x < maxs.x
65                        && key.y < maxs.y
66                        && key.z < maxs.z
67                }
68            }
69
70            /// Shortcut to [`Voxels::voxel_aabb`].
71            pub fn voxel_aabb(&self, key: IVect) -> BevyAabb {
72                aabb_bevy_from_na(&self.raw.voxel_aabb(key.into()))
73            }
74
75            /// Shortcut to [`Voxels::voxel_state`].
76            pub fn voxel_state(&self, key: IVect) -> Option<VoxelState> {
77                self.raw.voxel_state(key.into())
78            }
79
80            /// Shortcut to [`Voxels::voxel_at_point`].
81            pub fn voxel_at_point_unchecked(&self, point: Vect) -> IVect {
82                let p = self.raw.voxel_at_point(point.into());
83                #[cfg(feature = "dim2")]
84                {
85                    IVect::new(p.x, p.y)
86                }
87                #[cfg(feature = "dim3")]
88                {
89                    IVect::new(p.x, p.y, p.z)
90                }
91            }
92
93            /// Shortcut to [`Voxels::voxel_at_point`].
94            pub fn voxel_at_point(&self, pt: Vect) -> Option<IVect> {
95                let voxel = self.voxel_at_point_unchecked(pt);
96                if self.is_voxel_in_bounds(voxel) {
97                    Some(voxel)
98                } else {
99                    None
100                }
101            }
102
103            /// Shortcut to [`Voxels::domain`].
104            pub fn clamp_voxel(&self, key: IVect) -> IVect {
105                let [mins, maxs] = self.raw.domain();
106                #[cfg(feature = "dim2")]
107                {
108                    IVect::new(
109                        key.x.clamp(mins.x, maxs.x - 1),
110                        key.y.clamp(mins.y, maxs.y - 1),
111                    )
112                }
113                #[cfg(feature = "dim3")]
114                {
115                    IVect::new(
116                        key.x.clamp(mins.x, maxs.x - 1),
117                        key.y.clamp(mins.y, maxs.y - 1),
118                        key.z.clamp(mins.z, maxs.z - 1),
119                    )
120                }
121            }
122
123            /// Shortcut to [`Voxels::voxel_range_intersecting_local_aabb`].
124            pub fn voxel_range_intersecting_local_aabb(&self, aabb: &BevyAabb) -> [IVect; 2] {
125                let res = self
126                    .raw
127                    .voxel_range_intersecting_local_aabb(&aabb_na_from_bevy(aabb));
128                [res[0].into(), res[1].into()]
129            }
130
131            /// Shortcut to [`Voxels::voxel_range_aabb`].
132            pub fn voxel_range_aabb(&self, mins: IVect, maxs: IVect) -> BevyAabb {
133                aabb_bevy_from_na(&self.raw.voxel_range_aabb(mins.into(), maxs.into()))
134            }
135
136            /// Shortcut to [`Voxels::align_aabb_to_grid`].
137            pub fn align_aabb_to_grid(&self, aabb: &BevyAabb) -> BevyAabb {
138                aabb_bevy_from_na(&self.raw.align_aabb_to_grid(&aabb_na_from_bevy(aabb)))
139            }
140
141            /// Shortcut to [`Voxels::voxels_intersecting_local_aabb`].
142            pub fn voxels_intersecting_local_aabb(
143                &self,
144                aabb: &BevyAabb,
145            ) -> impl Iterator<Item = VoxelData> + '_ {
146                self.raw
147                    .voxels_intersecting_local_aabb(&aabb_na_from_bevy(aabb))
148            }
149
150            /// Shortcut to [`Voxels::voxels`].
151            pub fn voxels(&self) -> impl Iterator<Item = VoxelData> + '_ {
152                self.raw.voxels()
153            }
154
155            /// Shortcut to [`Voxels::split_with_box`].
156            #[cfg(feature = "dim2")]
157            pub fn split_with_box(&self, aabb: &BevyAabb) -> (Option<Voxels>, Option<Voxels>) {
158                self.raw.split_with_box(&aabb_na_from_bevy(aabb))
159            }
160
161            /// Shortcut to [`Voxels::voxels_in_range`].
162            pub fn voxels_in_range(
163                &self,
164                mins: IVect,
165                maxs: IVect,
166            ) -> impl Iterator<Item = VoxelData> + '_ {
167                self.raw.voxels_in_range(mins.into(), maxs.into())
168            }
169        }
170    }
171);
172
173impl_ref_methods!(VoxelsView);
174
175/// Read-write access to the properties of a [`Voxels`].
176pub struct VoxelsViewMut<'a> {
177    /// The raw shape from Rapier.
178    pub raw: &'a mut Voxels,
179}
180
181impl_ref_methods!(VoxelsViewMut);
182
183impl<'a> VoxelsViewMut<'a> {
184    /// Shortcut to set voxel state with bounds checking.
185    pub fn try_set_voxel(&mut self, key: IVect, is_filled: bool) -> Option<VoxelState> {
186        if self.is_voxel_in_bounds(key) {
187            Some(self.raw.set_voxel(key.into(), is_filled))
188        } else {
189            None
190        }
191    }
192
193    /// Shortcut to to [`Voxels::set_voxel`].
194    pub fn set_voxel(&mut self, key: IVect, is_filled: bool) -> VoxelState {
195        self.raw.set_voxel(key.into(), is_filled)
196    }
197
198    /// Shortcut to [`Voxels::crop`].
199    pub fn crop(&mut self, domain_mins: IVect, domain_maxs: IVect) {
200        self.raw.crop(domain_mins.into(), domain_maxs.into());
201    }
202}