Completed
Push — master ( ecdbb8...f78f60 )
by Doug
14:40
created

PackedBoxList::getMeanItemWeight()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
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 10
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 function count;
13
use Countable;
14
use IteratorAggregate;
15
use function reset;
16
use function round;
17
use Traversable;
18
use function usort;
19
20
/**
21
 * List of packed boxes.
22
 *
23
 * @author Doug Wright
24
 */
25
class PackedBoxList implements IteratorAggregate, Countable
26
{
27
    /**
28
     * List containing boxes.
29
     *
30
     * @var Box[]
31
     */
32
    private $list = [];
33
34
    /**
35
     * Has this list already been sorted?
36
     *
37
     * @var bool
38
     */
39
    private $isSorted = false;
40
41 19
    public function getIterator(): Traversable
42
    {
43 19
        if (!$this->isSorted) {
44 19
            usort($this->list, [$this, 'compare']);
45 19
            $this->isSorted = true;
46
        }
47
48 19
        return new ArrayIterator($this->list);
49
    }
50
51
    /**
52
     * Number of items in list.
53
     */
54 24
    public function count(): int
55
    {
56 24
        return count($this->list);
57
    }
58
59 27
    public function insert(PackedBox $item): void
60
    {
61 27
        $this->list[] = $item;
62 27
    }
63
64
    /**
65
     * Do a bulk insert.
66
     *
67
     * @internal
68
     *
69
     * @param PackedBox[] $boxes
70
     */
71 9
    public function insertFromArray(array $boxes): void
72
    {
73 9
        foreach ($boxes as $box) {
74 9
            $this->insert($box);
75
        }
76 9
    }
77
78
    /**
79
     * @internal
80
     */
81 7
    public function top(): PackedBox
82
    {
83 7
        if (!$this->isSorted) {
84 7
            usort($this->list, [$this, 'compare']);
85 7
            $this->isSorted = true;
86
        }
87
88 7
        return reset($this->list);
89
    }
90
91 10
    private function compare(PackedBox $boxA, PackedBox $boxB): int
92
    {
93 10
        $choice = $boxB->getItems()->count() <=> $boxA->getItems()->count();
94 10
        if ($choice === 0) {
95 9
            $choice = $boxB->getInnerVolume() <=> $boxA->getInnerVolume();
96
        }
97 10
        if ($choice === 0) {
98 9
            $choice = $boxA->getWeight() <=> $boxB->getWeight();
99
        }
100
101 10
        return $choice;
102
    }
103
104
    /**
105
     * Calculate the average (mean) weight of the boxes.
106
     */
107 10
    public function getMeanWeight(): float
108
    {
109 10
        $meanWeight = 0;
110
111
        /** @var PackedBox $box */
112 10
        foreach ($this->list as $box) {
113 10
            $meanWeight += $box->getWeight();
0 ignored issues
show
Bug introduced by
The method getWeight() does not exist on DVDoug\BoxPacker\Box. Did you maybe mean getMaxWeight()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

113
            $meanWeight += $box->/** @scrutinizer ignore-call */ getWeight();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
114
        }
115
116 10
        return $meanWeight / count($this->list);
117
    }
118
119
    /**
120
     * Calculate the average (mean) weight of the boxes.
121
     */
122 8
    public function getMeanItemWeight(): float
123
    {
124 8
        $meanWeight = 0;
125
126
        /** @var PackedBox $box */
127 8
        foreach ($this->list as $box) {
128 8
            $meanWeight += $box->getItemWeight();
0 ignored issues
show
Bug introduced by
The method getItemWeight() does not exist on DVDoug\BoxPacker\Box. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

128
            $meanWeight += $box->/** @scrutinizer ignore-call */ getItemWeight();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
129
        }
130
131 8
        return $meanWeight / count($this->list);
132
    }
133
134
    /**
135
     * Calculate the variance in weight between these boxes.
136
     */
137 9
    public function getWeightVariance(): float
138
    {
139 9
        $mean = $this->getMeanWeight();
140
141 9
        $weightVariance = 0;
142
        /** @var PackedBox $box */
143 9
        foreach ($this->list as $box) {
144 9
            $weightVariance += ($box->getWeight() - $mean) ** 2;
145
        }
146
147 9
        return round($weightVariance / count($this->list), 1);
148
    }
149
150
    /**
151
     * Get volume utilisation of the set of packed boxes.
152
     */
153 1
    public function getVolumeUtilisation(): float
154
    {
155 1
        $itemVolume = 0;
156 1
        $boxVolume = 0;
157
158
        /** @var PackedBox $box */
159 1
        foreach ($this as $box) {
160 1
            $boxVolume += $box->getInnerVolume();
161
162
            /** @var PackedItem $item */
163 1
            foreach ($box->getItems() as $item) {
164 1
                $itemVolume += ($item->getItem()->getWidth() * $item->getItem()->getLength() * $item->getItem()->getDepth());
165
            }
166
        }
167
168 1
        return round($itemVolume / $boxVolume * 100, 1);
169
    }
170
}
171