예제 #1
0
 /**
  * Constructor
  */
 public function __construct(Box $box, ItemList $items)
 {
     $this->logger = new NullLogger();
     $this->box = $box;
     $this->items = $items;
     $this->depthLeft = $this->box->getInnerDepth();
     $this->remainingWeight = $this->box->getMaxWeight() - $this->box->getEmptyWeight();
     $this->widthLeft = $this->box->getInnerWidth();
     $this->lengthLeft = $this->box->getInnerLength();
 }
예제 #2
0
 /**
  * Pack as many items as possible into specific given box
  * @param Box      $aBox
  * @param ItemList $aItems
  * @return PackedBox packed box
  */
 public function packIntoBox(Box $aBox, ItemList $aItems)
 {
     $this->logger->log(LogLevel::DEBUG, "[EVALUATING BOX] {$aBox->getReference()}");
     $packedItems = new ItemList();
     $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() > $remainingDepth || $itemToPack->getWeight() > $remainingWeight) {
             break;
         }
         $this->logger->log(LogLevel::DEBUG, "evaluating item {$itemToPack->getDescription()}");
         $this->logger->log(LogLevel::DEBUG, "remaining width: {$remainingWidth}, length: {$remainingLength}, depth: {$remainingDepth}");
         $this->logger->log(LogLevel::DEBUG, "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 >= 0 && $fitsSameGap <= $fitsRotatedGap || !$aItems->isEmpty() && $aItems->top() == $itemToPack && $remainingLength >= 2 * $itemLength) {
                 $this->logger->log(LogLevel::DEBUG, "fits (better) unrotated");
                 $remainingLength -= $itemLength;
                 $layerLength += $itemLength;
                 $layerWidth = max($itemWidth, $layerWidth);
             } else {
                 $this->logger->log(LogLevel::DEBUG, "fits (better) rotated");
                 $remainingLength -= $itemWidth;
                 $layerLength += $itemWidth;
                 $layerWidth = max($itemLength, $layerWidth);
             }
             $layerDepth = max($layerDepth, $itemToPack->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
             $maxStackDepth = $layerDepth - $itemToPack->getDepth();
             while (!$aItems->isEmpty()) {
                 $potentialStackItem = $aItems->top();
                 if ($potentialStackItem->getDepth() <= $maxStackDepth && $potentialStackItem->getWeight() <= $remainingWeight && $potentialStackItem->getWidth() <= $itemToPack->getWidth() && $potentialStackItem->getLength() <= $itemToPack->getLength()) {
                     $remainingWeight -= $potentialStackItem->getWeight();
                     $maxStackDepth -= $potentialStackItem->getDepth();
                     $packedItems->insert($aItems->extract());
                 } else {
                     break;
                 }
             }
         } else {
             if ($remainingWidth >= min($itemWidth, $itemLength) && $layerDepth > 0 && $layerWidth > 0 && $layerLength > 0) {
                 $this->logger->log(LogLevel::DEBUG, "No more fit in lengthwise, resetting for new row");
                 $remainingLength += $layerLength;
                 $remainingWidth -= $layerWidth;
                 $layerWidth = $layerLength = 0;
                 continue;
             }
             if ($remainingLength < min($itemWidth, $itemLength) || $layerDepth == 0) {
                 $this->logger->log(LogLevel::DEBUG, "doesn't fit on layer even when empty");
                 break;
             }
             $remainingWidth = $layerWidth ? min(floor($layerWidth * 1.1), $aBox->getInnerWidth()) : $aBox->getInnerWidth();
             $remainingLength = $layerLength ? min(floor($layerLength * 1.1), $aBox->getInnerLength()) : $aBox->getInnerLength();
             $remainingDepth -= $layerDepth;
             $layerWidth = $layerLength = $layerDepth = 0;
             $this->logger->log(LogLevel::DEBUG, "doesn't fit, so starting next vertical layer");
         }
     }
     $this->logger->log(LogLevel::DEBUG, "done with this box");
     return new PackedBox($aBox, $packedItems, $remainingWidth, $remainingLength, $remainingDepth, $remainingWeight);
 }
