Passed
Push — 3.x ( 05eab4...5fb647 )
by Doug
05:29 queued 03:46
created

PackedBox::getInnerVolume()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
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 function iterator_to_array;
12
use JsonSerializable;
13
use function max;
14
use ReturnTypeWillChange;
15
use function round;
16
17
/**
18
 * A "box" with items.
19
 *
20
 * @author Doug Wright
21
 */
22
class PackedBox implements JsonSerializable
23
{
24
    /**
25
     * Box used.
26
     *
27
     * @var Box
28
     */
29
    protected $box;
30
31
    /**
32
     * Items in the box.
33
     *
34
     * @var PackedItemList
35
     */
36
    protected $items;
37
38
    /**
39
     * Total weight of items in the box.
40
     *
41
     * @var int
42
     */
43
    protected $itemWeight;
44
45
    /**
46
     * Volume used for items as % of box.
47
     *
48
     * @var float
49
     */
50
    protected $volumeUtilisation;
51
52
    /**
53
     * Get box used.
54
     */
55 22
    public function getBox(): Box
56
    {
57 22
        return $this->box;
58
    }
59
60
    /**
61
     * Get items packed.
62
     */
63 82
    public function getItems(): PackedItemList
64
    {
65 82
        return $this->items;
66
    }
67
68
    /**
69
     * Get packed weight.
70
     *
71
     * @return int weight in grams
72
     */
73 4
    public function getWeight(): int
74
    {
75 4
        return $this->box->getEmptyWeight() + $this->getItemWeight();
76
    }
77
78
    /**
79
     * Get packed weight of the items only.
80
     *
81
     * @return int weight in grams
82
     */
83 4
    public function getItemWeight(): int
84
    {
85 4
        if ($this->itemWeight !== null) {
86 4
            return $this->itemWeight;
87
        }
88
89 4
        $this->itemWeight = 0;
90
        /** @var PackedItem $item */
91 4
        foreach ($this->items as $item) {
92 4
            $this->itemWeight += $item->getItem()->getWeight();
93
        }
94
95 4
        return $this->itemWeight;
96
    }
97
98
    /**
99
     * Get remaining width inside box for another item.
100
     */
101
    public function getRemainingWidth(): int
102
    {
103
        return $this->box->getInnerWidth() - $this->getUsedWidth();
104
    }
105
106
    /**
107
     * Get remaining length inside box for another item.
108
     */
109
    public function getRemainingLength(): int
110
    {
111
        return $this->box->getInnerLength() - $this->getUsedLength();
112
    }
113
114
    /**
115
     * Get remaining depth inside box for another item.
116
     */
117
    public function getRemainingDepth(): int
118
    {
119
        return $this->box->getInnerDepth() - $this->getUsedDepth();
120
    }
121
122
    /**
123
     * Used width inside box for packing items.
124
     */
125
    public function getUsedWidth(): int
126
    {
127
        $maxWidth = 0;
128
129
        /** @var PackedItem $item */
130
        foreach ($this->items as $item) {
131
            $maxWidth = max($maxWidth, $item->getX() + $item->getWidth());
132
        }
133
134
        return $maxWidth;
135
    }
136
137
    /**
138
     * Used length inside box for packing items.
139
     */
140
    public function getUsedLength(): int
141
    {
142
        $maxLength = 0;
143
144
        /** @var PackedItem $item */
145
        foreach ($this->items as $item) {
146
            $maxLength = max($maxLength, $item->getY() + $item->getLength());
147
        }
148
149
        return $maxLength;
150
    }
151
152
    /**
153
     * Used depth inside box for packing items.
154
     */
155
    public function getUsedDepth(): int
156
    {
157
        $maxDepth = 0;
158
159
        /** @var PackedItem $item */
160
        foreach ($this->items as $item) {
161
            $maxDepth = max($maxDepth, $item->getZ() + $item->getDepth());
162
        }
163
164
        return $maxDepth;
165
    }
166
167
    /**
168
     * Get remaining weight inside box for another item.
169
     */
170
    public function getRemainingWeight(): int
171
    {
172
        return $this->box->getMaxWeight() - $this->getWeight();
173
    }
174
175 82
    public function getInnerVolume(): int
176
    {
177 82
        return $this->box->getInnerWidth() * $this->box->getInnerLength() * $this->box->getInnerDepth();
178
    }
179
180
    /**
181
     * Get used volume of the packed box.
182
     */
183 82
    public function getUsedVolume(): int
184
    {
185 82
        return $this->items->getVolume();
186
    }
187
188
    /**
189
     * Get unused volume of the packed box.
190
     */
191
    public function getUnusedVolume(): int
192
    {
193
        return $this->getInnerVolume() - $this->getUsedVolume();
194
    }
195
196
    /**
197
     * Get volume utilisation of the packed box.
198
     */
199 12
    public function getVolumeUtilisation(): float
200
    {
201 12
        return $this->volumeUtilisation;
202
    }
203
204
    /**
205
     * Constructor.
206
     */
207 82
    public function __construct(Box $box, PackedItemList $packedItemList)
208
    {
209 82
        $this->box = $box;
210 82
        $this->items = $packedItemList;
211
212 82
        $this->volumeUtilisation = round($this->getUsedVolume() / ($this->getInnerVolume() ?: 1) * 100, 1);
213 82
    }
214
215
    #[ReturnTypeWillChange]
216
    public function jsonSerialize()/*: mixed*/
217
    {
218
        return [
219
            'box' => [
220
                'reference' => $this->box->getReference(),
221
                'innerWidth' => $this->box->getInnerWidth(),
222
                'innerLength' => $this->box->getInnerLength(),
223
                'innerDepth' => $this->box->getInnerDepth(),
224
            ],
225
            'items' => iterator_to_array($this->items),
226
        ];
227
    }
228
}
229