Passed
Push — 3.x ( 8e4c44...bf81ca )
by Doug
14:10
created

PackedBoxList::__construct()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 2

Importance

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