Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not optimal packing in a box #608

Open
patryk-kolorama opened this issue May 2, 2024 · 7 comments
Open

Not optimal packing in a box #608

patryk-kolorama opened this issue May 2, 2024 · 7 comments

Comments

@patryk-kolorama
Copy link

Hi,
I have a problem with optimal packaging of items in a box.
I have 3 types of box depths that are cut to the desired length but not exceeding the courier's limit.

So I made a while loop from the smallest possible size to the longest package + mountings box length in the order

$w=400;
while ($w<=2360) {
$packer->addBox(new MyBox('Box120 '.$w, $w, 285, 120, 1200, 25000));
$packer->addBox(new MyBox('Box160 '.$w, $w, 285, 160, 1200, 25000));
$packer->addBox(new MyBox('Box250 '.$w, $w, 285, 250, 1200, 25000));
$w += 10;
}
For now, in the example, I made the same outer dimensions as the inner ones

Items to pack are blinds and a box with mountings

$packer->addItem(new MyItem('mountings', 282, 110, 160, 500), 1);
$packer->addItem(new MyItem('blind 50mm', 2260, 218, 80, 1380), 1);
$packer->addItem(new MyItem('blind 35mm ', 1585, 192, 60, 5050), 1);
$packer->addItem(new MyItem('blind 50mm', 1175, 218, 80, 5190), 1);
$packer->addItem(new MyItem('blind 35mm', 1028, 191, 60, 3210), 1);
$packer->addItem(new MyItem('blind 35mm', 1028, 192, 60, 3200), 1);

https://boxpacker.io/en/master/visualiser.html?packing=%7B%22items%22%3A%5B%5B%22blind+50mm%22%2C218%2C1175%2C80%5D%2C%5B%22blind+35mm%22%2C192%2C1028%2C60%5D%2C%5B%22blind+35mm%22%2C191%2C1028%2C60%5D%2C%5B%22blind+50mm%22%2C218%2C2260%2C80%5D%2C%5B%22blind+35mm%22%2C192%2C1585%2C60%5D%2C%5B%22mountings%22%2C110%2C282%2C160%5D%5D%2C%22boxes%22%3A%5B%5B%22Box250+1180%22%2C285%2C1180%2C250%2C%5B%5B0%2C0%2C0%2C0%2C218%2C1175%2C80%5D%2C%5B1%2C0%2C0%2C80%2C192%2C1028%2C60%5D%2C%5B2%2C0%2C0%2C140%2C191%2C1028%2C60%5D%5D%5D%2C%5B%22Box250+2260%22%2C285%2C2260%2C250%2C%5B%5B3%2C0%2C0%2C0%2C218%2C2260%2C80%5D%2C%5B4%2C0%2C0%2C80%2C192%2C1585%2C60%5D%2C%5B5%2C0%2C1585%2C80%2C282%2C110%2C160%5D%5D%5D%5D%7D

And the problem is that the algorithm uses the box with mountings to pack it into two 250 boxes instead of two 160 boxes.
When I removed
$packer->addBox(new MyBox('Box250 '.$w, $w, 285, 250, 1200, 25000));
it was packed as it should be.
I thought that maybe it doesn't rotate the box with mountings, but this option is enabled.

https://boxpacker.io/en/master/visualiser.html?packing=%7B%22items%22%3A%5B%5B%22blind+50mm%22%2C218%2C2260%2C80%5D%2C%5B%22blind+50mm%22%2C218%2C1175%2C80%5D%2C%5B%22blind+35mm%22%2C192%2C1028%2C60%5D%2C%5B%22blind+35mm%22%2C192%2C1585%2C60%5D%2C%5B%22blind+35mm%22%2C191%2C1028%2C60%5D%2C%5B%22mountings%22%2C110%2C282%2C160%5D%5D%2C%22boxes%22%3A%5B%5B%22Box160+2260%22%2C285%2C2260%2C160%2C%5B%5B0%2C0%2C0%2C0%2C218%2C2260%2C80%5D%2C%5B1%2C0%2C0%2C80%2C218%2C1175%2C80%5D%2C%5B2%2C0%2C1175%2C80%2C192%2C1028%2C60%5D%5D%5D%2C%5B%22Box160+1700%22%2C285%2C1700%2C160%2C%5B%5B3%2C0%2C0%2C0%2C192%2C1585%2C60%5D%2C%5B4%2C0%2C0%2C60%2C191%2C1028%2C60%5D%2C%5B5%2C0%2C1585%2C0%2C282%2C110%2C160%5D%5D%5D%5D%7D

In my example, I would rather have a box with mountings to make the box longer than choose a larger one.
But idk how to do this.

dvdoug added a commit that referenced this issue May 5, 2024
dvdoug added a commit that referenced this issue May 5, 2024
@dvdoug
Copy link
Owner

dvdoug commented May 5, 2024

Hi @patryk-kolorama

You didn't say which version you're using, but on master with the testcase that I've just checked in based off your sample, I get the results in this link which has a 250 box and 120 box.

If I turn off weight redistribution, then I get this packing

@dvdoug
Copy link
Owner

dvdoug commented May 5, 2024

Can you explain a bit more why you'd expect 2x160 boxes?

@patryk-kolorama
Copy link
Author

Thank @dvdoug for your answer
My version is 4.0.1 (Master)

The difference probably came from Rotation, i have KeepFlat.

In my case the algorithm should pack the order into the smallest number of boxes while minimizing the empty space in the box.
So I expect 2x160 as this will minimize empty space in the boxes.
Additionally, it would be best if the long blinds were together in a box.

