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);
}