Skip to content

Commit 2d8f9a0

Browse files
authored
fix point-projection on voxels with empty chunks (#384)
* fix point-projection on voxels with empty chunks * chore: cargo fmt * fix clippy
1 parent 6755d0c commit 2d8f9a0

File tree

5 files changed

+28
-17
lines changed

5 files changed

+28
-17
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## Unreleased
2+
3+
- Fix point-projection of a ball on a voxels shape containing empty chunks (e.g. after voxels removal).
4+
15
## 0.25.0
26

37
- The `Voxels` shape now uses a sparse storage internally.

src/partitioning/bvh/bvh_optimize.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ impl Bvh {
1313
let num_optimized_leaves = (num_leaves * TARGET_REBUILD_NODE_PERCENTAGE).div_ceil(100);
1414

1515
let num_leaves_sqrt = (num_leaves as Real).sqrt();
16-
let root_mode = if frame_index % 2 == 0 {
16+
let root_mode = if frame_index.is_multiple_of(2) {
1717
RootOptimizationMode::Skip
18-
} else if (frame_index / 2) % 16 == 0 {
18+
} else if (frame_index / 2).is_multiple_of(16) {
1919
RootOptimizationMode::BreadthFirst
2020
} else {
2121
RootOptimizationMode::PriorityQueue

src/query/point/point_voxels.rs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::math::{Point, Real};
1+
use crate::math::{Point, Real, Vector};
22
use crate::query::{PointProjection, PointQuery};
33
use crate::shape::{Cuboid, FeatureId, Voxels, VoxelsChunkRef};
44

@@ -8,11 +8,15 @@ impl PointQuery for Voxels {
88
self.chunk_bvh()
99
.project_point(pt, Real::MAX, |chunk_id, _| {
1010
let chunk = self.chunk_ref(chunk_id);
11-
Some(chunk.project_local_point_and_get_vox_id(pt, solid).0)
11+
chunk
12+
.project_local_point_and_get_vox_id(pt, solid)
13+
.map(|(proj, _)| proj)
1214
})
13-
.unwrap()
14-
.1
15-
.1
15+
.map(|res| res.1 .1)
16+
.unwrap_or(PointProjection::new(
17+
false,
18+
Vector::repeat(Real::MAX).into(),
19+
))
1620
}
1721

1822
#[inline]
@@ -23,13 +27,16 @@ impl PointQuery for Voxels {
2327
self.chunk_bvh()
2428
.project_point_and_get_feature(pt, Real::MAX, |chunk_id, _| {
2529
let chunk = self.chunk_ref(chunk_id);
26-
let (proj, vox) = chunk.project_local_point_and_get_vox_id(pt, false);
2730
// TODO: we need a way to return both the voxel id, and the feature on the voxel.
28-
Some((proj, FeatureId::Face(vox)))
31+
chunk
32+
.project_local_point_and_get_vox_id(pt, false)
33+
.map(|(proj, vox)| (proj, FeatureId::Face(vox)))
2934
})
30-
.unwrap()
31-
.1
32-
.1
35+
.map(|res| res.1 .1)
36+
.unwrap_or((
37+
PointProjection::new(false, Vector::repeat(Real::MAX).into()),
38+
FeatureId::Unknown,
39+
))
3340
}
3441
}
3542

@@ -39,7 +46,7 @@ impl<'a> VoxelsChunkRef<'a> {
3946
&self,
4047
pt: &Point<Real>,
4148
solid: bool,
42-
) -> (PointProjection, u32) {
49+
) -> Option<(PointProjection, u32)> {
4350
// TODO: optimize this naive implementation that just iterates on all the voxels
4451
// from this chunk.
4552
let base_cuboid = Cuboid::new(self.parent.voxel_size() / 2.0);
@@ -59,6 +66,6 @@ impl<'a> VoxelsChunkRef<'a> {
5966
}
6067
}
6168

62-
(result, result_vox_id as u32)
69+
(smallest_dist < Real::MAX).then_some((result, result_vox_id as u32))
6370
}
6471
}

src/shape/voxels/voxels_chunk.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ impl<'a> VoxelsChunkRef<'a> {
180180

181181
/// Iterates through all the voxels in this chunk.
182182
///
183-
/// Note that this yields both empty and non-empty voxels within the range. This does not
183+
/// Note that this only yields non-empty voxels within the range. This does not
184184
/// include any voxel that falls outside [`Self::domain`].
185185
pub fn voxels(&self) -> impl Iterator<Item = VoxelData> + '_ {
186186
let range = self.domain();
@@ -189,7 +189,7 @@ impl<'a> VoxelsChunkRef<'a> {
189189

190190
/// Iterate through the data of all the voxels within the given (semi-open) voxel grid indices.
191191
///
192-
/// Note that this yields both empty and non-empty voxels within the range. This does not
192+
/// Note that this only yields non-empty voxels within the range. This does not
193193
/// include any voxel that falls outside [`Self::domain`].
194194
#[cfg(feature = "dim2")]
195195
pub fn voxels_in_range(

src/utils/median.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub fn median(vals: &mut [Real]) -> Real {
1313

1414
let n = vals.len();
1515

16-
if n % 2 == 0 {
16+
if n.is_multiple_of(2) {
1717
(vals[n / 2 - 1] + vals[n / 2]) / na::convert::<f64, Real>(2.0)
1818
} else {
1919
vals[n / 2]

0 commit comments

Comments
 (0)