dvdoug added a commit that referenced this issue May 6, 2024
@dvdoug
Copy link
Owner

dvdoug commented May 6, 2024

If you turn off weight redistribution ($packer->setMaxBoxesToBalanceWeight(0)), you get a 250 and a 120 rather than 2x250 which is more in line with what you're looking for (i.e. focusing on volume)

BoxPacker packs 1 box at a time though, so the default algorithm is never going to give you 2x160 unfortunately.

@Gemorroj
Copy link

Gemorroj commented May 9, 2024

Have same issue. It seems to me that this feature (setMaxBoxesToBalanceWeight) should be disabled by default.
Example:

<?php

use DVDoug\BoxPacker\Packer;
use DVDoug\BoxPacker\Rotation;

require __DIR__.'/vendor/autoload.php';


$packer = new Packer();

// $packer->setMaxBoxesToBalanceWeight(0); // https://boxpacker.io/en/stable/weight-distribution.html

// small package
$box1 = new \DVDoug\BoxPacker\Test\TestBox(
    reference: 'package1',
    outerWidth: 2000,
    outerLength: 10000,
    outerDepth: 9500,
    emptyWeight: 400,
    innerWidth: 2000,
    innerLength: 10000,
    innerDepth: 9500,
    maxWeight: 10000,
);
$packer->addBox($box1);

// big package
$box2 = new \DVDoug\BoxPacker\Test\TestBox(
    reference: 'package2',
    outerWidth: 6000,
    outerLength: 14500,
    outerDepth: 15750,
    emptyWeight: 500,
    innerWidth: 6000,
    innerLength: 14500,
    innerDepth: 15750,
    maxWeight: 50000,
);
$packer->addBox($box2);

$item = new \DVDoug\BoxPacker\Test\TestItem(
    description: 'product',
    width: 1650,
    length: 6200,
    depth: 5370,
    weight: 1000,
    allowedRotation: Rotation::BestFit,
);
$packer->addItem($item, 21);

$data = $packer->pack();
echo $data->generateVisualisationURL().PHP_EOL.PHP_EOL;

/** @var \DVDoug\BoxPacker\PackedBox $packedBox */
foreach ($data as $packedBox) {
    print_r($packedBox->box->getReference().PHP_EOL);
}

@patryk-kolorama
Copy link
Author

Thanks for answer @dvdoug
You're doing a great job

Below I have another strange case where in example the algorithm works great, but when I reduce the depth value in the mountings, it creates a new package for some reason

$packer->setMaxBoxesToBalanceWeight(0);

$packer->addItem(new MyItem('Mountings', 200, 285, 250, 500), 1);
$packer->addItem(new MyItem('blind 50mm', 1000, 285, 62, 5000), 1);
$packer->addItem(new MyItem('blind 50mm', 1000, 285, 62, 5000), 1);
$packer->addItem(new MyItem('blind 50mm', 1000, 285, 62, 5000), 1);
$packer->addItem(new MyItem('blind 50mm', 1000, 285, 62, 5000), 1);

$packer->addBox(new MyBox('Box', 1200, 285, 250, 1200, 25000));

https://boxpacker.io/en/master/visualiser.html?packing={"items":[["blind 50mm",285,1000,62],["blind 50mm",285,1000,62],["blind 50mm",285,1000,62],["blind 50mm",285,1000,62],["Mountings",285,200,250]],"boxes":[["Box",285,1200,250,[[0,0,0,0,285,1000,62],[1,0,0,62,285,1000,62],[2,0,0,124,285,1000,62],[3,0,0,186,285,1000,62],[4,0,1000,0,285,200,250]]]]}

If i change the depth of the Mountings to 240 then algorithm create second box.
$packer->addItem(new MyItem('Mountings', 200, 285, 240, 500), 1);

https://boxpacker.io/en/master/visualiser.html?packing=%7B%22items%22%3A%5B%5B%22blind+50mm%22%2C285%2C1000%2C62%5D%2C%5B%22blind+50mm%22%2C285%2C1000%2C62%5D%2C%5B%22blind+50mm%22%2C285%2C1000%2C62%5D%2C%5B%22Mountings%22%2C285%2C200%2C240%5D%2C%5B%22blind+50mm%22%2C285%2C1000%2C62%5D%5D%2C%22boxes%22%3A%5B%5B%22Box%22%2C285%2C1200%2C250%2C%5B%5B0%2C0%2C0%2C0%2C285%2C1000%2C62%5D%2C%5B1%2C0%2C0%2C62%2C285%2C1000%2C62%5D%2C%5B2%2C0%2C0%2C124%2C285%2C1000%2C62%5D%2C%5B3%2C0%2C1000%2C0%2C285%2C200%2C240%5D%5D%5D%2C%5B%22Box%22%2C285%2C1200%2C250%2C%5B%5B4%2C0%2C0%2C0%2C285%2C1000%2C62%5D%5D%5D%5D%7D

@dvdoug
Copy link
Owner

dvdoug commented May 27, 2024

Super, super-tight packings like these are very susceptible to the order of items and the relationships between the dimensions - what's happening here is the blinds are being packed up to the depth of the mountings. When the mountings are 250mm deep, this works because 4x62 < 250.

Where the mountings are only 240, we can only pack 3 inside that depth. Then a new "layer" is started where everything resets to zero, but in a box that is 250mm deep and the previously layer being 240mm that leaves only a depth of 10mm to work with and that last item is judged not to fit :(

Tracking of these "holes" so the algorithm can come back and fill them in is on my wishlist as it's the most common cause of "stupid" packing decisions, but isn't trivial as the current algorithm is explicitly based around not backtracking

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants