packer_3d/
box3d.rs

1//! 3-dimensional box
2use crate::vector3d::*;
3use crate::HashSetFnv;
4
5/// The structure of a 3-dimensional box
6#[derive(Eq, PartialEq, Default, Hash, Copy, Clone, Debug)]
7pub struct Box3D {
8	/// Corresponds to `x`,`y`,`z` properties
9	pub position: Vector3D::<u64>,
10	/// Corresponds to `w`,`h`,`l` properties
11	pub size: Vector3D::<u64>,
12	/// ID for each box
13	pub id: usize,
14	/// Keeps a trace of how the box evolved (only for debugging)
15	pub origin: u16,
16}
17
18impl Box3D {
19
20	/// Create Box3D from `position`, and `size`
21	pub fn from_position_size(position: Vector3D::<u64>, size: Vector3D::<u64>, id: usize, origin: u16) -> Box3D
22	{
23		Box3D { position, size, id, origin }
24	}
25
26	/// Create Box3D from `xyz`, and `whl`
27	pub fn from_xyz_whl(x: u64, y: u64, z: u64, w: u64, h: u64, l: u64, id: usize, origin: u16) -> Box3D
28	{
29		let position = Vector3D::<u64>::new(x,y,z);
30		let size = Vector3D::<u64>::new(w,h,l);
31		Box3D { position, size, id, origin }
32	}
33
34	/// Volume of the Box
35	pub fn volume(&self) -> u64
36	{
37		self.size.x * self.size.y * self.size.z
38	}
39
40	/// Box is smaller than other
41	pub fn fits_in(&self, other: &Box3D) -> bool
42	{
43		self.size.x <= other.size.x && self.size.y <= other.size.y && self.size.z <= other.size.z
44	}
45
46	/// Box is inside other in terms of size AND position
47	pub fn is_in(&self, other: &Box3D) -> bool 
48	{   // Check if shape IS in 'other' shape using
49		// a comparison of positions
50		self.position.x >= other.position.x &&       // BOTTOM corner of shape is inside 'other'
51		self.position.y >= other.position.y &&       //
52		self.position.z >= other.position.z &&       //
53
54		self.x2() <= other.x2() &&     // TOP corner of shape is inside 'other'
55		self.y2() <= other.y2() &&     //
56		self.z2() <= other.z2()        //
57	}
58
59	pub fn x2(&self) -> u64
60	{
61		self.position.x + self.size.x
62	}
63	pub fn y2(&self) -> u64
64	{
65		self.position.y + self.size.y
66	}
67	pub fn z2(&self) -> u64 
68	{
69		self.position.z + self.size.z
70	}
71
72	/// Box strictly (doesn't only touch) intersects other
73	pub fn intersects(&self, other: &Box3D) -> bool
74	{
75		range_overlap(self.position.x, self.x2(), other.position.x, other.x2()) &&
76		range_overlap(self.position.y, self.y2(), other.position.y, other.y2()) &&
77		range_overlap(self.position.z, self.z2(), other.position.z, other.z2())
78	}
79
80	/// Returns whether Box is covered among other Boxes
81	pub fn is_covered_among(&self, boxes: &HashSetFnv<Box3D>) -> bool
82	{
83		boxes.iter().any(|other| self.is_in(other))
84	}
85
86	/// Gets the new 6 boxes with sizes adjusted according to rotation
87	pub fn get_rotations(&self) -> Vec<Box3D>
88	{
89		vec![
90			Box3D::from_position_size(self.position, Vector3D::<u64>::new(self.size.x, self.size.y, self.size.z), self.id, self.origin), // w,h,l
91			Box3D::from_position_size(self.position, Vector3D::<u64>::new(self.size.y, self.size.x, self.size.z), self.id, self.origin), // h,w,l
92			Box3D::from_position_size(self.position, Vector3D::<u64>::new(self.size.z, self.size.y, self.size.x), self.id, self.origin), // l,h,w
93			Box3D::from_position_size(self.position, Vector3D::<u64>::new(self.size.x, self.size.z, self.size.y), self.id, self.origin), // w,l,h
94			Box3D::from_position_size(self.position, Vector3D::<u64>::new(self.size.z, self.size.x, self.size.y), self.id, self.origin), // l,w,h
95			Box3D::from_position_size(self.position, Vector3D::<u64>::new(self.size.y, self.size.z, self.size.x), self.id, self.origin)  // h,l,w
96		]
97	}
98}
99
100/// Checks if two 1D ranges `[amin, amax)` and `[bmin, bmax)` strictly overlap.
101fn range_overlap<T: std::cmp::PartialOrd>(amin: T, amax: T, bmin: T, bmax: T) -> bool
102{
103	amax > bmin && bmax > amin
104}