1use crate::index::SpatialIndex;
4
5use cgmath::{Point2, Point3, Vector2, Vector3};
6use cgmath::prelude::*;
7use num_traits::{Float, One, PrimInt};
8use smallvec::SmallVec;
9
10use std::fmt::{Debug, Formatter};
11
12pub trait VecDim {
13 const DIM: usize;
14}
15
16impl<T> VecDim for Point2 <T> { const DIM: usize = 2; }
17impl<T> VecDim for Point3 <T> { const DIM: usize = 3; }
18impl<T> VecDim for Vector2<T> { const DIM: usize = 2; }
19impl<T> VecDim for Vector3<T> { const DIM: usize = 3; }
20
21fn fold_arr<Arr, State, F>(arr: Arr, init: State, f: F) -> State
22where
23 Arr: Array,
24 F: FnMut(State, Arr::Element) -> State
25{
26 (0..Arr::len()).map(|i| arr[i]).fold(init, f)
27}
28
29fn init_arr<Arr, F>(arr: &mut Arr, mut f: F)
30where
31 Arr: Array,
32 F: FnMut(usize) -> Arr::Element
33{
34 #[allow(clippy::needless_range_loop)]
35 for i in 0..Arr::len() {
36 arr[i] = f(i);
37 }
38}
39
40fn max_axis<Arr>(arr: Arr) -> Arr::Element
41where
42 Arr: Array,
43 Arr::Element: Bounded + Ord
44{
45 fold_arr(arr, Arr::Element::min_value(), std::cmp::max)
46}
47
48fn scale_at_depth(depth: u32) -> u32 {
49 if depth == 0 {
50 panic!("scale at zero depth would overflow integer");
51 }
52 1u32 << (32 - depth)
53}
54
55fn truncate_to_depth(x: u32, depth: u32) -> u32 {
56 if depth == 0 {
57 x
58 } else {
59 x & !(scale_at_depth(depth) - 1u32)
60 }
61}
62
63pub trait IndexGenerator<Index>
69where
70 Index: SpatialIndex,
71 Self::Output: IntoIterator<Item = Index>
72{
73 type Output;
74
75 fn indices(self, min_depth: Option<u32>) -> Self::Output;
76 fn indices_at_depth(self, depth: u32) -> Self::Output;
77}
78
79#[derive(Copy, Clone, Debug, PartialEq)]
83#[cfg_attr(any(test, feature="serde"), derive(Deserialize, Serialize))]
84pub struct Bounds<Point> {
85 pub min: Point,
86 pub max: Point
87}
88
89impl<Point> Bounds<Point>
90where
91 Point: EuclideanSpace + Array<Element = <Point as EuclideanSpace>::Scalar> + Copy
92{
93 pub fn new(min: Point, max: Point) -> Self {
94 Self{min, max}
95 }
96
97 pub fn sizef(self) -> Point::Diff
98 where
99 Point::Scalar: Float
100 {
101 self.max - self.min
102 }
103
104 pub fn sizei(self) -> Point::Diff
105 where
106 Point::Scalar: PrimInt + One,
107 Point::Diff: ElementWise<Point::Scalar>
108 {
109 (self.max - self.min).add_element_wise(Point::Scalar::one())
110 }
111
112 pub fn overlaps(self, other: Bounds<Point>) -> bool {
113 for i in 0..Point::len() {
114 if self.min[i] > other.max[i] || self.max[i] < other.min[i] {
115 return false;
116 }
117 }
118 true
119 }
120
121 pub fn contains(self, other: Bounds<Point>) -> bool {
122 for i in 0..Point::len() {
123 if self.min[i] > other.min[i] || self.max[i] < other.max[i] {
124 return false;
125 }
126 }
127 true
128 }
129
130 pub fn center(self) -> Point {
131 self.min.midpoint(self.max)
132 }
133}
134
135pub trait SystemBounds<PointGlobal, PointLocal> {
137 fn to_local(&self, global: Bounds<PointGlobal>) -> Bounds<PointLocal>;
138 fn to_global(&self, local: Bounds<PointLocal>) -> Bounds<PointGlobal>;
139}
140
141impl<PointGlobal, PointLocal> SystemBounds<PointGlobal, PointLocal> for Bounds<PointGlobal>
142where
143 PointGlobal: EuclideanSpace<Scalar = f32>,
144 PointGlobal::Diff: Array<Element = f32>,
145 PointLocal: EuclideanSpace<Scalar = u32>,
146 PointLocal::Diff: Array<Element = u32>
147{
148 fn to_local(&self, global: Bounds<PointGlobal>) -> Bounds<PointLocal> {
149 let size = self.sizef();
150 let to_local = |global: PointGlobal, i| {
151 const MIN_VALUE: f32 = std::u32::MIN as f32;
153 const MAX_VALUE: f32 = 0xffff_ff00u32 as f32;
154 const RANGE: f32 = MAX_VALUE - MIN_VALUE;
155 ((global[i] - self.min[i]) / size[i] * RANGE + MIN_VALUE) as u32
156 };
157 let mut local = Bounds::new(
158 PointLocal::from_vec(PointLocal::Diff::zero()),
159 PointLocal::from_vec(PointLocal::Diff::zero()));
160 init_arr(&mut local.min, |i| to_local(global.min, i));
161 init_arr(&mut local.max, |i| to_local(global.max, i));
162 local
163 }
164
165 fn to_global(&self, local: Bounds<PointLocal>) -> Bounds<PointGlobal> {
166 let size = self.sizef();
167 let to_global = |local: PointLocal, i| {
168 const MIN_VALUE: f32 = std::u32::MIN as f32;
170 const MAX_VALUE: f32 = 0xffff_ff00u32 as f32;
171 const RANGE: f32 = MAX_VALUE - MIN_VALUE;
172 self.min[i] + (local[i] as f32 - MIN_VALUE) / RANGE * size[i]
173 };
174 let mut global = Bounds::new(
175 PointGlobal::from_vec(PointGlobal::Diff::zero()),
176 PointGlobal::from_vec(PointGlobal::Diff::zero()));
177 init_arr(&mut global.min, |i| to_global(local.min, i));
178 init_arr(&mut global.max, |i| to_global(local.max, i));
179 global
180 }
181}
182
183impl<Index> IndexGenerator<Index> for Bounds<Point2<u32>>
184where
185 Index: SpatialIndex<Diff = Vector2<u32>, Point = Point2<u32>>
186{
187 type Output = SmallVec<[Index; 4]>;
188
189 fn indices(self, min_depth: Option<u32>) -> Self::Output {
190 let max_axis = max_axis(self.sizei());
191 let mut depth = (max_axis - 1u32).leading_zeros();
192 if let Some(min_depth) = min_depth {
193 if depth < min_depth {
194 depth = min_depth;
195 }
196 }
197 depth = Index::clamp_depth(depth);
198
199 self.indices_at_depth(depth)
200 }
201
202 fn indices_at_depth(self, depth: u32) -> Self::Output {
203 if depth == 0 {
204 return smallvec![Index::default()];
205 }
206
207 let min = self.min.map(|scalar| truncate_to_depth(scalar, depth));
208 let max = self.max.map(|scalar| truncate_to_depth(scalar, depth));
209
210 let mut indices: Self::Output = Self::Output::new();
211
212 let step = scale_at_depth(depth);
213 let mut y = min.y;
214 loop {
215 let mut x = min.x;
216 loop {
217 indices.push(Index::default()
218 .set_depth(depth)
219 .set_origin(Point2::new(x, y)));
220
221 if x >= max.x {
222 break;
223 }
224 x += step;
225 }
226
227 if y >= max.y {
228 break;
229 }
230 y += step;
231 }
232
233 if indices.len() > 4 {
234 warn!("indices_at_depth generated more than 4 indices; decrease min_depth or split large objects to avoid heap allocations");
235 }
236
237 indices
238 }
239}
240
241impl<Index> IndexGenerator<Index> for Bounds<Point3<u32>>
242where
243 Index: SpatialIndex<Diff = Vector3<u32>, Point = Point3<u32>>
244{
245 type Output = SmallVec<[Index; 8]>;
246
247 fn indices(self, min_depth: Option<u32>) -> Self::Output {
248 let max_axis = max_axis(self.sizei());
249 let mut depth = (max_axis - 1u32).leading_zeros();
250 if let Some(min_depth) = min_depth {
251 if depth < min_depth {
252 depth = min_depth;
253 }
254 }
255 depth = Index::clamp_depth(depth);
256
257 self.indices_at_depth(depth)
258 }
259
260 fn indices_at_depth(self, depth: u32) -> Self::Output {
261 if depth == 0 {
262 return smallvec![Index::default()];
263 }
264
265 let min = self.min.map(|scalar| truncate_to_depth(scalar, depth));
266 let max = self.max.map(|scalar| truncate_to_depth(scalar, depth));
267
268 let mut indices: Self::Output = Self::Output::new();
269
270 let step = scale_at_depth(depth);
271 let mut z = min.z;
272 loop {
273 let mut y = min.y;
274 loop {
275 let mut x = min.x;
276 loop {
277 indices.push(Index::default()
278 .set_depth(depth)
279 .set_origin(Point3::new(x, y, z)));
280
281 if x >= max.x {
282 break;
283 }
284 x += step;
285 }
286
287 if y >= max.y {
288 break;
289 }
290 y += step;
291 }
292
293 if z >= max.z {
294 break;
295 }
296 z += step;
297 }
298
299 if indices.len() > 8 {
300 warn!("indices_at_depth generated more than 8 indices; decrease min_depth or split large objects to avoid heap allocations");
301 }
302
303 indices
304 }
305}
306
307impl<Index, Point> From<Index> for Bounds<Point>
308where
309 Index: SpatialIndex<Diff = Point::Diff, Point = Point>,
310 Point: EuclideanSpace<Scalar = u32> + ElementWise<u32>
311{
312 fn from(index: Index) -> Self {
313 let origin = index.origin();
314 let scale = scale_at_depth(index.depth());
315 Self{
316 min: origin,
317 max: origin.add_element_wise(scale-1)
318 }
319 }
320}
321
322pub trait TestGeometry: Sized + Debug {
328 type SubdivideResult: AsRef<[Self]>;
329 type TestOrder: AsRef<[usize]>;
330
331 fn subdivide(&self) -> Self::SubdivideResult;
338
339 fn test_order(&self) -> Self::TestOrder;
343
344 fn should_test(&self, nearest: f32) -> bool;
348}
349
350#[derive(Clone, Debug)]
353pub struct BoxTestGeometry<Point>
354where
355 Point: EuclideanSpace<Scalar = f32>
356{
357 cell_bounds: Bounds<Point>,
358 test_bounds: Bounds<Point>,
359}
360
361impl<Point> BoxTestGeometry<Point>
362where
363 Point: EuclideanSpace<Scalar = f32>
364{
365 pub fn with_system_bounds(
367 system_bounds: Bounds<Point>,
368 test_bounds: Bounds<Point>,) -> Self
369 where
370 Point: Debug,
371 Point::Diff: ElementWise + std::ops::Index<usize, Output = f32> + Debug,
372 {
373 Self{
374 cell_bounds: system_bounds,
375 test_bounds}
376 }
377}
378
379impl TestGeometry for BoxTestGeometry<Point2<f32>> {
380 type SubdivideResult = [Self; 4];
381 type TestOrder = [usize; 4];
382
383 fn subdivide(&self) -> Self::SubdivideResult {
384 let center = self.cell_bounds.center();
385 let mut results: [Self; 4] = [
386 self.clone(),
387 self.clone(),
388 self.clone(),
389 self.clone()
390 ];
391 for (cell, result) in results.iter_mut().enumerate() {
392 let bounds = &mut result.cell_bounds;
393 #[allow(clippy::needless_range_loop)]
394 for axis in 0..2 {
395 let side = cell & (1 << axis) != 0;
396 if side {
397 bounds.min[axis] = center[axis];
398 } else {
399 bounds.max[axis] = center[axis];
400 }
401 }
402 }
403 results
404 }
405
406 fn test_order(&self) -> Self::TestOrder {
407 [0, 1, 2, 3]
408 }
409
410 fn should_test(&self, nearest: f32) -> bool {
411 debug_assert!(!nearest.is_finite(), "BoxTestGeometry does not support \"pick\" operations");
412 self.cell_bounds.overlaps(self.test_bounds)
413 }
414}
415
416impl TestGeometry for BoxTestGeometry<Point3<f32>> {
417 type SubdivideResult = [Self; 8];
418 type TestOrder = [usize; 8];
419
420 fn subdivide(&self) -> Self::SubdivideResult {
421 let center = self.cell_bounds.center();
422 let mut results: [Self; 8] = [
423 self.clone(),
424 self.clone(),
425 self.clone(),
426 self.clone(),
427 self.clone(),
428 self.clone(),
429 self.clone(),
430 self.clone()
431 ];
432 for (cell, result) in results.iter_mut().enumerate() {
433 let bounds = &mut result.cell_bounds;
434 #[allow(clippy::needless_range_loop)]
435 for axis in 0..3 {
436 let side = cell & (1 << axis) != 0;
437 if side {
438 bounds.min[axis] = center[axis];
439 } else {
440 bounds.max[axis] = center[axis];
441 }
442 }
443 }
444 results
445 }
446
447 fn test_order(&self) -> Self::TestOrder {
448 [0, 1, 2, 3, 4, 5, 6, 7]
449 }
450
451 fn should_test(&self, nearest: f32) -> bool {
452 debug_assert!(!nearest.is_finite(), "BoxTestGeometry does not support \"pick\" operations");
453 self.cell_bounds.overlaps(self.test_bounds)
454 }
455}
456
457#[derive(Clone)]
460pub struct RayTestGeometry<Point>
461where
462 Point: EuclideanSpace<Scalar = f32>
463{
464 cell_bounds: Bounds<Point>,
465 origin: Point,
466 direction: Point::Diff,
467 range_min: f32,
468 range_max: f32
469}
470
471impl Debug for RayTestGeometry<Point2<f32>> {
472 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
473 write!(f, "RayTestGeometry{{{{({:}, {:}) - ({:}, {:})}}, ({:}, {:}), ({:}, {:}), {{{:}-{:}}}}}",
474 self.cell_bounds.min.x,
475 self.cell_bounds.min.y,
476 self.cell_bounds.max.x,
477 self.cell_bounds.max.y,
478 self.origin.x,
479 self.origin.y,
480 self.direction.x,
481 self.direction.y,
482 self.range_min,
483 self.range_max)
484 }
485}
486
487impl Debug for RayTestGeometry<Point3<f32>> {
488 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
489 write!(f, "RayTestGeometry{{{{({:}, {:}, {:}) - ({:}, {:}, {:})}}, ({:}, {:}, {:}), ({:}, {:}, {:}), {{{:}-{:}}}}}",
490 self.cell_bounds.min.x,
491 self.cell_bounds.min.y,
492 self.cell_bounds.min.z,
493 self.cell_bounds.max.x,
494 self.cell_bounds.max.y,
495 self.cell_bounds.max.z,
496 self.origin.x,
497 self.origin.y,
498 self.origin.z,
499 self.direction.x,
500 self.direction.y,
501 self.direction.z,
502 self.range_min,
503 self.range_max)
504 }
505}
506
507impl<Point> RayTestGeometry<Point>
508where
509 Point: EuclideanSpace<Scalar = f32> + VecDim
510{
511 pub fn with_system_bounds(
516 system_bounds: Bounds<Point>,
517 origin: Point,
518 direction: Point::Diff,
519 mut range_min: f32,
520 mut range_max: f32) -> Self
521 where
522 Point: Debug,
523 Point::Diff: ElementWise + std::ops::Index<usize, Output = f32> + Debug,
524 {
525 let distance_0 = (system_bounds.min - origin).div_element_wise(direction);
526 let distance_1 = (system_bounds.max - origin).div_element_wise(direction);
527 for axis in 0..<Point as VecDim>::DIM {
528 let is_forward = direction[axis] > 0f32;
529 let (d0, d1) = if is_forward {
530 (distance_0[axis], distance_1[axis])
531 } else {
532 (distance_1[axis], distance_0[axis])
533 };
534 if d0.is_finite() { range_min = range_min.max(d0); }
535 if d1.is_finite() { range_max = range_max.min(d1); }
536 }
537
538 Self{
539 cell_bounds: system_bounds,
540 origin,
541 direction,
542 range_min,
543 range_max}
544 }
545}
546
547impl TestGeometry for RayTestGeometry<Point2<f32>> {
548 type SubdivideResult = [Self; 4];
549 type TestOrder = [usize; 4];
550
551 fn subdivide(&self) -> Self::SubdivideResult {
552 let center = self.cell_bounds.center();
553 let distance = (self.cell_bounds.center() - self.origin).div_element_wise(self.direction);
554 let mut results: [Self; 4] = [
555 self.clone(),
556 self.clone(),
557 self.clone(),
558 self.clone()
559 ];
560 for (cell, result) in results.iter_mut().enumerate() {
561 let range_min = &mut result.range_min;
562 let range_max = &mut result.range_max;
563 for axis in 0..2 {
564 let side = cell & (1 << axis) != 0;
565 if distance[axis].is_finite() {
566 let is_towards = (self.direction[axis] > 0f32) != side;
567 if is_towards {
568 *range_max = range_max.min(distance[axis]);
569 } else {
570 *range_min = range_min.max(distance[axis]);
571 }
572 } else if (self.origin[axis] > center[axis]) != side {
573 *range_min = std::f32::INFINITY;
574 *range_max = std::f32::NEG_INFINITY;
575 }
576 }
577 let bounds = &mut result.cell_bounds;
578 #[allow(clippy::needless_range_loop)]
579 for axis in 0..2 {
580 let side = cell & (1 << axis) != 0;
581 if side {
582 bounds.min[axis] = center[axis];
583 } else {
584 bounds.max[axis] = center[axis];
585 }
586 }
587 }
588 results
589 }
590
591 fn test_order(&self) -> Self::TestOrder {
592 let abs = self.direction.map(|x| x.abs());
593 #[allow(clippy::collapsible_if)]
594 let axes = if abs.x <= abs.y { [0, 1] } else { [1, 0] };
595
596 let mut order: [usize; 4] = [0; 4];
597 for (cell_src, cell_dst) in order.iter_mut().enumerate() {
598 let i0 = (cell_src & 1 != 0) == (self.direction[axes[0]] >= 0f32);
599 let i1 = (cell_src & 2 != 0) == (self.direction[axes[1]] >= 0f32);
600 *cell_dst =
601 ((i0 as usize) << axes[0]) |
602 ((i1 as usize) << axes[1]);
603 }
604
605 order
606 }
607
608 fn should_test(&self, nearest: f32) -> bool {
609 self.range_min < self.range_max && self.range_min < nearest
610 }
611}
612
613impl TestGeometry for RayTestGeometry<Point3<f32>> {
614 type SubdivideResult = [Self; 8];
615 type TestOrder = [usize; 8];
616
617 fn subdivide(&self) -> Self::SubdivideResult {
618 let center = self.cell_bounds.center();
619 let distance = (self.cell_bounds.center() - self.origin).div_element_wise(self.direction);
620 let mut results: [Self; 8] = [
621 self.clone(),
622 self.clone(),
623 self.clone(),
624 self.clone(),
625 self.clone(),
626 self.clone(),
627 self.clone(),
628 self.clone()
629 ];
630 for (cell, result) in results.iter_mut().enumerate() {
631 let range_min = &mut result.range_min;
632 let range_max = &mut result.range_max;
633 for axis in 0..3 {
634 let side = cell & (1 << axis) != 0;
635 if distance[axis].is_finite() {
636 let is_towards = (self.direction[axis] > 0f32) != side;
637 if is_towards {
638 *range_max = range_max.min(distance[axis]);
639 } else {
640 *range_min = range_min.max(distance[axis]);
641 }
642 } else if (self.origin[axis] > center[axis]) != side {
643 *range_min = std::f32::INFINITY;
644 *range_max = std::f32::NEG_INFINITY;
645 }
646 }
647 let bounds = &mut result.cell_bounds;
648 #[allow(clippy::needless_range_loop)]
649 for axis in 0..3 {
650 let side = cell & (1 << axis) != 0;
651 if side {
652 bounds.min[axis] = center[axis];
653 } else {
654 bounds.max[axis] = center[axis];
655 }
656 }
657 }
658 results
659 }
660
661 fn test_order(&self) -> Self::TestOrder {
662 let abs = self.direction.map(|x| x.abs());
663 #[allow(clippy::collapsible_if)]
664 let axes = if abs.x <= abs.y && abs.x <= abs.z {
665 if abs.y <= abs.z { [0, 1, 2] } else { [0, 2, 1] }
666 } else if abs.y <= abs.z {
667 if abs.x <= abs.z { [1, 0, 2] } else { [1, 2, 0] }
668 } else {
669 if abs.x <= abs.y { [2, 0, 1] } else { [2, 1, 0] }
670 };
671
672 let mut order: [usize; 8] = [0; 8];
673 for (cell_src, cell_dst) in order.iter_mut().enumerate() {
674 let i0 = (cell_src & 1 != 0) == (self.direction[axes[0]] >= 0f32);
675 let i1 = (cell_src & 2 != 0) == (self.direction[axes[1]] >= 0f32);
676 let i2 = (cell_src & 4 != 0) == (self.direction[axes[2]] >= 0f32);
677 *cell_dst =
678 ((i0 as usize) << axes[0]) |
679 ((i1 as usize) << axes[1]) |
680 ((i2 as usize) << axes[2])
681 }
682
683 order
684 }
685
686 fn should_test(&self, nearest: f32) -> bool {
687 self.range_min < self.range_max && self.range_min < nearest
688 }
689}
690
691#[cfg(test)]
692mod tests {
693 use super::*;
694
695 #[test]
696 fn system_bounds() {
697 let system_bounds = Bounds{
698 min: Point3::new(-64f32, -64f32, -64f32),
699 max: Point3::new( 64f32, 64f32, 64f32)};
700 let global = Bounds{
701 min: Point3::new(-32f32, -32f32, -32f32),
702 max: Point3::new( 32f32, 32f32, 32f32)};
703 let local: Bounds<Point3<u32>> = system_bounds.to_local(global);
704 let expected = global;
705 let actual = system_bounds.to_global(local);
706 assert_eq!(actual, expected);
707 }
708}