1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// "ami" crate - Licensed under the MIT LICENSE
//  * Copyright (c) 2017  Douglas P. Lau
//  * Copyright (c) 2017-2018  Jeron A. Lau <jeron.lau@plopgrizzly.com>

use std::{ fmt, ops };

use Vec3;
use BCube;

/// Bounding box
#[derive(Clone, Copy)]
pub struct BBox {
	pub(crate) min: Vec3,
	pub(crate) max: Vec3,
}

impl fmt::Debug for BBox {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{:?} → {:?}", self.min, self.max)
	}
}

impl ops::Sub<Vec3> for BBox {
	type Output = BBox;

	fn sub(self, other: Vec3) -> Self::Output {
		BBox::new(self.min - other, self.max - other)
	}
}

impl ops::Add<Vec3> for BBox {
	type Output = BBox;

	fn add(self, other: Vec3) -> Self::Output {
		BBox::new(self.min + other, self.max + other)
	}
}

impl BBox {
	/// Create an new `BBox` at position `p`.
	pub fn new(min: Vec3, max: Vec3) -> BBox {
		assert!(min.x <= max.x);
		assert!(min.y <= max.y);
		assert!(min.z <= max.z);

		BBox { min, max }
	}

	/// Check if `BBox` collides with `other` `BBox`.
	pub fn collide(&self, other: BBox) -> bool {
		   other.max.x >= self.min.x
		&& self.max.x >= other.min.x
		&& other.max.y >= self.min.y
		&& self.max.y >= other.min.y
		&& other.max.z >= self.min.z
		&& self.max.z >= other.min.z
	}

	/// Check if `BBox` collides with `BCube`.
	pub fn collide_bcube(&self, bcube: BCube) -> bool {
		let (max, min) = bcube.to_point_pair();
		self.collide(BBox::new(min, max))
	}

	/// Check if `BBox` collides with point `p`.
	pub fn collide_vec3(&self, p: Vec3) -> bool {
		(p.x >= self.min.x) &&
		(p.x <= self.max.x) &&
		(p.y >= self.min.y) &&
		(p.y <= self.max.y) &&
		(p.z >= self.min.z) &&
		(p.z <= self.max.z)
	}

	/// Get all 8 points of the `BBox`.
	pub fn all_points(&self) -> [Vec3; 8] {
		[
			Vec3::new(self.min.x, self.min.y, self.min.z),
			Vec3::new(self.min.x, self.min.y, self.max.z),
			Vec3::new(self.min.x, self.max.y, self.min.z),
			Vec3::new(self.min.x, self.max.y, self.max.z),
			Vec3::new(self.max.x, self.min.y, self.min.z),
			Vec3::new(self.max.x, self.min.y, self.max.z),
			Vec3::new(self.max.x, self.max.y, self.min.z),
			Vec3::new(self.max.x, self.max.y, self.max.z),
		]
	}

	/// Get the center of the `BBox`.
	pub fn center(&self) -> Vec3 {
		Vec3::new(
			(self.min.x + self.max.x) / 2.0,
			(self.min.y + self.max.y) / 2.0,
			(self.min.z + self.max.z) / 2.0,
		)
	}
}