Passed
Push — 3.x ( 43a424...548f96 )
by Doug
08:16
created

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