@@ -4,29 +4,29 @@ |
||
4 | 4 | * @package BoxPacker |
5 | 5 | * @author Doug Wright |
6 | 6 | */ |
7 | - namespace DVDoug\BoxPacker; |
|
7 | + namespace DVDoug\BoxPacker; |
|
8 | 8 | |
9 | - /** |
|
10 | - * List of boxes available to put items into, ordered by volume |
|
11 | - * @author Doug Wright |
|
12 | - * @package BoxPacker |
|
13 | - */ |
|
14 | - class BoxList extends \SplMinHeap { |
|
9 | + /** |
|
10 | + * List of boxes available to put items into, ordered by volume |
|
11 | + * @author Doug Wright |
|
12 | + * @package BoxPacker |
|
13 | + */ |
|
14 | + class BoxList extends \SplMinHeap { |
|
15 | 15 | |
16 | 16 | /** |
17 | 17 | * Compare elements in order to place them correctly in the heap while sifting up. |
18 | 18 | * @see \SplMinHeap::compare() |
19 | 19 | */ |
20 | 20 | public function compare($aBoxA, $aBoxB) { |
21 | - if ($aBoxB->getInnerVolume() > $aBoxA->getInnerVolume()) { |
|
21 | + if ($aBoxB->getInnerVolume() > $aBoxA->getInnerVolume()) { |
|
22 | 22 | return 1; |
23 | - } |
|
24 | - else if ($aBoxB->getInnerVolume() < $aBoxA->getInnerVolume()) { |
|
23 | + } |
|
24 | + else if ($aBoxB->getInnerVolume() < $aBoxA->getInnerVolume()) { |
|
25 | 25 | return -1; |
26 | - } |
|
27 | - else { |
|
26 | + } |
|
27 | + else { |
|
28 | 28 | return 0; |
29 | - } |
|
29 | + } |
|
30 | 30 | } |
31 | 31 | |
32 | - } |
|
32 | + } |
@@ -20,11 +20,9 @@ |
||
20 | 20 | public function compare($aBoxA, $aBoxB) { |
21 | 21 | if ($aBoxB->getInnerVolume() > $aBoxA->getInnerVolume()) { |
22 | 22 | return 1; |
23 | - } |
|
24 | - else if ($aBoxB->getInnerVolume() < $aBoxA->getInnerVolume()) { |
|
23 | + } else if ($aBoxB->getInnerVolume() < $aBoxA->getInnerVolume()) { |
|
25 | 24 | return -1; |
26 | - } |
|
27 | - else { |
|
25 | + } else { |
|
28 | 26 | return 0; |
29 | 27 | } |
30 | 28 | } |
@@ -1,17 +1,17 @@ discard block |
||
1 | 1 | <?php |
2 | 2 | /** |
3 | - * Box packing (3D bin packing, knapsack problem) |
|
4 | - * @package BoxPacker |
|
5 | - * @author Doug Wright |
|
6 | - */ |
|
7 | - namespace DVDoug\BoxPacker; |
|
8 | - |
|
9 | - /** |
|
10 | - * List of possible packed box choices, ordered by utilisation (item count, volume) |
|
11 | - * @author Doug Wright |
|
12 | - * @package BoxPacker |
|
13 | - */ |
|
14 | - class PackedBoxList extends \SplMinHeap { |
|
3 | + * Box packing (3D bin packing, knapsack problem) |
|
4 | + * @package BoxPacker |
|
5 | + * @author Doug Wright |
|
6 | + */ |
|
7 | + namespace DVDoug\BoxPacker; |
|
8 | + |
|
9 | + /** |
|
10 | + * List of possible packed box choices, ordered by utilisation (item count, volume) |
|
11 | + * @author Doug Wright |
|
12 | + * @package BoxPacker |
|
13 | + */ |
|
14 | + class PackedBoxList extends \SplMinHeap { |
|
15 | 15 | |
16 | 16 | /** |
17 | 17 | * Average (mean) weight of boxes |
@@ -30,14 +30,14 @@ discard block |
||
30 | 30 | * @see \SplMinHeap::compare() |
31 | 31 | */ |
32 | 32 | public function compare($aBoxA, $aBoxB) { |
33 | - $choice = $aBoxA->getItems()->count() - $aBoxB->getItems()->count(); |
|
34 | - if ($choice === 0) { |
|
33 | + $choice = $aBoxA->getItems()->count() - $aBoxB->getItems()->count(); |
|
34 | + if ($choice === 0) { |
|
35 | 35 | $choice = $aBoxB->getBox()->getInnerVolume() - $aBoxA->getBox()->getInnerVolume(); |
36 | - } |
|
37 | - if ($choice === 0) { |
|
36 | + } |
|
37 | + if ($choice === 0) { |
|
38 | 38 | $choice = $aBoxA->getWeight() - $aBoxB->getWeight(); |
39 | - } |
|
40 | - return $choice; |
|
39 | + } |
|
40 | + return $choice; |
|
41 | 41 | } |
42 | 42 | |
43 | 43 | /** |
@@ -45,14 +45,14 @@ discard block |
||
45 | 45 | * @return int |
46 | 46 | */ |
47 | 47 | public function reverseCompare($aBoxA, $aBoxB) { |
48 | - $choice = $aBoxB->getItems()->count() - $aBoxA->getItems()->count(); |
|
49 | - if ($choice === 0) { |
|
48 | + $choice = $aBoxB->getItems()->count() - $aBoxA->getItems()->count(); |
|
49 | + if ($choice === 0) { |
|
50 | 50 | $choice = $aBoxA->getBox()->getInnerVolume() - $aBoxB->getBox()->getInnerVolume(); |
51 | - } |
|
52 | - if ($choice === 0) { |
|
51 | + } |
|
52 | + if ($choice === 0) { |
|
53 | 53 | $choice = $aBoxB->getWeight() - $aBoxA->getWeight(); |
54 | - } |
|
55 | - return $choice; |
|
54 | + } |
|
55 | + return $choice; |
|
56 | 56 | } |
57 | 57 | |
58 | 58 | /** |
@@ -61,15 +61,15 @@ discard block |
||
61 | 61 | */ |
62 | 62 | public function getMeanWeight() { |
63 | 63 | |
64 | - if (!is_null($this->meanWeight)) { |
|
64 | + if (!is_null($this->meanWeight)) { |
|
65 | 65 | return $this->meanWeight; |
66 | - } |
|
66 | + } |
|
67 | 67 | |
68 | - foreach (clone $this as $box) { |
|
68 | + foreach (clone $this as $box) { |
|
69 | 69 | $this->meanWeight += $box->getWeight(); |
70 | - } |
|
70 | + } |
|
71 | 71 | |
72 | - return $this->meanWeight /= $this->count(); |
|
72 | + return $this->meanWeight /= $this->count(); |
|
73 | 73 | |
74 | 74 | } |
75 | 75 | |
@@ -79,17 +79,17 @@ discard block |
||
79 | 79 | */ |
80 | 80 | public function getWeightVariance() { |
81 | 81 | |
82 | - if (!is_null($this->weightVariance)) { |
|
82 | + if (!is_null($this->weightVariance)) { |
|
83 | 83 | return $this->weightVariance; |
84 | - } |
|
84 | + } |
|
85 | 85 | |
86 | - $mean = $this->getMeanWeight(); |
|
86 | + $mean = $this->getMeanWeight(); |
|
87 | 87 | |
88 | - foreach (clone $this as $box) { |
|
88 | + foreach (clone $this as $box) { |
|
89 | 89 | $this->weightVariance += pow($box->getWeight() - $mean, 2); |
90 | - } |
|
90 | + } |
|
91 | 91 | |
92 | - return $this->weightVariance /= $this->count(); |
|
92 | + return $this->weightVariance /= $this->count(); |
|
93 | 93 | |
94 | 94 | } |
95 | 95 | |
@@ -98,20 +98,20 @@ discard block |
||
98 | 98 | * @return float |
99 | 99 | */ |
100 | 100 | public function getVolumeUtilisation() { |
101 | - $itemVolume = 0; |
|
102 | - $boxVolume = 0; |
|
101 | + $itemVolume = 0; |
|
102 | + $boxVolume = 0; |
|
103 | 103 | |
104 | - /** @var PackedBox $box */ |
|
105 | - foreach (clone $this as $box) { |
|
104 | + /** @var PackedBox $box */ |
|
105 | + foreach (clone $this as $box) { |
|
106 | 106 | $boxVolume += $box->getBox()->getInnerVolume(); |
107 | 107 | |
108 | 108 | /** @var Item $item */ |
109 | 109 | foreach (clone $box->getItems() as $item ) { |
110 | - $itemVolume += $item->getVolume(); |
|
110 | + $itemVolume += $item->getVolume(); |
|
111 | + } |
|
111 | 112 | } |
112 | - } |
|
113 | 113 | |
114 | - return round($itemVolume / $boxVolume * 100, 1); |
|
114 | + return round($itemVolume / $boxVolume * 100, 1); |
|
115 | 115 | } |
116 | 116 | |
117 | 117 | /** |
@@ -119,9 +119,9 @@ discard block |
||
119 | 119 | * @param array $aBoxes |
120 | 120 | */ |
121 | 121 | public function insertFromArray(array $aBoxes) { |
122 | - foreach ($aBoxes as $box) { |
|
122 | + foreach ($aBoxes as $box) { |
|
123 | 123 | $this->insert($box); |
124 | - } |
|
124 | + } |
|
125 | 125 | } |
126 | 126 | |
127 | - } |
|
127 | + } |
@@ -106,7 +106,7 @@ |
||
106 | 106 | $boxVolume += $box->getBox()->getInnerVolume(); |
107 | 107 | |
108 | 108 | /** @var Item $item */ |
109 | - foreach (clone $box->getItems() as $item ) { |
|
109 | + foreach (clone $box->getItems() as $item) { |
|
110 | 110 | $itemVolume += $item->getVolume(); |
111 | 111 | } |
112 | 112 | } |
@@ -1,17 +1,17 @@ discard block |
||
1 | 1 | <?php |
2 | 2 | /** |
3 | - * Box packing (3D bin packing, knapsack problem) |
|
4 | - * @package BoxPacker |
|
5 | - * @author Doug Wright |
|
6 | - */ |
|
7 | - namespace DVDoug\BoxPacker; |
|
3 | + * Box packing (3D bin packing, knapsack problem) |
|
4 | + * @package BoxPacker |
|
5 | + * @author Doug Wright |
|
6 | + */ |
|
7 | + namespace DVDoug\BoxPacker; |
|
8 | 8 | |
9 | - /** |
|
10 | - * A "box" (or envelope?) to pack items into |
|
11 | - * @author Doug Wright |
|
12 | - * @package BoxPacker |
|
13 | - */ |
|
14 | - interface Box { |
|
9 | + /** |
|
10 | + * A "box" (or envelope?) to pack items into |
|
11 | + * @author Doug Wright |
|
12 | + * @package BoxPacker |
|
13 | + */ |
|
14 | + interface Box { |
|
15 | 15 | |
16 | 16 | /** |
17 | 17 | * Reference for box type (e.g. SKU or description) |
@@ -73,4 +73,4 @@ discard block |
||
73 | 73 | */ |
74 | 74 | public function getMaxWeight(); |
75 | 75 | |
76 | - } |
|
76 | + } |
@@ -1,17 +1,17 @@ discard block |
||
1 | 1 | <?php |
2 | 2 | /** |
3 | - * Box packing (3D bin packing, knapsack problem) |
|
4 | - * @package BoxPacker |
|
5 | - * @author Doug Wright |
|
6 | - */ |
|
7 | - namespace DVDoug\BoxPacker; |
|
3 | + * Box packing (3D bin packing, knapsack problem) |
|
4 | + * @package BoxPacker |
|
5 | + * @author Doug Wright |
|
6 | + */ |
|
7 | + namespace DVDoug\BoxPacker; |
|
8 | 8 | |
9 | - /** |
|
10 | - * An item to be packed |
|
11 | - * @author Doug Wright |
|
12 | - * @package BoxPacker |
|
13 | - */ |
|
14 | - interface Item { |
|
9 | + /** |
|
10 | + * An item to be packed |
|
11 | + * @author Doug Wright |
|
12 | + * @package BoxPacker |
|
13 | + */ |
|
14 | + interface Item { |
|
15 | 15 | |
16 | 16 | /** |
17 | 17 | * Item SKU etc |
@@ -49,4 +49,4 @@ discard block |
||
49 | 49 | */ |
50 | 50 | public function getVolume(); |
51 | 51 | |
52 | - } |
|
52 | + } |
@@ -1,22 +1,22 @@ discard block |
||
1 | 1 | <?php |
2 | 2 | /** |
3 | - * Box packing (3D bin packing, knapsack problem) |
|
4 | - * @package BoxPacker |
|
5 | - * @author Doug Wright |
|
6 | - */ |
|
7 | - namespace DVDoug\BoxPacker; |
|
8 | - |
|
9 | - use Psr\Log\LoggerAwareInterface; |
|
10 | - use Psr\Log\LoggerAwareTrait; |
|
11 | - use Psr\Log\LogLevel; |
|
12 | - use Psr\Log\NullLogger; |
|
13 | - |
|
14 | - /** |
|
15 | - * Actual packer |
|
16 | - * @author Doug Wright |
|
17 | - * @package BoxPacker |
|
18 | - */ |
|
19 | - class Packer implements LoggerAwareInterface { |
|
3 | + * Box packing (3D bin packing, knapsack problem) |
|
4 | + * @package BoxPacker |
|
5 | + * @author Doug Wright |
|
6 | + */ |
|
7 | + namespace DVDoug\BoxPacker; |
|
8 | + |
|
9 | + use Psr\Log\LoggerAwareInterface; |
|
10 | + use Psr\Log\LoggerAwareTrait; |
|
11 | + use Psr\Log\LogLevel; |
|
12 | + use Psr\Log\NullLogger; |
|
13 | + |
|
14 | + /** |
|
15 | + * Actual packer |
|
16 | + * @author Doug Wright |
|
17 | + * @package BoxPacker |
|
18 | + */ |
|
19 | + class Packer implements LoggerAwareInterface { |
|
20 | 20 | use LoggerAwareTrait; |
21 | 21 | |
22 | 22 | /** |
@@ -35,10 +35,10 @@ discard block |
||
35 | 35 | * Constructor |
36 | 36 | */ |
37 | 37 | public function __construct() { |
38 | - $this->items = new ItemList(); |
|
39 | - $this->boxes = new BoxList(); |
|
38 | + $this->items = new ItemList(); |
|
39 | + $this->boxes = new BoxList(); |
|
40 | 40 | |
41 | - $this->logger = new NullLogger(); |
|
41 | + $this->logger = new NullLogger(); |
|
42 | 42 | } |
43 | 43 | |
44 | 44 | /** |
@@ -47,10 +47,10 @@ discard block |
||
47 | 47 | * @param int $aQty |
48 | 48 | */ |
49 | 49 | public function addItem(Item $aItem, $aQty = 1) { |
50 | - for ($i = 0; $i < $aQty; $i++) { |
|
50 | + for ($i = 0; $i < $aQty; $i++) { |
|
51 | 51 | $this->items->insert($aItem); |
52 | - } |
|
53 | - $this->logger->log(LogLevel::INFO, "added {$aQty} x {$aItem->getDescription()}"); |
|
52 | + } |
|
53 | + $this->logger->log(LogLevel::INFO, "added {$aQty} x {$aItem->getDescription()}"); |
|
54 | 54 | } |
55 | 55 | |
56 | 56 | /** |
@@ -58,18 +58,18 @@ discard block |
||
58 | 58 | * @param \Traversable $aItems |
59 | 59 | */ |
60 | 60 | public function setItems($aItems) { |
61 | - if ($aItems instanceof ItemList) { |
|
61 | + if ($aItems instanceof ItemList) { |
|
62 | 62 | $this->items = clone $aItems; |
63 | - } |
|
64 | - else if (is_array($aItems)) { |
|
63 | + } |
|
64 | + else if (is_array($aItems)) { |
|
65 | 65 | $this->items = new ItemList(); |
66 | 66 | foreach ($aItems as $item) { |
67 | - $this->items->insert($item); |
|
67 | + $this->items->insert($item); |
|
68 | 68 | } |
69 | - } |
|
70 | - else { |
|
69 | + } |
|
70 | + else { |
|
71 | 71 | throw new \RuntimeException('Not a valid list of items'); |
72 | - } |
|
72 | + } |
|
73 | 73 | } |
74 | 74 | |
75 | 75 | /** |
@@ -77,8 +77,8 @@ discard block |
||
77 | 77 | * @param Box $aBox |
78 | 78 | */ |
79 | 79 | public function addBox(Box $aBox) { |
80 | - $this->boxes->insert($aBox); |
|
81 | - $this->logger->log(LogLevel::INFO, "added box {$aBox->getReference()}"); |
|
80 | + $this->boxes->insert($aBox); |
|
81 | + $this->logger->log(LogLevel::INFO, "added box {$aBox->getReference()}"); |
|
82 | 82 | } |
83 | 83 | |
84 | 84 | /** |
@@ -86,7 +86,7 @@ discard block |
||
86 | 86 | * @param BoxList $aBoxList |
87 | 87 | */ |
88 | 88 | public function setBoxes(BoxList $aBoxList) { |
89 | - $this->boxes = clone $aBoxList; |
|
89 | + $this->boxes = clone $aBoxList; |
|
90 | 90 | } |
91 | 91 | |
92 | 92 | /** |
@@ -96,15 +96,15 @@ discard block |
||
96 | 96 | * @return PackedBoxList |
97 | 97 | */ |
98 | 98 | public function pack() { |
99 | - $packedBoxes = $this->doVolumePacking(); |
|
99 | + $packedBoxes = $this->doVolumePacking(); |
|
100 | 100 | |
101 | - //If we have multiple boxes, try and optimise/even-out weight distribution |
|
102 | - if ($packedBoxes->count() > 1) { |
|
101 | + //If we have multiple boxes, try and optimise/even-out weight distribution |
|
102 | + if ($packedBoxes->count() > 1) { |
|
103 | 103 | $packedBoxes = $this->redistributeWeight($packedBoxes); |
104 | - } |
|
104 | + } |
|
105 | 105 | |
106 | - $this->logger->log(LogLevel::INFO, "packing completed, {$packedBoxes->count()} boxes"); |
|
107 | - return $packedBoxes; |
|
106 | + $this->logger->log(LogLevel::INFO, "packing completed, {$packedBoxes->count()} boxes"); |
|
107 | + return $packedBoxes; |
|
108 | 108 | } |
109 | 109 | |
110 | 110 | /** |
@@ -115,53 +115,53 @@ discard block |
||
115 | 115 | */ |
116 | 116 | public function doVolumePacking() { |
117 | 117 | |
118 | - $packedBoxes = new PackedBoxList; |
|
118 | + $packedBoxes = new PackedBoxList; |
|
119 | 119 | |
120 | - //Keep going until everything packed |
|
121 | - while ($this->items->count()) { |
|
120 | + //Keep going until everything packed |
|
121 | + while ($this->items->count()) { |
|
122 | 122 | $boxesToEvaluate = clone $this->boxes; |
123 | 123 | $packedBoxesIteration = new PackedBoxList; |
124 | 124 | |
125 | 125 | //Loop through boxes starting with smallest, see what happens |
126 | 126 | while (!$boxesToEvaluate->isEmpty()) { |
127 | - $box = $boxesToEvaluate->extract(); |
|
128 | - $packedBox = $this->packIntoBox($box, clone $this->items); |
|
129 | - if ($packedBox->getItems()->count()) { |
|
127 | + $box = $boxesToEvaluate->extract(); |
|
128 | + $packedBox = $this->packIntoBox($box, clone $this->items); |
|
129 | + if ($packedBox->getItems()->count()) { |
|
130 | 130 | $packedBoxesIteration->insert($packedBox); |
131 | 131 | |
132 | 132 | //Have we found a single box that contains everything? |
133 | 133 | if ($packedBox->getItems()->count() === $this->items->count()) { |
134 | - break; |
|
134 | + break; |
|
135 | + } |
|
135 | 136 | } |
136 | - } |
|
137 | 137 | } |
138 | 138 | |
139 | 139 | //Check iteration was productive |
140 | 140 | if ($packedBoxesIteration->isEmpty()) { |
141 | - throw new \RuntimeException('Item ' . $this->items->top()->getDescription() . ' is too large to fit into any box'); |
|
141 | + throw new \RuntimeException('Item ' . $this->items->top()->getDescription() . ' is too large to fit into any box'); |
|
142 | 142 | } |
143 | 143 | |
144 | 144 | //Find best box of iteration, and remove packed items from unpacked list |
145 | 145 | $bestBox = $packedBoxesIteration->top(); |
146 | 146 | $unPackedItems = $this->items->asArray(); |
147 | 147 | foreach(clone $bestBox->getItems() as $packedItem) { |
148 | - foreach ($unPackedItems as $unpackedKey => $unpackedItem) { |
|
148 | + foreach ($unPackedItems as $unpackedKey => $unpackedItem) { |
|
149 | 149 | if ($packedItem === $unpackedItem) { |
150 | - unset($unPackedItems[$unpackedKey]); |
|
151 | - break; |
|
150 | + unset($unPackedItems[$unpackedKey]); |
|
151 | + break; |
|
152 | + } |
|
152 | 153 | } |
153 | - } |
|
154 | 154 | } |
155 | 155 | $unpackedItemList = new ItemList(); |
156 | 156 | foreach ($unPackedItems as $unpackedItem) { |
157 | - $unpackedItemList->insert($unpackedItem); |
|
157 | + $unpackedItemList->insert($unpackedItem); |
|
158 | 158 | } |
159 | 159 | $this->items = $unpackedItemList; |
160 | 160 | $packedBoxes->insert($bestBox); |
161 | 161 | |
162 | - } |
|
162 | + } |
|
163 | 163 | |
164 | - return $packedBoxes; |
|
164 | + return $packedBoxes; |
|
165 | 165 | } |
166 | 166 | |
167 | 167 | /** |
@@ -172,54 +172,54 @@ discard block |
||
172 | 172 | */ |
173 | 173 | public function redistributeWeight(PackedBoxList $aPackedBoxes) { |
174 | 174 | |
175 | - $targetWeight = $aPackedBoxes->getMeanWeight(); |
|
176 | - $this->logger->log(LogLevel::DEBUG, "repacking for weight distribution, weight variance {$aPackedBoxes->getWeightVariance()}, target weight {$targetWeight}"); |
|
175 | + $targetWeight = $aPackedBoxes->getMeanWeight(); |
|
176 | + $this->logger->log(LogLevel::DEBUG, "repacking for weight distribution, weight variance {$aPackedBoxes->getWeightVariance()}, target weight {$targetWeight}"); |
|
177 | 177 | |
178 | - $packedBoxes = new PackedBoxList; |
|
178 | + $packedBoxes = new PackedBoxList; |
|
179 | 179 | |
180 | - $overWeightBoxes = []; |
|
181 | - $underWeightBoxes = []; |
|
182 | - foreach (clone $aPackedBoxes as $packedBox) { |
|
180 | + $overWeightBoxes = []; |
|
181 | + $underWeightBoxes = []; |
|
182 | + foreach (clone $aPackedBoxes as $packedBox) { |
|
183 | 183 | $boxWeight = $packedBox->getWeight(); |
184 | 184 | if ($boxWeight > $targetWeight) { |
185 | - $overWeightBoxes[] = $packedBox; |
|
185 | + $overWeightBoxes[] = $packedBox; |
|
186 | 186 | } |
187 | 187 | else if ($boxWeight < $targetWeight) { |
188 | - $underWeightBoxes[] = $packedBox; |
|
188 | + $underWeightBoxes[] = $packedBox; |
|
189 | 189 | } |
190 | 190 | else { |
191 | - $packedBoxes->insert($packedBox); //target weight, so we'll keep these |
|
191 | + $packedBoxes->insert($packedBox); //target weight, so we'll keep these |
|
192 | + } |
|
192 | 193 | } |
193 | - } |
|
194 | 194 | |
195 | - do { //Keep moving items from most overweight box to most underweight box |
|
195 | + do { //Keep moving items from most overweight box to most underweight box |
|
196 | 196 | $tryRepack = false; |
197 | 197 | $this->logger->log(LogLevel::DEBUG, 'boxes under/over target: ' . count($underWeightBoxes) . '/' . count($overWeightBoxes)); |
198 | 198 | |
199 | 199 | foreach ($underWeightBoxes as $u => $underWeightBox) { |
200 | - $this->logger->log(LogLevel::DEBUG, 'Underweight Box ' . $u); |
|
201 | - foreach ($overWeightBoxes as $o => $overWeightBox) { |
|
200 | + $this->logger->log(LogLevel::DEBUG, 'Underweight Box ' . $u); |
|
201 | + foreach ($overWeightBoxes as $o => $overWeightBox) { |
|
202 | 202 | $this->logger->log(LogLevel::DEBUG, 'Overweight Box ' . $o); |
203 | 203 | $overWeightBoxItems = $overWeightBox->getItems()->asArray(); |
204 | 204 | |
205 | 205 | //For each item in the heavier box, try and move it to the lighter one |
206 | 206 | foreach ($overWeightBoxItems as $oi => $overWeightBoxItem) { |
207 | - $this->logger->log(LogLevel::DEBUG, 'Overweight Item ' . $oi); |
|
208 | - if ($underWeightBox->getWeight() + $overWeightBoxItem->getWeight() > $targetWeight) { |
|
207 | + $this->logger->log(LogLevel::DEBUG, 'Overweight Item ' . $oi); |
|
208 | + if ($underWeightBox->getWeight() + $overWeightBoxItem->getWeight() > $targetWeight) { |
|
209 | 209 | $this->logger->log(LogLevel::DEBUG, 'Skipping item for hindering weight distribution'); |
210 | 210 | continue; //skip if moving this item would hinder rather than help weight distribution |
211 | - } |
|
211 | + } |
|
212 | 212 | |
213 | - $newItemsForLighterBox = clone $underWeightBox->getItems(); |
|
214 | - $newItemsForLighterBox->insert($overWeightBoxItem); |
|
213 | + $newItemsForLighterBox = clone $underWeightBox->getItems(); |
|
214 | + $newItemsForLighterBox->insert($overWeightBoxItem); |
|
215 | 215 | |
216 | - $newLighterBoxPacker = new Packer(); //we may need a bigger box |
|
217 | - $newLighterBoxPacker->setBoxes($this->boxes); |
|
218 | - $newLighterBoxPacker->setItems($newItemsForLighterBox); |
|
219 | - $this->logger->log(LogLevel::INFO, "[ATTEMPTING TO PACK LIGHTER BOX]"); |
|
220 | - $newLighterBox = $newLighterBoxPacker->doVolumePacking()->extract(); |
|
216 | + $newLighterBoxPacker = new Packer(); //we may need a bigger box |
|
217 | + $newLighterBoxPacker->setBoxes($this->boxes); |
|
218 | + $newLighterBoxPacker->setItems($newItemsForLighterBox); |
|
219 | + $this->logger->log(LogLevel::INFO, "[ATTEMPTING TO PACK LIGHTER BOX]"); |
|
220 | + $newLighterBox = $newLighterBoxPacker->doVolumePacking()->extract(); |
|
221 | 221 | |
222 | - if ($newLighterBox->getItems()->count() === $newItemsForLighterBox->count()) { //new item fits |
|
222 | + if ($newLighterBox->getItems()->count() === $newItemsForLighterBox->count()) { //new item fits |
|
223 | 223 | $this->logger->log(LogLevel::DEBUG, 'New item fits'); |
224 | 224 | unset($overWeightBoxItems[$oi]); //now packed in different box |
225 | 225 | |
@@ -230,8 +230,8 @@ discard block |
||
230 | 230 | $this->logger->log(LogLevel::INFO, "[ATTEMPTING TO PACK HEAVIER BOX]"); |
231 | 231 | $newHeavierBoxes = $newHeavierBoxPacker->doVolumePacking(); |
232 | 232 | if (count($newHeavierBoxes) > 1) { //found an edge case in packing algorithm that *increased* box count |
233 | - $this->logger->log(LogLevel::INFO, "[REDISTRIBUTING WEIGHT] Abandoning redistribution, because new packing is less efficient than original"); |
|
234 | - return $aPackedBoxes; |
|
233 | + $this->logger->log(LogLevel::INFO, "[REDISTRIBUTING WEIGHT] Abandoning redistribution, because new packing is less efficient than original"); |
|
234 | + return $aPackedBoxes; |
|
235 | 235 | } |
236 | 236 | |
237 | 237 | $overWeightBoxes[$o] = $newHeavierBoxes->extract(); |
@@ -241,17 +241,17 @@ discard block |
||
241 | 241 | usort($overWeightBoxes, [$packedBoxes, 'reverseCompare']); |
242 | 242 | usort($underWeightBoxes, [$packedBoxes, 'reverseCompare']); |
243 | 243 | break 3; |
244 | - } |
|
244 | + } |
|
245 | + } |
|
245 | 246 | } |
246 | - } |
|
247 | 247 | } |
248 | - } while ($tryRepack); |
|
248 | + } while ($tryRepack); |
|
249 | 249 | |
250 | - //Combine back into a single list |
|
251 | - $packedBoxes->insertFromArray($overWeightBoxes); |
|
252 | - $packedBoxes->insertFromArray($underWeightBoxes); |
|
250 | + //Combine back into a single list |
|
251 | + $packedBoxes->insertFromArray($overWeightBoxes); |
|
252 | + $packedBoxes->insertFromArray($underWeightBoxes); |
|
253 | 253 | |
254 | - return $packedBoxes; |
|
254 | + return $packedBoxes; |
|
255 | 255 | } |
256 | 256 | |
257 | 257 | |
@@ -262,22 +262,22 @@ discard block |
||
262 | 262 | * @return PackedBox packed box |
263 | 263 | */ |
264 | 264 | public function packIntoBox(Box $aBox, ItemList $aItems) { |
265 | - $this->logger->log(LogLevel::DEBUG, "[EVALUATING BOX] {$aBox->getReference()}"); |
|
265 | + $this->logger->log(LogLevel::DEBUG, "[EVALUATING BOX] {$aBox->getReference()}"); |
|
266 | 266 | |
267 | - $packedItems = new ItemList; |
|
268 | - $remainingDepth = $aBox->getInnerDepth(); |
|
269 | - $remainingWeight = $aBox->getMaxWeight() - $aBox->getEmptyWeight(); |
|
270 | - $remainingWidth = $aBox->getInnerWidth(); |
|
271 | - $remainingLength = $aBox->getInnerLength(); |
|
267 | + $packedItems = new ItemList; |
|
268 | + $remainingDepth = $aBox->getInnerDepth(); |
|
269 | + $remainingWeight = $aBox->getMaxWeight() - $aBox->getEmptyWeight(); |
|
270 | + $remainingWidth = $aBox->getInnerWidth(); |
|
271 | + $remainingLength = $aBox->getInnerLength(); |
|
272 | 272 | |
273 | - $layerWidth = $layerLength = $layerDepth = 0; |
|
274 | - while(!$aItems->isEmpty()) { |
|
273 | + $layerWidth = $layerLength = $layerDepth = 0; |
|
274 | + while(!$aItems->isEmpty()) { |
|
275 | 275 | |
276 | 276 | $itemToPack = $aItems->top(); |
277 | 277 | |
278 | 278 | if ($itemToPack->getDepth() > $remainingDepth || $itemToPack->getWeight() > $remainingWeight) { |
279 | - $aItems->extract(); |
|
280 | - continue; |
|
279 | + $aItems->extract(); |
|
280 | + continue; |
|
281 | 281 | } |
282 | 282 | |
283 | 283 | $this->logger->log(LogLevel::DEBUG, "evaluating item {$itemToPack->getDescription()}"); |
@@ -292,67 +292,67 @@ discard block |
||
292 | 292 | |
293 | 293 | if ($fitsSameGap >= 0 || $fitsRotatedGap >= 0) { |
294 | 294 | |
295 | - $packedItems->insert($aItems->extract()); |
|
296 | - $remainingWeight -= $itemToPack->getWeight(); |
|
295 | + $packedItems->insert($aItems->extract()); |
|
296 | + $remainingWeight -= $itemToPack->getWeight(); |
|
297 | 297 | |
298 | - if ($fitsRotatedGap < 0 || |
|
298 | + if ($fitsRotatedGap < 0 || |
|
299 | 299 | ($fitsSameGap >= 0 && $fitsSameGap <= $fitsRotatedGap) || |
300 | 300 | ($itemWidth <= $remainingWidth && !$aItems->isEmpty() && $aItems->top() == $itemToPack && $remainingLength >= 2 * $itemLength)) { |
301 | 301 | $this->logger->log(LogLevel::DEBUG, "fits (better) unrotated"); |
302 | 302 | $remainingLength -= $itemLength; |
303 | 303 | $layerLength += $itemLength; |
304 | 304 | $layerWidth = max($itemWidth, $layerWidth); |
305 | - } |
|
306 | - else { |
|
305 | + } |
|
306 | + else { |
|
307 | 307 | $this->logger->log(LogLevel::DEBUG, "fits (better) rotated"); |
308 | 308 | $remainingLength -= $itemWidth; |
309 | 309 | $layerLength += $itemWidth; |
310 | 310 | $layerWidth = max($itemLength, $layerWidth); |
311 | - } |
|
312 | - $layerDepth = max($layerDepth, $itemToPack->getDepth()); //greater than 0, items will always be less deep |
|
311 | + } |
|
312 | + $layerDepth = max($layerDepth, $itemToPack->getDepth()); //greater than 0, items will always be less deep |
|
313 | 313 | |
314 | - //allow items to be stacked in place within the same footprint up to current layerdepth |
|
315 | - $maxStackDepth = $layerDepth - $itemToPack->getDepth(); |
|
316 | - while(!$aItems->isEmpty()) { |
|
314 | + //allow items to be stacked in place within the same footprint up to current layerdepth |
|
315 | + $maxStackDepth = $layerDepth - $itemToPack->getDepth(); |
|
316 | + while(!$aItems->isEmpty()) { |
|
317 | 317 | $potentialStackItem = $aItems->top(); |
318 | 318 | if ($potentialStackItem->getDepth() <= $maxStackDepth && |
319 | 319 | $potentialStackItem->getWeight() <= $remainingWeight && |
320 | 320 | $potentialStackItem->getWidth() <= $itemToPack->getWidth() && |
321 | 321 | $potentialStackItem->getLength() <= $itemToPack->getLength()) { |
322 | - $remainingWeight -= $potentialStackItem->getWeight(); |
|
323 | - $maxStackDepth -= $potentialStackItem->getDepth(); |
|
324 | - $packedItems->insert($aItems->extract()); |
|
322 | + $remainingWeight -= $potentialStackItem->getWeight(); |
|
323 | + $maxStackDepth -= $potentialStackItem->getDepth(); |
|
324 | + $packedItems->insert($aItems->extract()); |
|
325 | 325 | } |
326 | 326 | else { |
327 | - break; |
|
327 | + break; |
|
328 | + } |
|
328 | 329 | } |
329 | - } |
|
330 | 330 | } |
331 | 331 | else { |
332 | - if ($remainingWidth >= min($itemWidth, $itemLength) && $layerDepth > 0 && $layerWidth > 0 && $layerLength > 0) { |
|
332 | + if ($remainingWidth >= min($itemWidth, $itemLength) && $layerDepth > 0 && $layerWidth > 0 && $layerLength > 0) { |
|
333 | 333 | $this->logger->log(LogLevel::DEBUG, "No more fit in lengthwise, resetting for new row"); |
334 | 334 | $remainingLength += $layerLength; |
335 | 335 | $remainingWidth -= $layerWidth; |
336 | 336 | $layerWidth = $layerLength = 0; |
337 | 337 | continue; |
338 | - } |
|
338 | + } |
|
339 | 339 | |
340 | - if ($remainingLength < min($itemWidth, $itemLength) || $layerDepth == 0) { |
|
340 | + if ($remainingLength < min($itemWidth, $itemLength) || $layerDepth == 0) { |
|
341 | 341 | $this->logger->log(LogLevel::DEBUG, "doesn't fit on layer even when empty"); |
342 | 342 | $aItems->extract(); |
343 | 343 | continue; |
344 | - } |
|
344 | + } |
|
345 | 345 | |
346 | - $remainingWidth = $layerWidth ? min(floor($layerWidth * 1.1), $aBox->getInnerWidth()) : $aBox->getInnerWidth(); |
|
347 | - $remainingLength = $layerLength ? min(floor($layerLength * 1.1), $aBox->getInnerLength()) : $aBox->getInnerLength(); |
|
348 | - $remainingDepth -= $layerDepth; |
|
346 | + $remainingWidth = $layerWidth ? min(floor($layerWidth * 1.1), $aBox->getInnerWidth()) : $aBox->getInnerWidth(); |
|
347 | + $remainingLength = $layerLength ? min(floor($layerLength * 1.1), $aBox->getInnerLength()) : $aBox->getInnerLength(); |
|
348 | + $remainingDepth -= $layerDepth; |
|
349 | 349 | |
350 | - $layerWidth = $layerLength = $layerDepth = 0; |
|
351 | - $this->logger->log(LogLevel::DEBUG, "doesn't fit, so starting next vertical layer"); |
|
350 | + $layerWidth = $layerLength = $layerDepth = 0; |
|
351 | + $this->logger->log(LogLevel::DEBUG, "doesn't fit, so starting next vertical layer"); |
|
352 | + } |
|
352 | 353 | } |
353 | - } |
|
354 | - $this->logger->log(LogLevel::DEBUG, "done with this box"); |
|
355 | - return new PackedBox($aBox, $packedItems, $remainingWidth, $remainingLength, $remainingDepth, $remainingWeight); |
|
354 | + $this->logger->log(LogLevel::DEBUG, "done with this box"); |
|
355 | + return new PackedBox($aBox, $packedItems, $remainingWidth, $remainingLength, $remainingDepth, $remainingWeight); |
|
356 | 356 | } |
357 | 357 | |
358 | 358 | /** |
@@ -363,7 +363,7 @@ discard block |
||
363 | 363 | * @return ItemList items packed into box |
364 | 364 | */ |
365 | 365 | public function packBox(Box $aBox, ItemList $aItems) { |
366 | - $packedBox = $this->packIntoBox($aBox, $aItems); |
|
367 | - return $packedBox->getItems(); |
|
366 | + $packedBox = $this->packIntoBox($aBox, $aItems); |
|
367 | + return $packedBox->getItems(); |
|
368 | + } |
|
368 | 369 | } |
369 | - } |
@@ -144,7 +144,7 @@ discard block |
||
144 | 144 | //Find best box of iteration, and remove packed items from unpacked list |
145 | 145 | $bestBox = $packedBoxesIteration->top(); |
146 | 146 | $unPackedItems = $this->items->asArray(); |
147 | - foreach(clone $bestBox->getItems() as $packedItem) { |
|
147 | + foreach (clone $bestBox->getItems() as $packedItem) { |
|
148 | 148 | foreach ($unPackedItems as $unpackedKey => $unpackedItem) { |
149 | 149 | if ($packedItem === $unpackedItem) { |
150 | 150 | unset($unPackedItems[$unpackedKey]); |
@@ -173,7 +173,7 @@ discard block |
||
173 | 173 | public function redistributeWeight(PackedBoxList $aPackedBoxes) { |
174 | 174 | |
175 | 175 | $targetWeight = $aPackedBoxes->getMeanWeight(); |
176 | - $this->logger->log(LogLevel::DEBUG, "repacking for weight distribution, weight variance {$aPackedBoxes->getWeightVariance()}, target weight {$targetWeight}"); |
|
176 | + $this->logger->log(LogLevel::DEBUG, "repacking for weight distribution, weight variance {$aPackedBoxes->getWeightVariance()}, target weight {$targetWeight}"); |
|
177 | 177 | |
178 | 178 | $packedBoxes = new PackedBoxList; |
179 | 179 | |
@@ -194,19 +194,19 @@ discard block |
||
194 | 194 | |
195 | 195 | do { //Keep moving items from most overweight box to most underweight box |
196 | 196 | $tryRepack = false; |
197 | - $this->logger->log(LogLevel::DEBUG, 'boxes under/over target: ' . count($underWeightBoxes) . '/' . count($overWeightBoxes)); |
|
197 | + $this->logger->log(LogLevel::DEBUG, 'boxes under/over target: ' . count($underWeightBoxes) . '/' . count($overWeightBoxes)); |
|
198 | 198 | |
199 | 199 | foreach ($underWeightBoxes as $u => $underWeightBox) { |
200 | - $this->logger->log(LogLevel::DEBUG, 'Underweight Box ' . $u); |
|
200 | + $this->logger->log(LogLevel::DEBUG, 'Underweight Box ' . $u); |
|
201 | 201 | foreach ($overWeightBoxes as $o => $overWeightBox) { |
202 | - $this->logger->log(LogLevel::DEBUG, 'Overweight Box ' . $o); |
|
202 | + $this->logger->log(LogLevel::DEBUG, 'Overweight Box ' . $o); |
|
203 | 203 | $overWeightBoxItems = $overWeightBox->getItems()->asArray(); |
204 | 204 | |
205 | 205 | //For each item in the heavier box, try and move it to the lighter one |
206 | 206 | foreach ($overWeightBoxItems as $oi => $overWeightBoxItem) { |
207 | - $this->logger->log(LogLevel::DEBUG, 'Overweight Item ' . $oi); |
|
207 | + $this->logger->log(LogLevel::DEBUG, 'Overweight Item ' . $oi); |
|
208 | 208 | if ($underWeightBox->getWeight() + $overWeightBoxItem->getWeight() > $targetWeight) { |
209 | - $this->logger->log(LogLevel::DEBUG, 'Skipping item for hindering weight distribution'); |
|
209 | + $this->logger->log(LogLevel::DEBUG, 'Skipping item for hindering weight distribution'); |
|
210 | 210 | continue; //skip if moving this item would hinder rather than help weight distribution |
211 | 211 | } |
212 | 212 | |
@@ -216,21 +216,21 @@ discard block |
||
216 | 216 | $newLighterBoxPacker = new Packer(); //we may need a bigger box |
217 | 217 | $newLighterBoxPacker->setBoxes($this->boxes); |
218 | 218 | $newLighterBoxPacker->setItems($newItemsForLighterBox); |
219 | - $this->logger->log(LogLevel::INFO, "[ATTEMPTING TO PACK LIGHTER BOX]"); |
|
219 | + $this->logger->log(LogLevel::INFO, "[ATTEMPTING TO PACK LIGHTER BOX]"); |
|
220 | 220 | $newLighterBox = $newLighterBoxPacker->doVolumePacking()->extract(); |
221 | 221 | |
222 | 222 | if ($newLighterBox->getItems()->count() === $newItemsForLighterBox->count()) { //new item fits |
223 | - $this->logger->log(LogLevel::DEBUG, 'New item fits'); |
|
223 | + $this->logger->log(LogLevel::DEBUG, 'New item fits'); |
|
224 | 224 | unset($overWeightBoxItems[$oi]); //now packed in different box |
225 | 225 | |
226 | 226 | $newHeavierBoxPacker = new Packer(); //we may be able to use a smaller box |
227 | 227 | $newHeavierBoxPacker->setBoxes($this->boxes); |
228 | 228 | $newHeavierBoxPacker->setItems($overWeightBoxItems); |
229 | 229 | |
230 | - $this->logger->log(LogLevel::INFO, "[ATTEMPTING TO PACK HEAVIER BOX]"); |
|
230 | + $this->logger->log(LogLevel::INFO, "[ATTEMPTING TO PACK HEAVIER BOX]"); |
|
231 | 231 | $newHeavierBoxes = $newHeavierBoxPacker->doVolumePacking(); |
232 | 232 | if (count($newHeavierBoxes) > 1) { //found an edge case in packing algorithm that *increased* box count |
233 | - $this->logger->log(LogLevel::INFO, "[REDISTRIBUTING WEIGHT] Abandoning redistribution, because new packing is less efficient than original"); |
|
233 | + $this->logger->log(LogLevel::INFO, "[REDISTRIBUTING WEIGHT] Abandoning redistribution, because new packing is less efficient than original"); |
|
234 | 234 | return $aPackedBoxes; |
235 | 235 | } |
236 | 236 | |
@@ -262,7 +262,7 @@ discard block |
||
262 | 262 | * @return PackedBox packed box |
263 | 263 | */ |
264 | 264 | public function packIntoBox(Box $aBox, ItemList $aItems) { |
265 | - $this->logger->log(LogLevel::DEBUG, "[EVALUATING BOX] {$aBox->getReference()}"); |
|
265 | + $this->logger->log(LogLevel::DEBUG, "[EVALUATING BOX] {$aBox->getReference()}"); |
|
266 | 266 | |
267 | 267 | $packedItems = new ItemList; |
268 | 268 | $remainingDepth = $aBox->getInnerDepth(); |
@@ -271,7 +271,7 @@ discard block |
||
271 | 271 | $remainingLength = $aBox->getInnerLength(); |
272 | 272 | |
273 | 273 | $layerWidth = $layerLength = $layerDepth = 0; |
274 | - while(!$aItems->isEmpty()) { |
|
274 | + while (!$aItems->isEmpty()) { |
|
275 | 275 | |
276 | 276 | $itemToPack = $aItems->top(); |
277 | 277 | |
@@ -280,9 +280,9 @@ discard block |
||
280 | 280 | continue; |
281 | 281 | } |
282 | 282 | |
283 | - $this->logger->log(LogLevel::DEBUG, "evaluating item {$itemToPack->getDescription()}"); |
|
284 | - $this->logger->log(LogLevel::DEBUG, "remaining width: {$remainingWidth}, length: {$remainingLength}, depth: {$remainingDepth}"); |
|
285 | - $this->logger->log(LogLevel::DEBUG, "layerWidth: {$layerWidth}, layerLength: {$layerLength}, layerDepth: {$layerDepth}"); |
|
283 | + $this->logger->log(LogLevel::DEBUG, "evaluating item {$itemToPack->getDescription()}"); |
|
284 | + $this->logger->log(LogLevel::DEBUG, "remaining width: {$remainingWidth}, length: {$remainingLength}, depth: {$remainingDepth}"); |
|
285 | + $this->logger->log(LogLevel::DEBUG, "layerWidth: {$layerWidth}, layerLength: {$layerLength}, layerDepth: {$layerDepth}"); |
|
286 | 286 | |
287 | 287 | $itemWidth = $itemToPack->getWidth(); |
288 | 288 | $itemLength = $itemToPack->getLength(); |
@@ -298,13 +298,13 @@ discard block |
||
298 | 298 | if ($fitsRotatedGap < 0 || |
299 | 299 | ($fitsSameGap >= 0 && $fitsSameGap <= $fitsRotatedGap) || |
300 | 300 | ($itemWidth <= $remainingWidth && !$aItems->isEmpty() && $aItems->top() == $itemToPack && $remainingLength >= 2 * $itemLength)) { |
301 | - $this->logger->log(LogLevel::DEBUG, "fits (better) unrotated"); |
|
301 | + $this->logger->log(LogLevel::DEBUG, "fits (better) unrotated"); |
|
302 | 302 | $remainingLength -= $itemLength; |
303 | 303 | $layerLength += $itemLength; |
304 | 304 | $layerWidth = max($itemWidth, $layerWidth); |
305 | 305 | } |
306 | 306 | else { |
307 | - $this->logger->log(LogLevel::DEBUG, "fits (better) rotated"); |
|
307 | + $this->logger->log(LogLevel::DEBUG, "fits (better) rotated"); |
|
308 | 308 | $remainingLength -= $itemWidth; |
309 | 309 | $layerLength += $itemWidth; |
310 | 310 | $layerWidth = max($itemLength, $layerWidth); |
@@ -313,7 +313,7 @@ discard block |
||
313 | 313 | |
314 | 314 | //allow items to be stacked in place within the same footprint up to current layerdepth |
315 | 315 | $maxStackDepth = $layerDepth - $itemToPack->getDepth(); |
316 | - while(!$aItems->isEmpty()) { |
|
316 | + while (!$aItems->isEmpty()) { |
|
317 | 317 | $potentialStackItem = $aItems->top(); |
318 | 318 | if ($potentialStackItem->getDepth() <= $maxStackDepth && |
319 | 319 | $potentialStackItem->getWeight() <= $remainingWeight && |
@@ -330,7 +330,7 @@ discard block |
||
330 | 330 | } |
331 | 331 | else { |
332 | 332 | if ($remainingWidth >= min($itemWidth, $itemLength) && $layerDepth > 0 && $layerWidth > 0 && $layerLength > 0) { |
333 | - $this->logger->log(LogLevel::DEBUG, "No more fit in lengthwise, resetting for new row"); |
|
333 | + $this->logger->log(LogLevel::DEBUG, "No more fit in lengthwise, resetting for new row"); |
|
334 | 334 | $remainingLength += $layerLength; |
335 | 335 | $remainingWidth -= $layerWidth; |
336 | 336 | $layerWidth = $layerLength = 0; |
@@ -338,7 +338,7 @@ discard block |
||
338 | 338 | } |
339 | 339 | |
340 | 340 | if ($remainingLength < min($itemWidth, $itemLength) || $layerDepth == 0) { |
341 | - $this->logger->log(LogLevel::DEBUG, "doesn't fit on layer even when empty"); |
|
341 | + $this->logger->log(LogLevel::DEBUG, "doesn't fit on layer even when empty"); |
|
342 | 342 | $aItems->extract(); |
343 | 343 | continue; |
344 | 344 | } |
@@ -348,10 +348,10 @@ discard block |
||
348 | 348 | $remainingDepth -= $layerDepth; |
349 | 349 | |
350 | 350 | $layerWidth = $layerLength = $layerDepth = 0; |
351 | - $this->logger->log(LogLevel::DEBUG, "doesn't fit, so starting next vertical layer"); |
|
351 | + $this->logger->log(LogLevel::DEBUG, "doesn't fit, so starting next vertical layer"); |
|
352 | 352 | } |
353 | 353 | } |
354 | - $this->logger->log(LogLevel::DEBUG, "done with this box"); |
|
354 | + $this->logger->log(LogLevel::DEBUG, "done with this box"); |
|
355 | 355 | return new PackedBox($aBox, $packedItems, $remainingWidth, $remainingLength, $remainingDepth, $remainingWeight); |
356 | 356 | } |
357 | 357 |
@@ -60,14 +60,12 @@ discard block |
||
60 | 60 | public function setItems($aItems) { |
61 | 61 | if ($aItems instanceof ItemList) { |
62 | 62 | $this->items = clone $aItems; |
63 | - } |
|
64 | - else if (is_array($aItems)) { |
|
63 | + } else if (is_array($aItems)) { |
|
65 | 64 | $this->items = new ItemList(); |
66 | 65 | foreach ($aItems as $item) { |
67 | 66 | $this->items->insert($item); |
68 | 67 | } |
69 | - } |
|
70 | - else { |
|
68 | + } else { |
|
71 | 69 | throw new \RuntimeException('Not a valid list of items'); |
72 | 70 | } |
73 | 71 | } |
@@ -183,11 +181,9 @@ discard block |
||
183 | 181 | $boxWeight = $packedBox->getWeight(); |
184 | 182 | if ($boxWeight > $targetWeight) { |
185 | 183 | $overWeightBoxes[] = $packedBox; |
186 | - } |
|
187 | - else if ($boxWeight < $targetWeight) { |
|
184 | + } else if ($boxWeight < $targetWeight) { |
|
188 | 185 | $underWeightBoxes[] = $packedBox; |
189 | - } |
|
190 | - else { |
|
186 | + } else { |
|
191 | 187 | $packedBoxes->insert($packedBox); //target weight, so we'll keep these |
192 | 188 | } |
193 | 189 | } |
@@ -302,8 +298,7 @@ discard block |
||
302 | 298 | $remainingLength -= $itemLength; |
303 | 299 | $layerLength += $itemLength; |
304 | 300 | $layerWidth = max($itemWidth, $layerWidth); |
305 | - } |
|
306 | - else { |
|
301 | + } else { |
|
307 | 302 | $this->logger->log(LogLevel::DEBUG, "fits (better) rotated"); |
308 | 303 | $remainingLength -= $itemWidth; |
309 | 304 | $layerLength += $itemWidth; |
@@ -322,13 +317,11 @@ discard block |
||
322 | 317 | $remainingWeight -= $potentialStackItem->getWeight(); |
323 | 318 | $maxStackDepth -= $potentialStackItem->getDepth(); |
324 | 319 | $packedItems->insert($aItems->extract()); |
325 | - } |
|
326 | - else { |
|
320 | + } else { |
|
327 | 321 | break; |
328 | 322 | } |
329 | 323 | } |
330 | - } |
|
331 | - else { |
|
324 | + } else { |
|
332 | 325 | if ($remainingWidth >= min($itemWidth, $itemLength) && $layerDepth > 0 && $layerWidth > 0 && $layerLength > 0) { |
333 | 326 | $this->logger->log(LogLevel::DEBUG, "No more fit in lengthwise, resetting for new row"); |
334 | 327 | $remainingLength += $layerLength; |
@@ -1,32 +1,32 @@ discard block |
||
1 | 1 | <?php |
2 | 2 | /** |
3 | - * Box packing (3D bin packing, knapsack problem) |
|
4 | - * @package BoxPacker |
|
5 | - * @author Doug Wright |
|
6 | - */ |
|
7 | - namespace DVDoug\BoxPacker; |
|
3 | + * Box packing (3D bin packing, knapsack problem) |
|
4 | + * @package BoxPacker |
|
5 | + * @author Doug Wright |
|
6 | + */ |
|
7 | + namespace DVDoug\BoxPacker; |
|
8 | 8 | |
9 | - /** |
|
10 | - * List of items to be packed, ordered by volume |
|
11 | - * @author Doug Wright |
|
12 | - * @package BoxPacker |
|
13 | - */ |
|
14 | - class ItemList extends \SplMaxHeap { |
|
9 | + /** |
|
10 | + * List of items to be packed, ordered by volume |
|
11 | + * @author Doug Wright |
|
12 | + * @package BoxPacker |
|
13 | + */ |
|
14 | + class ItemList extends \SplMaxHeap { |
|
15 | 15 | |
16 | 16 | /** |
17 | 17 | * Compare elements in order to place them correctly in the heap while sifting up. |
18 | 18 | * @see \SplMaxHeap::compare() |
19 | 19 | */ |
20 | 20 | public function compare($aItemA, $aItemB) { |
21 | - if ($aItemA->getVolume() > $aItemB->getVolume()) { |
|
21 | + if ($aItemA->getVolume() > $aItemB->getVolume()) { |
|
22 | 22 | return 1; |
23 | - } |
|
24 | - else if ($aItemA->getVolume() < $aItemB->getVolume()) { |
|
23 | + } |
|
24 | + else if ($aItemA->getVolume() < $aItemB->getVolume()) { |
|
25 | 25 | return -1; |
26 | - } |
|
27 | - else { |
|
26 | + } |
|
27 | + else { |
|
28 | 28 | return 0; |
29 | - } |
|
29 | + } |
|
30 | 30 | } |
31 | 31 | |
32 | 32 | /** |
@@ -34,11 +34,11 @@ discard block |
||
34 | 34 | * @return array |
35 | 35 | */ |
36 | 36 | public function asArray() { |
37 | - $return = []; |
|
38 | - foreach (clone $this as $item) { |
|
37 | + $return = []; |
|
38 | + foreach (clone $this as $item) { |
|
39 | 39 | $return[] = $item; |
40 | - } |
|
41 | - return $return; |
|
40 | + } |
|
41 | + return $return; |
|
42 | 42 | } |
43 | 43 | |
44 | - } |
|
44 | + } |
@@ -20,11 +20,9 @@ |
||
20 | 20 | public function compare($aItemA, $aItemB) { |
21 | 21 | if ($aItemA->getVolume() > $aItemB->getVolume()) { |
22 | 22 | return 1; |
23 | - } |
|
24 | - else if ($aItemA->getVolume() < $aItemB->getVolume()) { |
|
23 | + } else if ($aItemA->getVolume() < $aItemB->getVolume()) { |
|
25 | 24 | return -1; |
26 | - } |
|
27 | - else { |
|
25 | + } else { |
|
28 | 26 | return 0; |
29 | 27 | } |
30 | 28 | } |
@@ -1,17 +1,17 @@ discard block |
||
1 | 1 | <?php |
2 | 2 | /** |
3 | - * Box packing (3D bin packing, knapsack problem) |
|
4 | - * @package BoxPacker |
|
5 | - * @author Doug Wright |
|
6 | - */ |
|
7 | - namespace DVDoug\BoxPacker; |
|
3 | + * Box packing (3D bin packing, knapsack problem) |
|
4 | + * @package BoxPacker |
|
5 | + * @author Doug Wright |
|
6 | + */ |
|
7 | + namespace DVDoug\BoxPacker; |
|
8 | 8 | |
9 | - /** |
|
10 | - * A "box" with items |
|
11 | - * @author Doug Wright |
|
12 | - * @package BoxPacker |
|
13 | - */ |
|
14 | - class PackedBox { |
|
9 | + /** |
|
10 | + * A "box" with items |
|
11 | + * @author Doug Wright |
|
12 | + * @package BoxPacker |
|
13 | + */ |
|
14 | + class PackedBox { |
|
15 | 15 | |
16 | 16 | /** |
17 | 17 | * Box used |
@@ -60,7 +60,7 @@ discard block |
||
60 | 60 | * @return Box |
61 | 61 | */ |
62 | 62 | public function getBox() { |
63 | - return $this->box; |
|
63 | + return $this->box; |
|
64 | 64 | } |
65 | 65 | |
66 | 66 | /** |
@@ -68,7 +68,7 @@ discard block |
||
68 | 68 | * @return ItemList |
69 | 69 | */ |
70 | 70 | public function getItems() { |
71 | - return $this->items; |
|
71 | + return $this->items; |
|
72 | 72 | } |
73 | 73 | |
74 | 74 | /** |
@@ -77,16 +77,16 @@ discard block |
||
77 | 77 | */ |
78 | 78 | public function getWeight() { |
79 | 79 | |
80 | - if (!is_null($this->weight)) { |
|
80 | + if (!is_null($this->weight)) { |
|
81 | 81 | return $this->weight; |
82 | - } |
|
82 | + } |
|
83 | 83 | |
84 | - $this->weight = $this->box->getEmptyWeight(); |
|
85 | - $items = clone $this->items; |
|
86 | - foreach ($items as $item) { |
|
84 | + $this->weight = $this->box->getEmptyWeight(); |
|
85 | + $items = clone $this->items; |
|
86 | + foreach ($items as $item) { |
|
87 | 87 | $this->weight += $item->getWeight(); |
88 | - } |
|
89 | - return $this->weight; |
|
88 | + } |
|
89 | + return $this->weight; |
|
90 | 90 | } |
91 | 91 | |
92 | 92 | /** |
@@ -94,7 +94,7 @@ discard block |
||
94 | 94 | * @return int |
95 | 95 | */ |
96 | 96 | public function getRemainingWidth() { |
97 | - return $this->remainingWidth; |
|
97 | + return $this->remainingWidth; |
|
98 | 98 | } |
99 | 99 | |
100 | 100 | /** |
@@ -102,7 +102,7 @@ discard block |
||
102 | 102 | * @return int |
103 | 103 | */ |
104 | 104 | public function getRemainingLength() { |
105 | - return $this->remainingLength; |
|
105 | + return $this->remainingLength; |
|
106 | 106 | } |
107 | 107 | |
108 | 108 | /** |
@@ -110,7 +110,7 @@ discard block |
||
110 | 110 | * @return int |
111 | 111 | */ |
112 | 112 | public function getRemainingDepth() { |
113 | - return $this->remainingDepth; |
|
113 | + return $this->remainingDepth; |
|
114 | 114 | } |
115 | 115 | |
116 | 116 | /** |
@@ -118,7 +118,7 @@ discard block |
||
118 | 118 | * @return int |
119 | 119 | */ |
120 | 120 | public function getRemainingWeight() { |
121 | - return $this->remainingWeight; |
|
121 | + return $this->remainingWeight; |
|
122 | 122 | } |
123 | 123 | |
124 | 124 | /** |
@@ -126,14 +126,14 @@ discard block |
||
126 | 126 | * @return float |
127 | 127 | */ |
128 | 128 | public function getVolumeUtilisation() { |
129 | - $itemVolume = 0; |
|
129 | + $itemVolume = 0; |
|
130 | 130 | |
131 | - /** @var Item $item */ |
|
132 | - foreach (clone $this->items as $item) { |
|
131 | + /** @var Item $item */ |
|
132 | + foreach (clone $this->items as $item) { |
|
133 | 133 | $itemVolume += $item->getVolume(); |
134 | - } |
|
134 | + } |
|
135 | 135 | |
136 | - return round($itemVolume / $this->box->getInnerVolume() * 100, 1); |
|
136 | + return round($itemVolume / $this->box->getInnerVolume() * 100, 1); |
|
137 | 137 | } |
138 | 138 | |
139 | 139 | |
@@ -148,12 +148,12 @@ discard block |
||
148 | 148 | * @param int $aRemainingWeight |
149 | 149 | */ |
150 | 150 | public function __construct(Box $aBox, ItemList $aItemList, $aRemainingWidth, $aRemainingLength, $aRemainingDepth, $aRemainingWeight) { |
151 | - $this->box = $aBox; |
|
152 | - $this->items = $aItemList; |
|
153 | - $this->remainingWidth = $aRemainingWidth; |
|
154 | - $this->remainingLength = $aRemainingLength; |
|
155 | - $this->remainingDepth = $aRemainingDepth; |
|
156 | - $this->remainingWeight = $aRemainingWeight; |
|
151 | + $this->box = $aBox; |
|
152 | + $this->items = $aItemList; |
|
153 | + $this->remainingWidth = $aRemainingWidth; |
|
154 | + $this->remainingLength = $aRemainingLength; |
|
155 | + $this->remainingDepth = $aRemainingDepth; |
|
156 | + $this->remainingWeight = $aRemainingWeight; |
|
157 | 157 | } |
158 | 158 | |
159 | - } |
|
159 | + } |