Passed
Push — master ( b79dbd...29a054 )
by Doug
08:25 queued 05:38
created

PackedBox   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 196
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 40
c 3
b 0
f 0
dl 0
loc 196
ccs 52
cts 52
cp 1
rs 10
wmc 22

17 Methods

Rating   Name   Duplication   Size   Complexity  
A getBox() 0 3 1
A getWeight() 0 3 1
A getItems() 0 3 1
A getVolumeUtilisation() 0 3 1
A getItemWeight() 0 3 1
A getRemainingWeight() 0 3 1
A getInnerVolume() 0 3 1
A getRemainingLength() 0 3 1
A getUsedWidth() 0 10 2
A getUsedDepth() 0 10 2
A getRemainingWidth() 0 3 1
A getRemainingDepth() 0 3 1
A __construct() 0 9 3
A getUsedLength() 0 10 2
A getUnusedVolume() 0 3 1
A getUsedVolume() 0 3 1
A jsonSerialize() 0 10 1
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 46
    public function getBox(): Box
55
    {
56 46
        return $this->box;
57
    }
58
59
    /**
60
     * Get items packed.
61
     */
62 80
    public function getItems(): PackedItemList
63
    {
64 80
        return $this->items;
65
    }
66
67
    /**
68
     * Get packed weight.
69
     *
70
     * @return int weight in grams
71
     */
72 16
    public function getWeight(): int
73
    {
74 16
        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 18
    public function getItemWeight(): int
83
    {
84 18
        return $this->itemWeight;
85
    }
86
87
    /**
88
     * Get remaining width inside box for another item.
89
     */
90 2
    public function getRemainingWidth(): int
91
    {
92 2
        return $this->box->getInnerWidth() - $this->getUsedWidth();
93
    }
94
95
    /**
96
     * Get remaining length inside box for another item.
97
     */
98 2
    public function getRemainingLength(): int
99
    {
100 2
        return $this->box->getInnerLength() - $this->getUsedLength();
101
    }
102
103
    /**
104
     * Get remaining depth inside box for another item.
105
     */
106 2
    public function getRemainingDepth(): int
107
    {
108 2
        return $this->box->getInnerDepth() - $this->getUsedDepth();
109
    }
110
111
    /**
112
     * Used width inside box for packing items.
113
     */
114 10
    public function getUsedWidth(): int
115
    {
116 10
        $maxWidth = 0;
117
118
        /** @var PackedItem $item */
119 10
        foreach ($this->items as $item) {
120 10
            $maxWidth = max($maxWidth, $item->getX() + $item->getWidth());
121
        }
122
123 10
        return $maxWidth;
124
    }
125
126
    /**
127
     * Used length inside box for packing items.
128
     */
129 10
    public function getUsedLength(): int
130
    {
131 10
        $maxLength = 0;
132
133
        /** @var PackedItem $item */
134 10
        foreach ($this->items as $item) {
135 10
            $maxLength = max($maxLength, $item->getY() + $item->getLength());
136
        }
137
138 10
        return $maxLength;
139
    }
140
141
    /**
142
     * Used depth inside box for packing items.
143
     */
144 10
    public function getUsedDepth(): int
145
    {
146 10
        $maxDepth = 0;
147
148
        /** @var PackedItem $item */
149 10
        foreach ($this->items as $item) {
150 10
            $maxDepth = max($maxDepth, $item->getZ() + $item->getDepth());
151
        }
152
153 10
        return $maxDepth;
154
    }
155
156
    /**
157
     * Get remaining weight inside box for another item.
158
     */
159 2
    public function getRemainingWeight(): int
160
    {
161 2
        return $this->box->getMaxWeight() - $this->getWeight();
162
    }
163
164 86
    public function getInnerVolume(): int
165
    {
166 86
        return $this->box->getInnerWidth() * $this->box->getInnerLength() * $this->box->getInnerDepth();
167
    }
168
169
    /**
170
     * Get used volume of the packed box.
171
     */
172 86
    public function getUsedVolume(): int
173
    {
174 86
        return $this->items->getVolume();
175
    }
176
177
    /**
178
     * Get unused volume of the packed box.
179
     */
180 2
    public function getUnusedVolume(): int
181
    {
182 2
        return $this->getInnerVolume() - $this->getUsedVolume();
183
    }
184
185
    /**
186
     * Get volume utilisation of the packed box.
187
     */
188 24
    public function getVolumeUtilisation(): float
189
    {
190 24
        return $this->volumeUtilisation;
191
    }
192
193
    /**
194
     * Constructor.
195
     */
196 86
    public function __construct(Box $box, PackedItemList $packedItemList)
197
    {
198 86
        $this->box = $box;
199 86
        $this->items = $packedItemList;
200
201 86
        foreach ($this->items as $item) {
202 84
            $this->itemWeight += $item->getItem()->getWeight();
203
        }
204 86
        $this->volumeUtilisation = round($this->getUsedVolume() / ($this->getInnerVolume() ?: 1) * 100, 1);
205 86
    }
206
207 2
    public function jsonSerialize(): array
208
    {
209
        return [
210
            'box' => [
211 2
                'reference' => $this->box->getReference(),
212 2
                'innerWidth' => $this->box->getInnerWidth(),
213 2
                'innerLength' => $this->box->getInnerLength(),
214 2
                'innerDepth' => $this->box->getInnerDepth(),
215
            ],
216 2
            'items' => iterator_to_array($this->items),
217
        ];
218
    }
219
}
220