Ejemplo n.º 1
0
        private void Insert(
            Cuboid cuboid,
            FreeCuboidChoiceHeuristic cuboidChoice,
            GuillotineSplitHeuristic splitMethod)
        {
            // Check is overweight
            if (cuboid.Weight + _usedCuboids.Sum(x => x.Weight) > _parameter.BinWeight)
            {
                return;
            }

            // Find where to put the new cuboid
            var freeNodeIndex = 0;

            FindPositionForNewNode(cuboid, cuboidChoice, out freeNodeIndex);

            // Abort if we didn't have enough space in the bin
            if (!cuboid.IsPlaced)
            {
                return;
            }

            // Remove the space that was just consumed by the new cuboid
            if (freeNodeIndex < 0)
            {
                throw new ArithmeticException("freeNodeIndex < 0");
            }
            SplitFreeCuboidByHeuristic(_freeCuboids[freeNodeIndex], cuboid, splitMethod);
            _freeCuboids.RemoveAt(freeNodeIndex);

            // Remember the new used cuboid
            _usedCuboids.Add(cuboid);
        }
Ejemplo n.º 2
0
        /// Splits the given L-shaped free rectangle into two new free rectangles after placedRect has been placed into it.
        /// Determines the split axis by using the given heuristic.
        private void SplitFreeRectByHeuristic(Rect freeRect, Rect placedRect, GuillotineSplitHeuristic method)
        {
            // Compute the lengths of the leftover area.
            int w = freeRect.Width - placedRect.Width;
            int h = freeRect.Height - placedRect.Height;

            // Placing placedRect into freeRect results in an L-shaped free area, which must be split into
            // two disjoint rectangles. This can be achieved with by splitting the L-shape using a single line.
            // We have two choices: horizontal or vertical.

            // Use the given heuristic to decide which choice to make.

            bool splitHorizontal;

            switch (method)
            {
            case GuillotineSplitHeuristic.SplitShorterLeftoverAxis:
                // Split along the shorter leftover axis.
                splitHorizontal = (w <= h);
                break;

            case GuillotineSplitHeuristic.SplitLongerLeftoverAxis:
                // Split along the longer leftover axis.
                splitHorizontal = (w > h);
                break;

            case GuillotineSplitHeuristic.SplitMinimizeArea:
                // Maximize the larger area == minimize the smaller area.
                // Tries to make the single bigger rectangle.
                splitHorizontal = (placedRect.Width * h > w * placedRect.Height);
                break;

            case GuillotineSplitHeuristic.SplitMaximizeArea:
                // Maximize the smaller area == minimize the larger area.
                // Tries to make the rectangles more even-sized.
                splitHorizontal = (placedRect.Width * h <= w * placedRect.Height);
                break;

            case GuillotineSplitHeuristic.SplitShorterAxis:
                // Split along the shorter total axis.
                splitHorizontal = (freeRect.Width <= freeRect.Height);
                break;

            case GuillotineSplitHeuristic.SplitLongerAxis:
                // Split along the longer total axis.
                splitHorizontal = (freeRect.Width > freeRect.Height);
                break;

            default:
                splitHorizontal = true;
                break;
            }
            // Perform the actual split.
            SplitFreeRectAlongAxis(freeRect, placedRect, splitHorizontal);
        }
Ejemplo n.º 3
0
 public BinPackGuillotineAlgorithm(
     BinPackParameter parameter,
     FreeCuboidChoiceHeuristic cuboidChoice,
     GuillotineSplitHeuristic splitMethod)
 {
     _parameter    = parameter;
     _cuboidChoice = cuboidChoice;
     _splitMethod  = splitMethod;
     _usedCuboids  = new List <Cuboid>();
     _freeCuboids  = new List <Cuboid>();
     AddFreeCuboid(new Cuboid(parameter.BinWidth, parameter.BinHeight, parameter.BinDepth));
 }
Ejemplo n.º 4
0
 public BinPackShelfAlgorithm(
     BinPackParameter parameter,
     FreeRectChoiceHeuristic rectChoice,
     GuillotineSplitHeuristic splitMethod,
     ShelfChoiceHeuristic shelfChoice)
 {
     _parameter     = parameter;
     _rectChoice    = rectChoice;
     _splitMethod   = splitMethod;
     _shelfChoice   = shelfChoice;
     _currentY      = 0;
     _shelves       = new List <Shelf>();
     _packedCuboids = new List <Cuboid>();
     StartNewShelf(0);
 }
Ejemplo n.º 5
0
        public void InsertOnPosition(
            Rectangle rect,
            GuillotineSplitHeuristic splitMethod,
            int freeRectIndex)
        {
            // Remove the space that was just consumed by the new rectangle.
            if (freeRectIndex < 0)
            {
                throw new ArithmeticException("freeRectIndex < 0");
            }
            SplitFreeRectByHeuristic(_freeRectangles[freeRectIndex], rect, splitMethod);
            _freeRectangles.RemoveAt(freeRectIndex);

            // Remember the new used rectangle
            _usedRectangles.Add(rect);
        }
