1 | <?php |
||
2 | |||
3 | /** |
||
4 | * Box packing (3D bin packing, knapsack problem). |
||
5 | * |
||
6 | * @author Doug Wright |
||
7 | */ |
||
8 | declare(strict_types=1); |
||
9 | |||
10 | namespace DVDoug\BoxPacker; |
||
11 | |||
12 | use JsonSerializable; |
||
13 | use Stringable; |
||
14 | |||
15 | use function atan; |
||
16 | use function min; |
||
17 | use function sort; |
||
18 | |||
19 | /** |
||
20 | * An item to be packed. |
||
21 | */ |
||
22 | class OrientatedItem implements JsonSerializable, Stringable |
||
23 | { |
||
24 | public readonly int $surfaceFootprint; |
||
25 | |||
26 | /** |
||
27 | * @var array<string, bool> |
||
28 | */ |
||
29 | protected static array $stabilityCache = []; |
||
30 | |||
31 | /** |
||
32 | * @var int[] |
||
33 | */ |
||
34 | protected array $dimensionsAsArray; |
||
35 | 102 | ||
36 | public function __construct( |
||
37 | public readonly Item $item, |
||
38 | public readonly int $width, |
||
39 | public readonly int $length, |
||
40 | public readonly int $depth |
||
41 | 102 | ) { |
|
42 | $this->surfaceFootprint = $width * $length; |
||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
43 | 102 | ||
44 | 102 | $this->dimensionsAsArray = [$width, $length, $depth]; |
|
45 | sort($this->dimensionsAsArray); |
||
46 | } |
||
47 | |||
48 | /** |
||
49 | * Is this item stable (low centre of gravity), calculated as if the tipping point is >15 degrees. |
||
50 | * |
||
51 | * N.B. Assumes equal weight distribution. |
||
52 | 86 | */ |
|
53 | public function isStable(): bool |
||
54 | 86 | { |
|
55 | $cacheKey = $this->width . '|' . $this->length . '|' . $this->depth; |
||
56 | 86 | ||
57 | return static::$stabilityCache[$cacheKey] ?? (static::$stabilityCache[$cacheKey] = atan(min($this->length, $this->width) / ($this->depth ?: 1)) > 0.261); |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * Is the supplied item the same size as this one? |
||
62 | * |
||
63 | * @internal |
||
64 | 93 | */ |
|
65 | public function isSameDimensions(Item $item): bool |
||
66 | 93 | { |
|
67 | 56 | if ($item === $this->item) { |
|
68 | return true; |
||
69 | } |
||
70 | 63 | ||
71 | 63 | $itemDimensions = [$item->getWidth(), $item->getLength(), $item->getDepth()]; |
|
72 | sort($itemDimensions); |
||
73 | 63 | ||
74 | return $this->dimensionsAsArray === $itemDimensions; |
||
75 | } |
||
76 | 1 | ||
77 | public function jsonSerialize(): array |
||
78 | 1 | { |
|
79 | 1 | return [ |
|
80 | 1 | 'item' => $this->item, |
|
81 | 1 | 'width' => $this->width, |
|
82 | 1 | 'length' => $this->length, |
|
83 | 1 | 'depth' => $this->depth, |
|
84 | ]; |
||
85 | } |
||
86 | 1 | ||
87 | public function __toString(): string |
||
88 | 1 | { |
|
89 | return $this->width . '|' . $this->length . '|' . $this->depth; |
||
90 | } |
||
91 | } |
||
92 |