Passed
Push — dependabot/npm_and_yarn/docs/v... ( 8fa60d )
by
unknown
09:01
created

PackedBoxList::getVolumeUtilisation()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 7
c 0
b 0
f 0
nc 3
nop 0
dl 0
loc 14
ccs 8
cts 8
cp 1
crap 3
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 ArrayIterator;
12
use Countable;
13
use IteratorAggregate;
14
use JsonSerializable;
15
use Traversable;
16
17
use function count;
18
use function json_encode;
19
use function reset;
20
use function round;
21
use function urlencode;
22
use function usort;
23
24
/**
25
 * List of packed boxes.
26
 */
27
class PackedBoxList implements IteratorAggregate, Countable, JsonSerializable
28
{
29
    /**
30
     * @var PackedBox[]
31
     */
32
    private array $list = [];
33
34
    private bool $isSorted = false;
35
36 55
    public function __construct(private readonly PackedBoxSorter $sorter = new DefaultPackedBoxSorter())
37
    {
38 55
    }
39
40
    /**
41
     * @return Traversable<PackedBox>
42
     */
43 33
    public function getIterator(): Traversable
44
    {
45 33
        if (!$this->isSorted) {
46 33
            usort($this->list, $this->sorter->compare(...));
47 33
            $this->isSorted = true;
48
        }
49
50 33
        return new ArrayIterator($this->list);
51
    }
52
53
    /**
54
     * Number of items in list.
55
     */
56 43
    public function count(): int
57
    {
58 43
        return count($this->list);
59
    }
60
61 51
    public function insert(PackedBox $item): void
62
    {
63 51
        $this->list[] = $item;
64 51
        $this->isSorted = false;
65
    }
66
67
    /**
68
     * Do a bulk insert.
69
     *
70
     * @internal
71
     *
72
     * @param PackedBox[] $boxes
73
     */
74 13
    public function insertFromArray(array $boxes): void
75
    {
76 13
        foreach ($boxes as $box) {
77 13
            $this->insert($box);
78
        }
79
    }
80
81
    /**
82
     * @internal
83
     */
84 10
    public function top(): PackedBox
85
    {
86 10
        if (!$this->isSorted) {
87 9
            usort($this->list, $this->sorter->compare(...));
88 9
            $this->isSorted = true;
89
        }
90
91 10
        return reset($this->list);
92
    }
93
94
    /**
95
     * Calculate the average (mean) weight of the boxes.
96
     */
97 14
    public function getMeanWeight(): float
98
    {
99 14
        $meanWeight = 0;
100
101 14
        foreach ($this->list as $box) {
102 14
            $meanWeight += $box->getWeight();
103
        }
104
105 14
        return $meanWeight / count($this->list);
106
    }
107
108
    /**
109
     * Calculate the average (mean) weight of the boxes.
110
     */
111 12
    public function getMeanItemWeight(): float
112
    {
113 12
        $meanWeight = 0;
114
115 12
        foreach ($this->list as $box) {
116 12
            $meanWeight += $box->getItemWeight();
117
        }
118
119 12
        return $meanWeight / count($this->list);
120
    }
121
122
    /**
123
     * Calculate the variance in weight between these boxes.
124
     */
125 13
    public function getWeightVariance(): float
126
    {
127 13
        $mean = $this->getMeanWeight();
128
129 13
        $weightVariance = 0;
130 13
        foreach ($this->list as $box) {
131 13
            $weightVariance += ($box->getWeight() - $mean) ** 2;
132
        }
133
134 13
        return round($weightVariance / count($this->list), 1);
135
    }
136
137
    /**
138
     * Get volume utilisation of the set of packed boxes.
139
     */
140 1
    public function getVolumeUtilisation(): float
141
    {
142 1
        $itemVolume = 0;
143 1
        $boxVolume = 0;
144
145 1
        foreach ($this as $box) {
146 1
            $boxVolume += $box->getInnerVolume();
147
148 1
            foreach ($box->getItems() as $item) {
149 1
                $itemVolume += ($item->getItem()->getWidth() * $item->getItem()->getLength() * $item->getItem()->getDepth());
150
            }
151
        }
152
153 1
        return round($itemVolume / $boxVolume * 100, 1);
154
    }
155
156
    /**
157
     * Create a custom website visualiser URL for this packing.
158
     */
159 1
    public function generateVisualisationURL(): string
160
    {
161 1
        return 'https://boxpacker.io/en/master/visualiser.html?packing=' . urlencode(json_encode($this));
162
    }
163
164 2
    public function jsonSerialize(): array
165
    {
166 2
        return $this->list;
167
    }
168
}
169