Ejemplo n.º 6
0
 public BinPackGuillotineAlgorithm(
     decimal binWidth,
     decimal binHeight,
     decimal binDepth,
     FreeCuboidChoiceHeuristic cuboidChoice,
     GuillotineSplitHeuristic splitMethod)
 {
     _binWidth     = binWidth;
     _binHeight    = binHeight;
     _binDepth     = binDepth;
     _cuboidChoice = cuboidChoice;
     _splitMethod  = splitMethod;
     _usedCuboids  = new List <Cuboid>();
     _freeCuboids  = new List <Cuboid>();
     AddFreeCuboid(new Cuboid(_binWidth, _binHeight, _binDepth));
 }
Ejemplo n.º 7
0
        private void SplitFreeRectByHeuristic(
            Rectangle freeRect,
            Rectangle placedRect,
            GuillotineSplitHeuristic method)
        {
            // Compute the lengths of the leftover area.
            decimal w = freeRect.Width - placedRect.Width;
            decimal h = freeRect.Height - placedRect.Height;

            // Placing placedRect into freeRect results in an L-shaped free area, which
            // must be split into two disjoint rectangles. This can be achieved with by
            // splitting the L-shape using a single line.
            // We have two choices: horizontal or vertical.

            // Use the given heuristic to decide which choice to make.

            bool splitHorizontal;

            switch (method)
            {
            case GuillotineSplitHeuristic.SplitShorterLeftoverAxis:
                // Split along the shorter leftover axis.
                splitHorizontal = (w <= h);
                break;

            case GuillotineSplitHeuristic.SplitLongerLeftoverAxis:
                // Split along the longer leftover axis.
                splitHorizontal = (w > h);
                break;

            case GuillotineSplitHeuristic.SplitShorterAxis:
                // Split along the shorter total axis.
                splitHorizontal = (freeRect.Width <= freeRect.Height);
                break;

            case GuillotineSplitHeuristic.SplitLongerAxis:
                // Split along the longer total axis.
                splitHorizontal = (freeRect.Width > freeRect.Height);
                break;

            default:
                throw new NotSupportedException($"split method is unsupported: {method}");
            }

            // Perform the actual split.
            SplitFreeRectAlongAxis(freeRect, placedRect, splitHorizontal);
        }
 public BinPackShelfAlgorithm(
     decimal binWidth,
     decimal binHeight,
     decimal binDepth,
     FreeRectChoiceHeuristic rectChoice,
     GuillotineSplitHeuristic splitMethod,
     ShelfChoiceHeuristic shelfChoice)
 {
     _binWidth    = binWidth;
     _binHeight   = binHeight;
     _binDepth    = binDepth;
     _rectChoice  = rectChoice;
     _splitMethod = splitMethod;
     _shelfChoice = shelfChoice;
     _currentY    = 0;
     _shelves     = new List <Shelf>();
     StartNewShelf(0);
 }
Ejemplo n.º 9
0
        private void SplitFreeCuboidByHeuristic(
            Cuboid freeCuboid,
            Cuboid placedCuboid,
            GuillotineSplitHeuristic method)
        {
            // Compute the lengths of the leftover area.
            var w = freeCuboid.Width - placedCuboid.Width;
            var d = freeCuboid.Depth - placedCuboid.Depth;

            // Use the given heuristic to decide which choice to make.

            bool splitHorizontal;

            switch (method)
            {
            case GuillotineSplitHeuristic.SplitShorterLeftoverAxis:
                // Split along the shorter leftover axis.
                splitHorizontal = (w <= d);
                break;

            case GuillotineSplitHeuristic.SplitLongerLeftoverAxis:
                // Split along the longer leftover axis.
                splitHorizontal = (w > d);
                break;

            case GuillotineSplitHeuristic.SplitShorterAxis:
                // Split along the shorter total axis.
                splitHorizontal = (freeCuboid.Width <= freeCuboid.Depth);
                break;

            case GuillotineSplitHeuristic.SplitLongerAxis:
                // Split along the longer total axis.
                splitHorizontal = (freeCuboid.Width > freeCuboid.Depth);
                break;

            default:
                throw new NotSupportedException($"split method is unsupported: {method}");
            }

            // Perform the actual split.
            SplitFreeCuboidAlongAxis(freeCuboid, placedCuboid, splitHorizontal);
        }
