Completed
Push — issue_187 ( 8952f9...e99851 )
by Doug
12:21
created

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