Passed
Push — master ( 5719ef...74c658 )
by Doug
02:48 queued 11s
created

PackedBox::jsonSerialize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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