Passed
Pull Request — master (#308)
by
unknown
05:50 queued 03:55
created

PackedBoxList::getWeightVariance()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

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