Completed
Push — master ( 17ecec...f96e7f )
by Doug
51:32 queued 50:04
created

PackedBoxList::getVolumeUtilisation()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 8
cts 8
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 8
nc 3
nop 0
crap 3
1
<?php
2
/**
3
 * Box packing (3D bin packing, knapsack problem)
4
 * @package BoxPacker
5
 * @author Doug Wright
6
 */
7
declare(strict_types=1);
8
namespace DVDoug\BoxPacker;
9
10
use ArrayIterator, Countable, IteratorAggregate, Traversable;
11
use function reset;
12
13
/**
14
 * List of packed boxes
15
 * @author Doug Wright
16
 * @package BoxPacker
17
 */
18
class PackedBoxList implements IteratorAggregate
19
{
20
    /**
21
     * Average (mean) weight of boxes
22
     * @var float
23
     */
24
    protected $meanWeight;
25
26
    /**
27
     * List containing boxes
28
     * @var Box[]
29
     */
30
    private $list = [];
31
32
    /**
33
     * Has this list already been sorted?
34
     * @var bool
35
     */
36
    private $isSorted = false;
37
38
    /**
39
     * @return Traversable
40
     */
41 11 View Code Duplication
    public function getIterator(): Traversable
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
42
    {
43 11
        if (!$this->isSorted) {
44 11
            usort($this->list, [$this, 'compare']);
45 11
            $this->isSorted = true;
46
        }
47 11
        return new ArrayIterator($this->list);
48
    }
49
50
    /**
51
     * Number of items in list
52
     * @return int
53
     */
54 24
    public function count(): int
55
    {
56 24
        return count($this->list);
57
    }
58
59
    /**
60
     * @param PackedBox $item
61
     */
62 27
    public function insert(PackedBox $item)
63
    {
64 27
        $this->list[] = $item;
65
    }
66
67
    /**
68
     * Do a bulk insert
69
     * @internal
70
     * @param PackedBox[] $boxes
71
     */
72 6
    public function insertFromArray(array $boxes): void
73
    {
74 6
        foreach ($boxes as $box) {
75 4
            $this->insert($box);
76
        }
77
    }
78
79
    /**
80
     * @internal
81
     * @return PackedBox
82
     */
83 5 View Code Duplication
    public function top(): PackedBox
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
84
    {
85 5
        if (!$this->isSorted) {
86 5
            usort($this->list, [$this, 'compare']);
87 5
            $this->isSorted = true;
88
        }
89 5
        return reset($this->list);
90
    }
91
92
    /**
93
     * @param PackedBox $boxA
94
     * @param PackedBox $boxB
95
     *
96
     * @return int
97
     */
98 7 View Code Duplication
    private function compare(PackedBox $boxA, PackedBox $boxB): int
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
99
    {
100 7
        $choice = $boxB->getItems()->count() <=> $boxA->getItems()->count();
101 7
        if ($choice === 0) {
102 4
            $choice = $boxB->getInnerVolume() <=> $boxA->getInnerVolume();
103
        }
104 7
        if ($choice === 0) {
105 4
            $choice = $boxA->getWeight() <=> $boxB->getWeight();
106
        }
107 7
        return $choice;
108
    }
109
110
    /**
111
     * Calculate the average (mean) weight of the boxes
112
     * @return float
113
     */
114 7
    public function getMeanWeight(): float
115
    {
116 7
        if (!is_null($this->meanWeight)) {
117 6
            return $this->meanWeight;
118
        }
119
120
        /** @var PackedBox $box */
121 7
        foreach ($this->list as $box) {
122 7
            $this->meanWeight += $box->getWeight();
0 ignored issues
show
Bug introduced by
The method getWeight() does not seem to exist on object<DVDoug\BoxPacker\Box>.

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