Passed
Push — 3.x ( 071761...f78397 )
by Doug
03:06
created

PackedBoxList::__construct()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

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