1pub extern crate nalgebra;
2
3use nalgebra::{SVector, RealField, Point};
4
5pub type BoundingSpace1<T> = BoundingSpaceN<T, 1>;
6pub type BoundingSpace2<T> = BoundingSpaceN<T, 2>;
7pub type BoundingSpace3<T> = BoundingSpaceN<T, 3>;
8
9pub type BoundingRange<T> = BoundingSpace1<T>;
10pub type BoundingSquare<T> = BoundingSpace2<T>;
11pub type BoundingBox<T> = BoundingSpace3<T>;
12
13#[derive(Debug, Clone, Copy)]
14pub struct BoundingSpaceN<T: RealField, const D: usize> {
15 pub lower: Point<T, D>,
16 pub upper: Point<T, D>,
17}
18
19impl<T: RealField, const D: usize> BoundingSpaceN<T, D> {
20 pub fn new(lower: Point<T, D>, upper: Point<T, D>) -> Self {
21 Self { lower, upper }
22 }
23
24 pub fn from_point(point: Point<T, D>) -> Self {
25 Self::new(point.to_owned(), point)
26 }
27
28 pub fn from_value(value: T) -> Self {
29 let coords = SVector::<T, D>::repeat(value);
30 Self {
31 lower: Point { coords: coords.to_owned() },
32 upper: Point { coords }
33 }
34 }
35
36 pub fn from_values(lower: T, upper: T) -> Self {
37 Self {
38 lower: Point { coords: SVector::repeat(lower) },
39 upper: Point { coords: SVector::repeat(upper) },
40 }
41 }
42
43 pub fn diagonal(&self) -> SVector<T, D> {
44 &self.upper - &self.lower
45 }
46
47 pub fn contains(&self, point: &Point<T, D>) -> bool {
48 for (l, p) in self.lower.coords.iter().zip(&point.coords) {
49 if l > p {
50 return false;
51 }
52 }
53
54 for (u, p) in self.upper.coords.iter().zip(&point.coords) {
55 if u < p {
56 return false;
57 }
58 }
59
60 true
61 }
62
63 pub fn expand_lower(&mut self, point: &Point<T, D>) {
64 self.lower.coords.zip_apply(&point.coords, |l, p| {
65 *l = p.min(l.to_owned());
66 });
67 }
68
69 pub fn expand_upper(&mut self, point: &Point<T, D>) {
70 self.upper.coords.zip_apply(&point.coords, |u, p| {
71 *u = p.max(u.to_owned());
72 });
73 }
74
75 pub fn expand(&mut self, point: &Point<T, D>) {
76 self.expand_lower(point);
77 self.expand_upper(point);
78 }
79}
80
81impl<T: RealField, const D: usize> Default for BoundingSpaceN<T, D>
82{
83 fn default() -> Self {
84 Self {
85 lower: Point::origin(),
86 upper: Point::origin(),
87 }
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use approx::assert_relative_eq;
94 use nalgebra::Point1;
95
96 use super::*;
97
98 #[test]
99 fn default_initialized_with_zeros() {
100 let bs = BoundingSpaceN::<f64, 1>::default();
101
102 for v in bs.lower.iter().chain(bs.upper.iter()) {
103 assert_relative_eq!(*v, 0.0);
104 }
105 }
106
107 #[test]
108 fn first_expand_nan() {
109 let mut bound = BoundingSpaceN::<f64, 1>::from_value(f64::NAN);
110 let point = Point1::new(0.0);
111
112 bound.expand(&point);
113
114 assert_relative_eq!(bound.lower.x, point.x);
115 assert_relative_eq!(bound.upper.x, point.x);
116 }
117
118 #[test]
119 fn expand_1d() {
120 let value = 0.0_f64;
121 let mut bound = BoundingSpaceN::<f64, 1>::from_value(value);
122
123 let p1 = Point1::new(1.0);
124 bound.expand(&p1);
125
126 assert_relative_eq!(bound.lower.x, value);
127 assert_relative_eq!(bound.upper.x, p1.x);
128
129 let p2 = Point1::new(-1.0);
130 bound.expand(&p2);
131
132 assert_relative_eq!(bound.lower.x, p2.x);
133 assert_relative_eq!(bound.upper.x, p1.x);
134 }
135}