Ejemplo n.º 10
0
        /// Inserts a single rectangle into the bin. The packer might rotate the rectangle, in which case the returned
        /// struct will have the width and height values swapped.
        /// @param merge If true, performs free Rectangle Merge procedure after packing the new rectangle. This procedure
        ///		tries to defragment the list of disjoint free rectangles to improve packing performance, but also takes up
        ///		some extra time.
        /// @param rectChoice The free rectangle choice heuristic rule to use.
        /// @param splitMethod The free rectangle split heuristic rule to use.
        public BinRect Insert(int width, int height, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
        {
            // Find where to put the new rectangle.
            int     freeNodeIndex = 0;
            BinRect newRect       = FindPositionForNewNode(width, height, rectChoice, ref freeNodeIndex);

            // Abort if we didn't have enough space in the bin.
            if (newRect.height == 0)
            {
                return(newRect);
            }

            // Remove the space that was just consumed by the new rectangle.
            {
                var item = freeRectangles[freeNodeIndex];
                SplitFreeRectByHeuristic(ref item, ref newRect, splitMethod);
                freeRectangles[freeNodeIndex] = item;
                freeRectangles.RemoveAt(freeNodeIndex);
            }
            // Perform a Rectangle Merge step if desired.
            if (merge)
            {
                MergeFreeList();
            }

            // Remember the new used rectangle.
            usedRectangles.Add(newRect);


            return(newRect);
        }
Ejemplo n.º 11
0
        /// Inserts a list of rectangles into the bin.
        /// @param rects The list of rectangles to add. This list will be destroyed in the packing process.
        /// @param merge If true, performs Rectangle Merge operations during the packing process.
        /// @param rectChoice The free rectangle choice heuristic rule to use.
        /// @param splitMethod The free rectangle split heuristic rule to use.
        public void Insert(List <RectSize> rects, bool merge,
                           FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
        { // Remember variables about the best packing choice we have made so far during the iteration process.
            int  bestFreeRect = 0;
            int  bestRect     = 0;
            bool bestFlipped  = false;

            // Pack rectangles one at a time until we have cleared the rects array of all rectangles.
            // rects will get destroyed in the process.
            while (rects.Count > 0)
            {
                // Stores the penalty score of the best rectangle placement - bigger=worse, smaller=better.
                int bestScore = int.MaxValue;

                for (int i = 0; i < freeRectangles.Count; ++i)
                {
                    for (int j = 0; j < rects.Count; ++j)
                    {
                        // If this rectangle is a perfect match, we pick it instantly.
                        if (rects[j].width == freeRectangles[i].width && rects[j].height == freeRectangles[i].height)
                        {
                            bestFreeRect = i;
                            bestRect     = j;
                            bestFlipped  = false;
                            bestScore    = int.MinValue;
                            i            = freeRectangles.Count; // Force a jump out of the outer loop as well - we got an instant fit.
                            break;
                        }
                        // If flipping this rectangle is a perfect match, pick that then.
                        else if (rects[j].height == freeRectangles[i].width && rects[j].width == freeRectangles[i].height)
                        {
                            bestFreeRect = i;
                            bestRect     = j;
                            bestFlipped  = true;
                            bestScore    = int.MinValue;
                            i            = freeRectangles.Count; // Force a jump out of the outer loop as well - we got an instant fit.
                            break;
                        }
                        // Try if we can fit the rectangle upright.
                        else if (rects[j].width <= freeRectangles[i].width && rects[j].height <= freeRectangles[i].height)
                        {
                            var item  = freeRectangles[i];
                            int score = ScoreByHeuristic(rects[j].width, rects[j].height, ref item, rectChoice);
                            freeRectangles[i] = item;
                            if (score < bestScore)
                            {
                                bestFreeRect = i;
                                bestRect     = j;
                                bestFlipped  = false;
                                bestScore    = score;
                            }
                        }
                        // If not, then perhaps flipping sideways will make it fit?
                        else if (rects[j].height <= freeRectangles[i].width && rects[j].width <= freeRectangles[i].height)
                        {
                            var item  = freeRectangles[i];
                            int score = ScoreByHeuristic(rects[j].height, rects[j].width, ref item, rectChoice);
                            freeRectangles[i] = item;
                            if (score < bestScore)
                            {
                                bestFreeRect = i;
                                bestRect     = j;
                                bestFlipped  = true;
                                bestScore    = score;
                            }
                        }
                    }
                }

                // If we didn't manage to find any rectangle to pack, abort.
                if (bestScore == int.MaxValue)
                {
                    return;
                }

                // Otherwise, we're good to go and do the actual packing.
                BinRect newNode;
                newNode.x      = freeRectangles[bestFreeRect].x;
                newNode.y      = freeRectangles[bestFreeRect].y;
                newNode.width  = rects[bestRect].width;
                newNode.height = rects[bestRect].height;

                if (bestFlipped)
                {
                    int temp = newNode.width;
                    newNode.width  = newNode.height;
                    newNode.height = temp;
                }

                // Remove the free space we lost in the bin.
                {
                    var item = freeRectangles[bestFreeRect];
                    SplitFreeRectByHeuristic(ref item, ref newNode, splitMethod);
                    freeRectangles[bestFreeRect] = item;
                    freeRectangles.RemoveAt(bestFreeRect);
                }
                // Remove the rectangle we just packed from the input list.
                rects.RemoveAt(bestRect);

                // Perform a Rectangle Merge step if desired.
                if (merge)
                {
                    MergeFreeList();
                }

                // Remember the new used rectangle.
                usedRectangles.Add(newNode);
            }
        }