Passed
Push — master ( 3f7235...602f18 )
by Doug
07:56
created

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