Skip to content

Commit

Permalink
Correct rotations before entering callbacks, add assertions around th…
Browse files Browse the repository at this point in the history
…is area
  • Loading branch information
dvdoug committed Apr 23, 2023
1 parent 03db671 commit 02b4d31
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 1 deletion.
8 changes: 8 additions & 0 deletions src/LayerPacker.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class LayerPacker implements LoggerAwareInterface

private bool $beStrictAboutItemOrdering = false;

private bool $isBoxRotated = false;

public function __construct(private readonly Box $box)
{
$this->logger = new NullLogger();
Expand All @@ -54,6 +56,12 @@ public function setSinglePassMode(bool $singlePassMode): void
$this->orientatedItemFactory->setSinglePassMode($singlePassMode);
}

public function setBoxIsRotated(bool $boxIsRotated): void
{
$this->isBoxRotated = $boxIsRotated;
$this->orientatedItemFactory->setBoxIsRotated($boxIsRotated);
}

public function beStrictAboutItemOrdering(bool $beStrict): void
{
$this->beStrictAboutItemOrdering = $beStrict;
Expand Down
18 changes: 17 additions & 1 deletion src/OrientatedItemFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class OrientatedItemFactory implements LoggerAwareInterface

protected bool $singlePassMode = false;

protected bool $boxIsRotated = false;

/**
* @var array<string, bool>
*/
Expand All @@ -46,6 +48,11 @@ public function setSinglePassMode(bool $singlePassMode): void
$this->singlePassMode = $singlePassMode;
}

public function setBoxIsRotated(bool $boxIsRotated): void
{
$this->boxIsRotated = $boxIsRotated;
}

/**
* Get the best orientation for an item.
*/
Expand Down Expand Up @@ -121,7 +128,16 @@ public function getPossibleOrientations(
/** @var ConstrainedPlacementItem $constrainedItem */
$constrainedItem = $i->getItem();

return $constrainedItem->canBePacked(new PackedBox($this->box, $prevPackedItemList), $x, $y, $z, $i->getWidth(), $i->getLength(), $i->getDepth());
if ($this->boxIsRotated) {
$rotatedPrevPackedItemList = new PackedItemList();
foreach ($prevPackedItemList as $prevPackedItem) {
$rotatedPrevPackedItemList->insert(new PackedItem($prevPackedItem->getItem(), $prevPackedItem->getY(), $prevPackedItem->getX(), $prevPackedItem->getZ(), $prevPackedItem->getLength(), $prevPackedItem->getWidth(), $prevPackedItem->getDepth()));
}

return $constrainedItem->canBePacked(new PackedBox($this->box, $rotatedPrevPackedItemList), $y, $x, $z, $i->getLength(), $i->getWidth(), $i->getDepth());
} else {
return $constrainedItem->canBePacked(new PackedBox($this->box, $prevPackedItemList), $x, $y, $z, $i->getWidth(), $i->getLength(), $i->getDepth());
}
});
}

Expand Down
33 changes: 33 additions & 0 deletions src/PackedBox.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
use function round;
use function urlencode;
use function is_iterable;
use function count;
use function array_pop;
use function assert;

/**
* A "box" with items.
Expand Down Expand Up @@ -179,6 +182,7 @@ public function __construct(protected Box $box, protected PackedItemList $items)
$this->itemWeight += $item->getItem()->getWeight();
}
$this->volumeUtilisation = round($this->getUsedVolume() / ($this->getInnerVolume() ?: 1) * 100, 1);
$this->assertPackingCompliesWithRealWorld();
}

public function jsonSerialize(): array
Expand All @@ -205,4 +209,33 @@ public function jsonSerialize(): array
'items' => iterator_to_array($this->items),
];
}

/**
* Validate that all items are placed solely within the confines of the box, and that no two items are placed
* into the same physical space.
*/
private function assertPackingCompliesWithRealWorld(): void
{
/** @var PackedItem[] $itemsToCheck */
$itemsToCheck = iterator_to_array($this->items);
while (count($itemsToCheck) > 0) {
$itemToCheck = array_pop($itemsToCheck);

assert($itemToCheck->getX() >= 0);
assert($itemToCheck->getX() + $itemToCheck->getWidth() <= $this->box->getInnerWidth());
assert($itemToCheck->getY() >= 0);
assert($itemToCheck->getY() + $itemToCheck->getLength() <= $this->box->getInnerLength());
assert($itemToCheck->getZ() >= 0);
assert($itemToCheck->getZ() + $itemToCheck->getDepth() <= $this->box->getInnerDepth());

foreach ($itemsToCheck as $otherItem) {
$hasXOverlap = $itemToCheck->getX() < ($otherItem->getX() + $otherItem->getWidth()) && $otherItem->getX() < ($itemToCheck->getX() + $itemToCheck->getWidth());
$hasYOverlap = $itemToCheck->getY() < ($otherItem->getY() + $otherItem->getLength()) && $otherItem->getY() < ($itemToCheck->getY() + $itemToCheck->getLength());
$hasZOverlap = $itemToCheck->getZ() < ($otherItem->getZ() + $otherItem->getDepth()) && $otherItem->getZ() < ($itemToCheck->getZ() + $itemToCheck->getDepth());

$hasOverlap = $hasXOverlap && $hasYOverlap && $hasZOverlap;
assert(!$hasOverlap);
}
}
}
}
1 change: 1 addition & 0 deletions src/VolumePacker.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ public function pack(): PackedBox
private function packRotation(int $boxWidth, int $boxLength): PackedBox
{
$this->logger->debug("[EVALUATING ROTATION] {$this->box->getReference()}", ['width' => $boxWidth, 'length' => $boxLength]);
$this->layerPacker->setBoxIsRotated($this->box->getInnerWidth() !== $boxWidth);

$layers = [];
$items = clone $this->items;
Expand Down

0 comments on commit 02b4d31

Please sign in to comment.