/**
* Pack items into boxes using the principle of largest volume item first
*
* @throws \RuntimeException
* @return PackedBoxList
*/
public function doVolumePacking()
{
$packedBoxes = new PackedBoxList();
//Keep going until everything packed
while ($this->items->count()) {
$boxesToEvaluate = clone $this->boxes;
$packedBoxesIteration = new PackedBoxList();
//Loop through boxes starting with smallest, see what happens
while (!$boxesToEvaluate->isEmpty()) {
$box = $boxesToEvaluate->extract();
$volumePacker = new VolumePacker($box, clone $this->items);
$volumePacker->setLogger($this->logger);
$packedBox = $volumePacker->pack();
if ($packedBox->getItems()->count()) {
$packedBoxesIteration->insert($packedBox);
//Have we found a single box that contains everything?
if ($packedBox->getItems()->count() === $this->items->count()) {
break;
}
}
}
//Check iteration was productive
if ($packedBoxesIteration->isEmpty()) {
throw new \RuntimeException('Item ' . $this->items->top()->getDescription() . ' is too large to fit into any box');
}
//Find best box of iteration, and remove packed items from unpacked list
$bestBox = $packedBoxesIteration->top();
$unPackedItems = $this->items->asArray();
foreach (clone $bestBox->getItems() as $packedItem) {
foreach ($unPackedItems as $unpackedKey => $unpackedItem) {
if ($packedItem === $unpackedItem) {
unset($unPackedItems[$unpackedKey]);
break;
}
}
}
$unpackedItemList = new ItemList();
foreach ($unPackedItems as $unpackedItem) {
$unpackedItemList->insert($unpackedItem);
}
$this->items = $unpackedItemList;
$packedBoxes->insert($bestBox);
}
return $packedBoxes;
}