/** * Pack as many items as possible into specific given box * @param ArtatusBox $aBox * @param ArtatusItemList $aItems * @return ArtatusPackedBox packed box */ public function packIntoBox(ArtatusBox $aBox, ArtatusItemList $aItems) { if ($this->debug) { echo "evaluating box {$aBox->getReference()}"; } $packedItems = new ArtatusItemList(); $remainingDepth = $aBox->getInnerDepth(); $remainingWeight = $aBox->getMaxWeight() - $aBox->getEmptyWeight(); $remainingWidth = $aBox->getInnerWidth(); $remainingLength = $aBox->getInnerLength(); $layerWidth = $layerLength = $layerDepth = 0; while (!$aItems->isEmpty()) { $itemToPack = $aItems->top(); if ($itemToPack->getDepth() > ($layerDepth ?: $remainingDepth) || $itemToPack->getWeight() > $remainingWeight) { break; } if ($this->debug) { echo "evaluating item {$itemToPack->getDescription()}"; echo "remaining width: {$remainingWidth}, length: {$remainingLength}, depth: {$remainingDepth}"; echo "layerWidth: {$layerWidth}, layerLength: {$layerLength}, layerDepth: {$layerDepth}"; } $itemWidth = $itemToPack->getWidth(); $itemLength = $itemToPack->getLength(); $fitsSameGap = min($remainingWidth - $itemWidth, $remainingLength - $itemLength); $fitsRotatedGap = min($remainingWidth - $itemLength, $remainingLength - $itemWidth); if ($fitsSameGap >= 0 || $fitsRotatedGap >= 0) { $packedItems->insert($aItems->extract()); $remainingWeight -= $itemToPack->getWeight(); if ($fitsRotatedGap < 0 || $fitsSameGap <= $fitsRotatedGap || !$aItems->isEmpty() && $aItems->top() == $itemToPack && $remainingLength >= 2 * $itemLength) { if ($this->debug) { echo "fits (better) unrotated"; } $remainingLength -= $itemLength; $layerWidth += $itemWidth; $layerLength += $itemLength; } else { if ($this->debug) { echo "fits (better) rotated"; } $remainingLength -= $itemWidth; $layerWidth += $itemLength; $layerLength += $itemWidth; } $layerDepth = max($layerDepth, $itemToPack->getDepth()); //greater than 0, items will always be less deep } else { if (!$layerWidth) { if ($this->debug) { echo "doesn't fit on layer even when empty"; } break; } $remainingWidth = min(floor($layerWidth * 1.1), $aBox->getInnerWidth()); $remainingLength = min(floor($layerLength * 1.1), $aBox->getInnerLength()); $remainingDepth -= $layerDepth; $layerWidth = $layerLength = $layerDepth = 0; if ($this->debug) { echo "doesn't fit, so starting next vertical layer"; } } } if ($this->debug) { echo "done with this box"; } return new ArtatusPackedBox($aBox, $packedItems, $remainingWidth, $remainingLength, $remainingDepth, $remainingWeight); }
$packer->addBox(new ArtatusBox('No. 5 box', 300, 300, 10, 10, 296, 296, 8, 1000)); $packer->addBox(new ArtatusBox('No. 6 box', 300, 300, 10, 10, 296, 296, 8, 1000)); $packer->addItem(new ArtatusItem('Item 1', 250, 250, 2, 200)); $packer->addItem(new ArtatusItem('Item 2', 250, 250, 2, 200)); $packer->addItem(new ArtatusItem('Item 3', 250, 250, 2, 200)); $packedBoxes = $packer->pack(); echo "These items fitted into " . count($packedBoxes) . " box(es)" . PHP_EOL; foreach ($packedBoxes as $packedBox) { $boxType = $packedBox->getBox(); // your own box object, in this case BasicBox echo "This box is a {$boxType->getReference()}, it is {$boxType->getOuterWidth()}mm wide, {$boxType->getOuterLength()}mm long and {$boxType->getOuterDepth()}mm high" . PHP_EOL; echo "The combined weight of this box and the items inside it is {$packedBox->getWeight()}g" . PHP_EOL; echo "The items in this box are:" . PHP_EOL; $itemsInTheBox = $packedBox->getItems(); foreach ($itemsInTheBox as $item) { // your own item object, in this case BasicItem echo $item->getDescription() . PHP_EOL; } echo PHP_EOL; } /* * To just see if a selection of items will fit into one specific box */ $box = new ArtatusBox('Le box', 300, 300, 10, 10, 296, 296, 8, 1000); $items = new ArtatusItemList(); $items->insert(new ArtatusItem('Item 1', 297, 296, 2, 200)); $items->insert(new ArtatusItem('Item 2', 297, 296, 2, 500)); $items->insert(new ArtatusItem('Item 3', 296, 296, 4, 290)); $packer = new ArtatusPacker(); $packedBox = $packer->packIntoBox($box, $items); /* $packedBox->getItems() contains the items that fit */