예제 #3
0
 /**
  * Pack as many items as possible into specific given box
  * @param Box      $box
  * @param ItemList $items
  * @return PackedBox packed box
  */
 public function packIntoBox(Box $box, ItemList $items)
 {
     $this->logger->log(LogLevel::DEBUG, "[EVALUATING BOX] {$box->getReference()}");
     $packedItems = new ItemList();
     $remainingDepth = $box->getInnerDepth();
     $remainingWeight = $box->getMaxWeight() - $box->getEmptyWeight();
     $remainingWidth = $box->getInnerWidth();
     $remainingLength = $box->getInnerLength();
     $layerWidth = $layerLength = $layerDepth = 0;
     while (!$items->isEmpty()) {
         $itemToPack = $items->top();
         //skip items that are simply too large
         if ($this->isItemTooLargeForBox($itemToPack, $remainingDepth, $remainingWeight)) {
             $items->extract();
             continue;
         }
         $this->logger->log(LogLevel::DEBUG, "evaluating item {$itemToPack->getDescription()}");
         $this->logger->log(LogLevel::DEBUG, "remaining width: {$remainingWidth}, length: {$remainingLength}, depth: {$remainingDepth}");
         $this->logger->log(LogLevel::DEBUG, "layerWidth: {$layerWidth}, layerLength: {$layerLength}, layerDepth: {$layerDepth}");
         $itemWidth = $itemToPack->getWidth();
         $itemLength = $itemToPack->getLength();
         if ($this->fitsGap($itemToPack, $remainingWidth, $remainingLength)) {
             $packedItems->insert($items->extract());
             $remainingWeight -= $itemToPack->getWeight();
             $nextItem = !$items->isEmpty() ? $items->top() : null;
             if ($this->fitsBetterRotated($itemToPack, $nextItem, $remainingWidth, $remainingLength)) {
                 $this->logger->log(LogLevel::DEBUG, "fits (better) unrotated");
                 $remainingLength -= $itemLength;
                 $layerLength += $itemLength;
                 $layerWidth = max($itemWidth, $layerWidth);
             } else {
                 $this->logger->log(LogLevel::DEBUG, "fits (better) rotated");
                 $remainingLength -= $itemWidth;
                 $layerLength += $itemWidth;
                 $layerWidth = max($itemLength, $layerWidth);
             }
             $layerDepth = max($layerDepth, $itemToPack->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
             $maxStackDepth = $layerDepth - $itemToPack->getDepth();
             while (!$items->isEmpty() && $this->canStackItemInLayer($itemToPack, $items->top(), $maxStackDepth, $remainingWeight)) {
                 $remainingWeight -= $items->top()->getWeight();
                 $maxStackDepth -= $items->top()->getDepth();
                 $packedItems->insert($items->extract());
             }
         } else {
             if ($remainingWidth >= min($itemWidth, $itemLength) && $this->isLayerStarted($layerWidth, $layerLength, $layerDepth)) {
                 $this->logger->log(LogLevel::DEBUG, "No more fit in lengthwise, resetting for new row");
                 $remainingLength += $layerLength;
                 $remainingWidth -= $layerWidth;
                 $layerWidth = $layerLength = 0;
                 continue;
             } elseif ($remainingLength < min($itemWidth, $itemLength) || $layerDepth == 0) {
                 $this->logger->log(LogLevel::DEBUG, "doesn't fit on layer even when empty");
                 $items->extract();
                 continue;
             }
             $remainingWidth = $layerWidth ? min(floor($layerWidth * 1.1), $box->getInnerWidth()) : $box->getInnerWidth();
             $remainingLength = $layerLength ? min(floor($layerLength * 1.1), $box->getInnerLength()) : $box->getInnerLength();
             $remainingDepth -= $layerDepth;
             $layerWidth = $layerLength = $layerDepth = 0;
             $this->logger->log(LogLevel::DEBUG, "doesn't fit, so starting next vertical layer");
         }
     }
     $this->logger->log(LogLevel::DEBUG, "done with this box");
     return new PackedBox($box, $packedItems, $remainingWidth, $remainingLength, $remainingDepth, $remainingWeight);
 }