DVDoug\BoxPacker\VolumePacker::pack PHP Метод

pack() публичный Метод

Pack as many items as possible into specific given box
public pack ( ) : DVDoug\BoxPacker\PackedBox
Результат DVDoug\BoxPacker\PackedBox packed box
    public function pack()
    {
        $this->logger->debug("[EVALUATING BOX] {$this->box->getReference()}");
        $packedItems = new ItemList();
        $layerWidth = $layerLength = $layerDepth = 0;
        $prevItem = null;
        while (!$this->items->isEmpty()) {
            $itemToPack = $this->items->extract();
            //skip items that are simply too heavy
            if ($itemToPack->getWeight() > $this->remainingWeight) {
                continue;
            }
            $this->logger->debug("evaluating item {$itemToPack->getDescription()}");
            $this->logger->debug("remaining width: {$this->widthLeft}, length: {$this->lengthLeft}, depth: {$this->depthLeft}");
            $this->logger->debug("layerWidth: {$layerWidth}, layerLength: {$layerLength}, layerDepth: {$layerDepth}");
            $nextItem = !$this->items->isEmpty() ? $this->items->top() : null;
            $orientatedItem = $this->findBestOrientation($itemToPack, $prevItem, $nextItem, $this->widthLeft, $this->lengthLeft, $this->depthLeft);
            if ($orientatedItem) {
                $packedItems->insert($orientatedItem->getItem());
                $this->remainingWeight -= $itemToPack->getWeight();
                $this->lengthLeft -= $orientatedItem->getLength();
                $layerLength += $orientatedItem->getLength();
                $layerWidth = max($orientatedItem->getWidth(), $layerWidth);
                $layerDepth = max($layerDepth, $orientatedItem->getDepth());
                //greater than 0, items will always be less deep
                //allow items to be stacked in place within the same footprint up to current layerdepth
                $stackableDepth = $layerDepth - $orientatedItem->getDepth();
                $this->tryAndStackItemsIntoSpace($packedItems, $orientatedItem->getWidth(), $orientatedItem->getLength(), $stackableDepth);
                $prevItem = $orientatedItem;
            } else {
                $prevItem = null;
                if ($this->widthLeft >= min($itemToPack->getWidth(), $itemToPack->getLength()) && $this->isLayerStarted($layerWidth, $layerLength, $layerDepth)) {
                    $this->logger->debug("No more fit in lengthwise, resetting for new row");
                    $this->lengthLeft += $layerLength;
                    $this->widthLeft -= $layerWidth;
                    $layerWidth = $layerLength = 0;
                    $this->items->insert($itemToPack);
                    continue;
                } elseif ($this->lengthLeft < min($itemToPack->getWidth(), $itemToPack->getLength()) || $layerDepth == 0) {
                    $this->logger->debug("doesn't fit on layer even when empty");
                    continue;
                }
                $this->widthLeft = $layerWidth ? min(floor($layerWidth * 1.1), $this->box->getInnerWidth()) : $this->box->getInnerWidth();
                $this->lengthLeft = $layerLength ? min(floor($layerLength * 1.1), $this->box->getInnerLength()) : $this->box->getInnerLength();
                $this->depthLeft -= $layerDepth;
                $layerWidth = $layerLength = $layerDepth = 0;
                $this->logger->debug("doesn't fit, so starting next vertical layer");
                $this->items->insert($itemToPack);
            }
        }
        $this->logger->debug("done with this box");
        return new PackedBox($this->box, $packedItems, $this->widthLeft, $this->lengthLeft, $this->depthLeft, $this->remainingWeight);
    }

Usage Example

Пример #1
0
 /**
  * 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;
 }