Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

BIN Packing 3D Item Most Efficiently Given Pack Quantity

5.00/5 (2 votes)
10 Nov 2017CPOL 10K  
Posting this solution because I found all other options out there except this one. In this particular case, I have 1 item that can be packed a # of times and the goal is to pack it in the most efficient manner not to exceed UPS/FedEX LxWxH limitations, not providing box dimensions to fit the item in

BIN Packing Item given LxWxH Number of Times

I was able to find a bunch of solutions out there, but for example to get a UPS/FedEx shipping quote, my items can be packed provided a specified pack quantity. Packing same items in NON defined boxes is not something I found out there. So this method will: provided LxWxH and Quantity, return the best way to pack it with smallest area and least amount of empty space.

Using the Code

The code is fairly simple. This is a brute force approach to finding the first most adequate package size to provide to UPS/FedEx to get a quote. For example: suppose you have an item 22" x 8" x 8" and you want to pack 10 of them together to have a single package. Adequate packed dimensions are: 22x40x16, 44x40x8... Below recursive method will return the result in a decimal[3] array where [0] = Length, [1] = Width and [2] = Height of the newly packed box. Please note that in my code, any given dimension was set not to exceed 108".

C#
protected decimal[] PackItemsInBin(decimal[] PackingDimensions, decimal Length, 
                                   decimal Width, decimal Height, decimal Quantity )
    {
        decimal[] dimensions_l;
        decimal[] dimensions_w;
        decimal[] dimensions_h;

        decimal LengthPackingQuantity, WidthPackingQuantity, 
                HeightPackingQuantity, LengthArea, WidthArea, HeightArea = 0; 
        try
        {
            if (Math.Floor(PackingDimensions[0] / Length) * Math.Floor(PackingDimensions[1] / Width) * 
                       Math.Floor(PackingDimensions[2] / Height) >= Quantity)
            {
                return PackingDimensions;
            }
            else
            {
                //HAVE NOT FOUND THE SOLUTION 
                //so lets go in all directions until we get a solution. 
                dimensions_l = new decimal[3] { PackingDimensions[0], 
                                                PackingDimensions[1], PackingDimensions[2] };
                dimensions_w = new decimal[3] { PackingDimensions[0], 
                                                PackingDimensions[1], PackingDimensions[2] };
                dimensions_h = new decimal[3] { PackingDimensions[0], 
                                                PackingDimensions[1], PackingDimensions[2] };

                dimensions_l[0] += Length;//go with length
                dimensions_w[1] += Width;//go with width
                dimensions_h[2] += Height;//go with height

                //get the results from each direciton 
                dimensions_l = PackItemsInBin(dimensions_l, Length, Width, Height, Quantity);
                dimensions_w = PackItemsInBin(dimensions_w, Length, Width, Height, Quantity);
                dimensions_h = PackItemsInBin(dimensions_h, Length, Width, Height, Quantity);

                //calculate some of the measurements to use to determine the best packed choice 
                LengthPackingQuantity = Math.Floor(dimensions_l[0] / Length) * 
                    Math.Floor(dimensions_l[1] / Width) * Math.Floor(dimensions_l[2] / Height);
                WidthPackingQuantity = Math.Floor(dimensions_w[0] / Length) * 
                    Math.Floor(dimensions_w[1] / Width) * Math.Floor(dimensions_w[2] / Height);
                HeightPackingQuantity = Math.Floor(dimensions_h[0] / Length) * 
                    Math.Floor(dimensions_h[1] / Width) * Math.Floor(dimensions_h[2] / Height);

                LengthArea = dimensions_l[0] + dimensions_l[1] + dimensions_l[2];
                WidthArea = dimensions_w[0] + dimensions_w[1] + dimensions_w[2];
                HeightArea = dimensions_h[0] + dimensions_h[1] + dimensions_h[2];

                //GB. determine if the best solution is here based on several decisions, 
                //for example if there is empty space or not and what the area is 
                //GB. best decision is made on the packed box that takes the least amount of space 
                //and has the least amount of empty space considering the area 
                if (LengthPackingQuantity + LengthArea <= WidthArea + WidthPackingQuantity && 
                    LengthPackingQuantity + LengthArea <= HeightArea + 
                    HeightPackingQuantity && dimensions_l[0] < 108)
                {
                    return dimensions_l;
                }
                else if (WidthArea + WidthPackingQuantity <= LengthPackingQuantity + 
                         LengthArea && WidthArea + WidthPackingQuantity <= HeightArea + 
                         HeightPackingQuantity && dimensions_l[0] < 108)
                {
                    return dimensions_w;
                }
                else
                    return dimensions_h; 
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message, ex);
        }
    }

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)