ami/
bcube.rs

1// Copyright Jeron A. Lau 2017-2018.
2// Copyright Douglas Lau 2017
3// Dual-licensed under either the MIT License or the Boost Software License,
4// Version 1.0.  (See accompanying file LICENSE_1_0.txt or copy at
5// https://www.boost.org/LICENSE_1_0.txt)
6
7use std::fmt;
8use *;
9
10/// Single-precision bounding cube
11#[derive(Clone, Copy, PartialEq)]
12pub struct BCube {
13	pub(crate) center: Vector,
14	pub(crate) half_len: f32,
15}
16
17impl fmt::Debug for BCube {
18	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
19		write!(f, "{:?}±{:?}", self.center, self.half_len)
20	}
21}
22
23impl BCube {
24	/// Create an new empty `BCube`.
25	pub fn empty() -> BCube {
26		let z = 0.0;
27
28		BCube { center: Vector::new(z, z, z), half_len: -1.0 }
29	}
30
31	/// Create an new `BCube` at position `p`.
32	pub fn new(p: Vector) -> BCube {
33		BCube { center: p, half_len: 1.0 }
34	}
35
36	/// Extend the `BCube` to accommodate for `BBox`
37	pub fn extend(&mut self, p: BBox) {
38//		println!("Extend: {:?}", p);
39		self.center = self.move_center(p);
40		self.half_len *= 2.0;
41	}
42
43	fn move_center(&self, p: BBox) -> Vector {
44		let (maxx, maxy, maxz) = p.bcube_sides(*self);
45
46//		println!("MAX: {} {} {}", maxx, maxy, maxz);
47
48		let min = self.center - vector!(self.half_len);
49		let max = self.center + vector!(self.half_len);
50
51		match (maxx, maxy, maxz) {
52			(false, false, false) => Vector::new(min.x, min.y, min.z),
53			(false, false, true) => Vector::new(min.x, min.y, max.z),
54			(false, true, false) => Vector::new(min.x, max.y, min.z),
55			(false, true, true) => Vector::new(min.x, max.y, max.z),
56			(true, false, false) => Vector::new(max.x, min.y, min.z),
57			(true, false, true) => Vector::new(max.x, min.y, max.z),
58			(true, true, false) => Vector::new(max.x, max.y, min.z),
59			(true, true, true) => Vector::new(max.x, max.y, max.z),
60		}
61	}
62
63	/// Check if `BCube` contains point `p`.
64	pub fn contains(&self, p: Vector) -> bool {
65		let Vector { x, y, z } = self.center;
66		let hl = self.half_len;
67		(p.x >= x - hl) &&
68		(p.x < x + hl) &&
69		(p.y >= y - hl) &&
70		(p.y < y + hl) &&
71		(p.z >= z - hl) &&
72		(p.z < z + hl)
73	}
74
75	/// Get two opposite points that are the bounds of the BCube.
76	pub fn to_point_pair(&self) -> (Vector, Vector) {
77		let half_cube = Vector::new(self.half_len, self.half_len,
78			self.half_len);
79
80		(self.center + half_cube, self.center - half_cube)
81	}
82
83	/// Turn into a bbox.
84	pub fn to_bbox(&self) -> BBox {
85		let (max, min) = self.to_point_pair();
86		BBox::new(min, max)
87	}
88
89	/// Get all 6 points or the `BCube`.
90	pub fn all_points(&self) -> [Vector; 7] {
91		let z = 0.0;
92
93		[
94			self.center,
95			self.center + Vector::new(self.half_len, z, z),
96			self.center + Vector::new(z, self.half_len, z),
97			self.center + Vector::new(z, z, self.half_len),
98			self.center + Vector::new(-self.half_len, z, z),
99			self.center + Vector::new(z, -self.half_len, z),
100			self.center + Vector::new(z, z, -self.half_len),
101		]
102	}
103
104	/// Get a positive and negative pair of opposite points that are the
105	/// bounds of the BCube, based around a normal.
106	pub fn pn_pair_from_normal(&self, normal: Vector)
107		-> (Vector, Vector)
108	{
109		let mut pvertex = self.center;
110		let mut nvertex = self.center;
111
112		if normal.x >= 0.0 {
113			pvertex.x += self.half_len;
114			nvertex.x -= self.half_len;
115		} else {
116			nvertex.x += self.half_len;
117			pvertex.x -= self.half_len;
118		}
119
120		if normal.y >= 0.0 {
121			pvertex.y += self.half_len;
122			nvertex.y -= self.half_len;
123		} else {
124			nvertex.y += self.half_len;
125			pvertex.y -= self.half_len;
126		}
127
128		if normal.z >= 0.0 {
129			pvertex.z += self.half_len;
130			nvertex.z -= self.half_len;
131		} else {
132			nvertex.z += self.half_len;
133			pvertex.z -= self.half_len;
134		}
135
136		(nvertex, pvertex)
137	}
138}