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

src/PackedBoxList.php (1 issue)

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