Passed
Push — 3.x ( 97397b...854a27 )
by Doug
12:23 queued 10:33
created

PackedBox::getBox()   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
    protected Box $box;
31
32
    /**
33
     * Items in the box.
34
     */
35
    protected PackedItemList $items;
36
37
    /**
38
     * Total weight of items in the box.
39
     */
40
    protected int $itemWeight = 0;
41
42
    /**
43
     * Volume used for items as % of box.
44
     */
45
    protected float $volumeUtilisation;
46
47
    /**
48
     * Get box used.
49
     */
50 38
    public function getBox(): Box
51
    {
52 38
        return $this->box;
53
    }
54
55
    /**
56
     * Get items packed.
57
     */
58 85
    public function getItems(): PackedItemList
59
    {
60 85
        return $this->items;
61
    }
62
63
    /**
64
     * Get packed weight.
65
     *
66
     * @return int weight in grams
67
     */
68 13
    public function getWeight(): int
69
    {
70 13
        return $this->box->getEmptyWeight() + $this->getItemWeight();
71
    }
72
73
    /**
74
     * Get packed weight of the items only.
75
     *
76
     * @return int weight in grams
77
     */
78 14
    public function getItemWeight(): int
79
    {
80 14
        return $this->itemWeight;
81
    }
82
83
    /**
84
     * Get remaining width inside box for another item.
85
     */
86 1
    public function getRemainingWidth(): int
87
    {
88 1
        return $this->box->getInnerWidth() - $this->getUsedWidth();
89
    }
90
91
    /**
92
     * Get remaining length inside box for another item.
93
     */
94 1
    public function getRemainingLength(): int
95
    {
96 1
        return $this->box->getInnerLength() - $this->getUsedLength();
97
    }
98
99
    /**
100
     * Get remaining depth inside box for another item.
101
     */
102 1
    public function getRemainingDepth(): int
103
    {
104 1
        return $this->box->getInnerDepth() - $this->getUsedDepth();
105
    }
106
107
    /**
108
     * Used width inside box for packing items.
109
     */
110 5
    public function getUsedWidth(): int
111
    {
112 5
        $maxWidth = 0;
113
114 5
        foreach ($this->items as $item) {
115 5
            $maxWidth = max($maxWidth, $item->getX() + $item->getWidth());
116
        }
117
118 5
        return $maxWidth;
119
    }
120
121
    /**
122
     * Used length inside box for packing items.
123
     */
124 5
    public function getUsedLength(): int
125
    {
126 5
        $maxLength = 0;
127
128 5
        foreach ($this->items as $item) {
129 5
            $maxLength = max($maxLength, $item->getY() + $item->getLength());
130
        }
131
132 5
        return $maxLength;
133
    }
134
135
    /**
136
     * Used depth inside box for packing items.
137
     */
138 5
    public function getUsedDepth(): int
139
    {
140 5
        $maxDepth = 0;
141
142 5
        foreach ($this->items as $item) {
143 5
            $maxDepth = max($maxDepth, $item->getZ() + $item->getDepth());
144
        }
145
146 5
        return $maxDepth;
147
    }
148
149
    /**
150
     * Get remaining weight inside box for another item.
151
     */
152 1
    public function getRemainingWeight(): int
153
    {
154 1
        return $this->box->getMaxWeight() - $this->getWeight();
155
    }
156
157 88
    public function getInnerVolume(): int
158
    {
159 88
        return $this->box->getInnerWidth() * $this->box->getInnerLength() * $this->box->getInnerDepth();
160
    }
161
162
    /**
163
     * Get used volume of the packed box.
164
     */
165 88
    public function getUsedVolume(): int
166
    {
167 88
        return $this->items->getVolume();
168
    }
169
170
    /**
171
     * Get unused volume of the packed box.
172
     */
173 1
    public function getUnusedVolume(): int
174
    {
175 1
        return $this->getInnerVolume() - $this->getUsedVolume();
176
    }
177
178
    /**
179
     * Get volume utilisation of the packed box.
180
     */
181 23
    public function getVolumeUtilisation(): float
182
    {
183 23
        return $this->volumeUtilisation;
184
    }
185
186
    /**
187
     * Constructor.
188
     */
189 88
    public function __construct(Box $box, PackedItemList $packedItemList)
190
    {
191 88
        $this->box = $box;
192 88
        $this->items = $packedItemList;
193
194 88
        foreach ($this->items as $item) {
195 87
            $this->itemWeight += $item->getItem()->getWeight();
196
        }
197
198 88
        $this->volumeUtilisation = round($this->getUsedVolume() / ($this->getInnerVolume() ?: 1) * 100, 1);
199
    }
200
201 1
    #[ReturnTypeWillChange]
202
    public function jsonSerialize()/* : mixed */
203
    {
204 1
        $userValues = [];
205
206 1
        if ($this->box instanceof JsonSerializable) {
207 1
            $userSerialisation = $this->box->jsonSerialize();
0 ignored issues
show
Bug introduced by
The method jsonSerialize() does not exist on DVDoug\BoxPacker\Box. It seems like you code against a sub-type of said class. However, the method does not exist in DVDoug\BoxPacker\LimitedSupplyBox. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

207
            /** @scrutinizer ignore-call */ 
208
            $userSerialisation = $this->box->jsonSerialize();
Loading history...
208 1
            if (is_array($userSerialisation)) {
209 1
                $userValues = $userSerialisation;
210
            } else {
211
                $userValues = ['extra' => $userSerialisation];
212
            }
213
        }
214
215 1
        return [
216 1
            'box' => array_merge(
217 1
                $userValues,
218 1
                [
219 1
                    'reference' => $this->box->getReference(),
220 1
                    'innerWidth' => $this->box->getInnerWidth(),
221 1
                    'innerLength' => $this->box->getInnerLength(),
222 1
                    'innerDepth' => $this->box->getInnerDepth(),
223 1
                ]
224 1
            ),
225 1
            'items' => iterator_to_array($this->items),
226 1
        ];
227
    }
228
}
229