Skip to content

Commit

Permalink
Add a better form of lookahead to properly fix #89
Browse files Browse the repository at this point in the history
  • Loading branch information
dvdoug committed Nov 10, 2018
1 parent d5c8757 commit 94988b6
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 19 deletions.
70 changes: 65 additions & 5 deletions src/OrientatedItemFactory.php
Expand Up @@ -69,8 +69,7 @@ public function getBestOrientation(
return null;
}

$nextItem = $nextItems->count() ? $nextItems->top() : null;
usort($usableOrientations, function (OrientatedItem $a, OrientatedItem $b) use ($widthLeft, $lengthLeft, $depthLeft, $nextItem) {
usort($usableOrientations, function (OrientatedItem $a, OrientatedItem $b) use ($widthLeft, $lengthLeft, $depthLeft, $nextItems) {
$orientationAWidthLeft = $widthLeft - $a->getWidth();
$orientationALengthLeft = $lengthLeft - $a->getLength();
$orientationADepthLeft = $depthLeft - $a->getDepth();
Expand All @@ -89,15 +88,22 @@ public function getBestOrientation(
}

// prefer leaving room for next item in current row
if ($nextItem) {
$nextItemFitA = count($this->getPossibleOrientations($nextItem, $a, $orientationAWidthLeft, $lengthLeft, $depthLeft));
$nextItemFitB = count($this->getPossibleOrientations($nextItem, $b, $orientationBWidthLeft, $lengthLeft, $depthLeft));
if ($nextItems->count()) {
$nextItemFitA = count($this->getPossibleOrientations($nextItems->top(), $a, $orientationAWidthLeft, $lengthLeft, $depthLeft));
$nextItemFitB = count($this->getPossibleOrientations($nextItems->top(), $b, $orientationBWidthLeft, $lengthLeft, $depthLeft));
if ($nextItemFitA && !$nextItemFitB) {
return -1;
}
if ($nextItemFitB && !$nextItemFitA) {
return 1;
}

// if not an easy either/or, do a partial lookahead
$additionalPackedA = $this->calculateAdditionalItemsPackedWithThisOrientation($a, $nextItems, $widthLeft, $lengthLeft, $depthLeft);
$additionalPackedB = $this->calculateAdditionalItemsPackedWithThisOrientation($b, $nextItems, $widthLeft, $lengthLeft, $depthLeft);
if ($additionalPackedA !== $additionalPackedB) {
return $additionalPackedB <=> $additionalPackedA;
}
}
// otherwise prefer leaving minimum possible gap, or the greatest footprint
return $orientationADepthLeft <=> $orientationBDepthLeft ?: $orientationAMinGap <=> $orientationBMinGap ?: $a->getSurfaceFootprint() <=> $b->getSurfaceFootprint();
Expand Down Expand Up @@ -265,4 +271,58 @@ protected function isSameDimensions(Item $itemA, Item $itemB): bool

return $itemADimensions === $itemBDimensions;
}

/**
* Approximation of a forward-looking packing.
*
* Not an actual packing, that has additional logic regarding constraints and stackability, this focuses
* purely on fit.
*
* @param OrientatedItem $prevItem
* @param ItemList $nextItems
* @param int $originalWidthLeft
* @param int $originalLengthLeft
* @param int $depthLeft
* @return int
*/
protected function calculateAdditionalItemsPackedWithThisOrientation(
OrientatedItem $prevItem,
ItemList $nextItems,
int $originalWidthLeft,
int $originalLengthLeft,
int $depthLeft
): int
{
$packedCount = 0;

// first try packing into current row
$workingSetItems = clone $nextItems;
$widthLeft = $originalWidthLeft - $prevItem->getWidth();
$lengthLeft = $originalLengthLeft;
while (count($workingSetItems) > 0 && $widthLeft > 0) {
$itemToPack = $workingSetItems->extract();
$orientatedItem = $this->getBestOrientation($itemToPack, $prevItem, $workingSetItems, !count($workingSetItems), $widthLeft, $lengthLeft, $depthLeft);
if ($orientatedItem instanceof OrientatedItem) {
$packedCount++;
$widthLeft -= $orientatedItem->getWidth();
$prevItem = $orientatedItem;
}
}

// then see what happens if we try in the next row
$workingSetItems = clone $nextItems;
$widthLeft = $originalWidthLeft;
$lengthLeft = $originalLengthLeft - $prevItem->getLength();
while (count($workingSetItems) > 0 && $widthLeft > 0) {
$itemToPack = $workingSetItems->extract();
$orientatedItem = $this->getBestOrientation($itemToPack, $prevItem, $workingSetItems, !count($workingSetItems), $widthLeft, $lengthLeft, $depthLeft);
if ($orientatedItem instanceof OrientatedItem) {
$packedCount++;
$widthLeft -= $orientatedItem->getWidth();
$prevItem = $orientatedItem;
}
}

return $packedCount; // this isn't scientific, but is a reasonable proxy for success from an actual forward packing
}
}
28 changes: 14 additions & 14 deletions tests/data/expected.csv
Expand Up @@ -393,7 +393,7 @@
1672e9897bfb16f7f644365da8d6992c,1,0,26.4,1,0,26.4
167db38fa514a30e70f167f70d19f214,1,0,16.2,1,0,16.2
168065302d10d2f4b683e3d5e7475594,2,536556.3,32.7,1,0,19.8
1680b70ba864c313d28c9386ce54ac25,3,12592978.7,44,3,64070.2,38.5
1680b70ba864c313d28c9386ce54ac25,3,12592978.7,44,3,203349.6,49.5
1694662b95ac32661ee2b45826bb54f6,1,0,42.4,1,0,42.4
16a2283358cddda00bf2e47e5ad746d3,1,0,24,1,0,24
16a59c72d05be053c19e4b32ceafaef0,1,0,29.2,1,0,29.2
Expand Down Expand Up @@ -456,7 +456,7 @@
191909ab474fbb9f500c7c76f4f5697b,1,0,43.9,1,0,43.9
1927bc198a6b6b93a1d2dbbb6c11fd88,2,42.3,34.2,1,0,10.3
192aa66ebca07300ea732e2a05cdc370,1,0,32.8,1,0,32.8
19389352a94fb01b2a359fdc23c5e62d,2,6642.3,25.7,1,0,7.7
19389352a94fb01b2a359fdc23c5e62d,1,0,51.5,1,0,51.5
19471900c0fbc832cfcf3a64bd911d5d,1,0,34.2,1,0,34.2
194a256a5a4782ac7f049c2eb05fac01,1,0,23.1,1,0,23.1
1960c5d6c7d34a4b0eaf5e4cef6cc0af,1,0,22.3,1,0,22.3
Expand Down Expand Up @@ -832,7 +832,7 @@
2fffff39600acb91a32853d9c8a8f8fa,1,0,49.1,1,0,49.1
3004d7b042ae19dca17e23572ccd0307,1,0,50.2,1,0,50.2
300a552c32cf943b6cb1f89272b98f0a,1,0,23.7,1,0,23.7
30207339e3ae62b06cfdaf7ff2bc7a60,2,1118306.3,18.8,2,132.3,10.8
30207339e3ae62b06cfdaf7ff2bc7a60,2,1118306.3,18.8,2,30.3,10.8
30239296520840f04db4b3553c44ebff,2,12.3,36.9,1,0,11.1
3058994b05cdb67763ea7a7ee4ab33ff,1,0,28.2,1,0,28.2
306db218fea51e46b2be7741d8ec8ac9,3,14734.2,41.8,2,226576,16.4
Expand Down Expand Up @@ -868,7 +868,7 @@
3223ff53874ff3768881db6e163c96a3,2,99856,31.5,1,0,19.1
323d3a61ac8f60761edc56c34b339a1d,1,0,40.8,1,0,40.8
3242e661790ad530e5a8419a5c7c0b5b,1,0,22.8,1,0,22.8
3247e39c4bfd94e9f525f7ef5c179317,2,403225,70.1,2,199809,29.2
3247e39c4bfd94e9f525f7ef5c179317,2,366025,36.9,3,630.2,17.3
326b6af0e5d3ac4f72622ce744ee4b27,1,0,32.4,1,0,32.4
3276e0aa9afede0f2e5b0d5e3dcf7426,2,14884,23.9,1,0,7.2
328f28aadcd871aa3ade0646fda55b85,1,0,25.2,1,0,25.2
Expand Down Expand Up @@ -1709,7 +1709,7 @@
62dcab5291143dc6fc110ed65e070627,2,2500,27.3,2,2500,27.3
62e6b715a5a841db4292ce86055ad993,3,2646757.6,61,3,2646757.6,61
62f1be6037444d4f1f37a941da288493,1,0,30.1,1,0,30.1
62f9a1e4dc829da0729325702c2b031c,2,121,44.9,2,324,32.7
62f9a1e4dc829da0729325702c2b031c,2,16,44.9,2,324,32.7
62fd86f546a52d904692e1a9e919e089,1,0,12.5,1,0,12.5
62fd8a5e4b91cd6c7cd1d0aebd05c4ca,1,0,40.9,1,0,40.9
63102af3c3bc3f814be53dffddb29e2d,1,0,18.6,1,0,18.6
Expand Down Expand Up @@ -2227,7 +2227,7 @@
808255961bd2cd69ada085757150b913,1,0,38,1,0,38
808b82b9297c4ab6bbd366c4e189962c,1,0,33.3,1,0,33.3
80ad76b20162a20c96fd28c1a0fd1554,1,0,57.8,1,0,57.8
80b35862e48198d457d850237619a1be,1,0,73.1,1,0,73.1
80b35862e48198d457d850237619a1be,1,0,73.1,1,0,33.3
80bfcbb8cabb6d518bd218a09f72d280,1,0,26.1,1,0,26.1
80d45c7ecee2bf6045d135f0b149a218,1,0,56.3,1,0,56.3
80f0a1007c7e471ed1bfff1373ba6b53,2,756.3,47.1,2,756.3,47.1
Expand Down Expand Up @@ -2306,7 +2306,7 @@
865c43072c811009f4da22ee0525dd8a,1,0,35.5,1,0,35.5
86662df0ffaffef90bc3a5148f5e2de8,1,0,53.3,1,0,53.3
8672f30b07050392198c25cf8ab568fd,2,6241,24.9,1,0,15.1
867cd61bae65718bcc20e210c6b2234e,2,324,38.9,1,0,77.8
867cd61bae65718bcc20e210c6b2234e,2,324,38.9,2,25,53.4
867f7b009007b84c4f8882a07f9a4d55,2,20449,27.2,2,20449,27.2
868c30a0d203e41ffa05cb3b1810bb7c,6,516.8,22,2,1206702.3,9.9
869253e021bfbdfc79ffb385cf2678ec,2,1234321,16.5,1,0,19
Expand Down Expand Up @@ -3553,7 +3553,7 @@ d0efe6d5522001320a4372da93769920,1,0,33.1,1,0,33.1
d10e78eff303de831aff0a556a536a0f,1,0,48.7,1,0,48.7
d11076dc6cd4720a1fe9add55d2281aa,1,0,14.9,1,0,14.9
d1239d721e49347c9804bed0a6db56ab,1,0,39.3,1,0,39.3
d12f9cb4e8c278ab3286ae03ea30313a,2,39204,11.5,1,0,7
d12f9cb4e8c278ab3286ae03ea30313a,2,90000,23.3,1,0,7
d130d596db644f016ca8529c8abf46cc,1,0,37.8,1,0,37.8
d138dfe2bd5abdd66b951e505e6ce634,1,0,21.3,1,0,21.3
d144251f58433c0af02fa1a09ce64d30,1,0,74.6,1,0,74.6
Expand Down Expand Up @@ -3591,7 +3591,7 @@ d345c6ede0a6e399b1921e6e0d09771b,1,0,46.6,1,0,46.6
d35b204200c059c702d16639cafc039d,1,0,30.2,1,0,30.2
d3a52afd9fa04043e90575e6e1b01f06,2,6.3,44.5,2,506.3,44.5
d3c37074ddb58c94e5955674ae994e36,1,0,30.7,1,0,30.7
d3c8d10a93ee25028cae4520659ffee4,1,0,50.4,1,0,50.4
d3c8d10a93ee25028cae4520659ffee4,1,0,50.4,1,0,23
d3ce80a17be91b35737ce6964de65f7b,2,2304,30.9,1,0,9.3
d3d3ac90213ec9a8b659ea678866678f,2,95790.3,26.7,2,95790.3,26.7
d3e162ccd42cceda49e15bab20b0a14a,1,0,37.7,1,0,37.7
Expand Down Expand Up @@ -3697,7 +3697,7 @@ d9c9c85316195a77174f29ad7c5b4022,2,24649,44,2,24649,44
d9dda9089bc4e3833b2dd170e4ac9b10,1,0,21.6,1,0,21.6
da04810164fc021b1592dc8b1fed6401,1,0,24.9,1,0,24.9
da30bfae6a9a5a83cadc7eec05eeda03,2,41820.3,34,1,0,20.6
da660877a6d6b415aefc442798798ccb,4,22909716.2,68.3,4,22909716.2,68.3
da660877a6d6b415aefc442798798ccb,4,22909716.2,68.3,4,22909745.2,68.3
da69840b381127b1528ecb3aff6341ee,1,0,18.5,1,0,18.5
da6d9a2e56d9ef2ce69d4d8c33688963,1,0,36,1,0,36
da7a9e5d5e8c6ee725b402ef1b22f12f,1,0,24.4,1,0,24.4
Expand Down Expand Up @@ -3742,7 +3742,7 @@ dd0b36c45e6dd7c0bbca1132041a2bc8,1,0,36.1,1,0,36.1
dd10cf63e03f3226d61c074d9d8e1caf,1,0,20.3,1,0,20.3
dd24f8cede11d6722e4fa5a34ffd0f92,1,0,32.4,1,0,32.4
dd5dcec91f88d9e518cc5386b69e1ee5,1,0,22,1,0,22
dd655a5bf318ca48d36010fce2709553,1,0,22.3,1,0,7.3
dd655a5bf318ca48d36010fce2709553,1,0,7.3,1,0,7.3
dd74f550bb177a933b62b5d2836fa4ac,1,0,47.6,1,0,47.6
dd8191420604dcedf2ec59a470b09b4b,2,6642.3,30.5,2,930.3,30.5
dd897cf7eea6d6a7cc0380f78f29ba4f,1,0,35.5,1,0,35.5
Expand Down Expand Up @@ -3964,11 +3964,11 @@ ea266831e9477cce0b85e20b13aa1f80,1,0,37.8,1,0,37.8
ea34cb8db18f0013c9def40a8ef77fa2,1,0,37.9,1,0,37.9
ea3b0e88bbb5bc8b619c374d71922f4e,2,19881,54.5,2,19881,54.5
ea3d98fed8ae69ce0f7d783ed4bd5af6,1,0,26.9,1,0,26.9
ea7122ae9954678d540f9b751e7332d1,2,303050.3,27.7,2,303050.3,27.7
ea7122ae9954678d540f9b751e7332d1,2,303050.3,27.7,1,0,16.8
ea80be7cc0e28b418054440bef9af100,1,0,25.5,1,0,25.5
ea8a581abae0dc3e269d0ffc7e6ab65f,1,0,22.6,1,0,22.6
eabe5412040e26fb2b47f6d7bf08bd4b,1,0,17.1,1,0,17.1
eacf25c832163cc3c02cc8ef67e5ac81,2,256,27,2,4624,27
eacf25c832163cc3c02cc8ef67e5ac81,2,256,27,2,3481,27
eae143840bf7f0fc86e134802c7dc547,1,0,23.7,1,0,23.7
eaf265fc1e76d003d97acb83e904fae7,1,0,18.8,1,0,18.8
eaf774f16798d781d477621ac7d6de69,1,0,23.5,1,0,23.5
Expand Down Expand Up @@ -4199,7 +4199,7 @@ fa5d9ae6b63e9d33769081f7d4f2b115,1,0,30,1,0,30
fa74eadd074843a8c78542d7602c31d4,1,0,48.4,1,0,48.4
faa914e796a804997c19804300db0204,1,0,42.7,1,0,42.7
faae756f0de0eef0384474255db1e662,1,0,41.6,1,0,41.6
fac6c548649f983888821cb370e87966,1,0,34,1,0,74.5
fac6c548649f983888821cb370e87966,1,0,34,1,0,34
fad39d2e603bae2ac15387a3662de7ff,2,22201,37.6,1,0,11.3
fae22f77df7666ed2fdc5757bd78ed07,1,0,33.9,1,0,33.9
faec3db769a11d268cd4845fb3966167,1,0,41.1,1,0,41.1
Expand Down

0 comments on commit 94988b6

Please sign in to comment.