Passed
Pull Request — master (#344)
by
unknown
05:27 queued 03:46
created

PackedBoxList::getIterator()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

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