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