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

src/PackedBoxList.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
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
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
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
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