示例#1
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 override Rect Insert(RectSize rectSize, GenericOption option)
        {
            var opt    = option as Option;
            int width  = rectSize.Width;
            int height = rectSize.Height;

            // Find where to put the new rectangle.
            int  freeNodeIndex = 0;
            Rect newRect       = FindPositionForNewNode(width, height, opt.FreeRectChoice, 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.
            SplitFreeRectByHeuristic(freeRectangles[freeNodeIndex], newRect, opt.GuillotineSplit);
            freeRectangles.RemoveAt(freeNodeIndex);

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

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

            // Check that we're really producing correct packings here.
            disjointRects.Add(newRect);
            return(newRect);
        }
示例#2
0
        /// Places the given rectangle into the bin.
        private void PlaceRect(Rect node)
        {
            int numRectanglesToProcess = freeRectangles.Count;

            for (int i = 0; i < numRectanglesToProcess; ++i)
            {
                if (SplitFreeNode(freeRectangles[i], ref node))
                {
                    freeRectangles.RemoveAt(i);
                    --i;
                    --numRectanglesToProcess;
                }
            }
            PruneFreeList();
            UsedRectangles.Add(node);
        }
示例#3
0
        /// Inserts a single rectangle into the bin, possibly rotated.
        public override Rect Insert(RectSize rect, GenericOption option)
        {
            Rect newNode = new Rect();
            // Unused in this function. We don't need to know the score after finding the position.
            int score1 = int.MaxValue;
            int score2 = int.MaxValue;

            int width = rect.Width, height = rect.Height;
            var optionMaxRectsBinPath = option as Option;

            switch (optionMaxRectsBinPath.Method)
            {
            case FreeRectChoiceHeuristic.RectBestShortSideFit: newNode = FindPositionForNewNodeBestShortSideFit(width, height, ref score1, ref score2); break;

            case FreeRectChoiceHeuristic.RectBottomLeftRule: newNode = FindPositionForNewNodeBottomLeft(width, height, ref score1, ref score2); break;

            case FreeRectChoiceHeuristic.RectContactPointRule: newNode = FindPositionForNewNodeContactPoint(width, height, ref score1); break;

            case FreeRectChoiceHeuristic.RectBestLongSideFit: newNode = FindPositionForNewNodeBestLongSideFit(width, height, ref score2, ref score1); break;

            case FreeRectChoiceHeuristic.RectBestAreaFit: newNode = FindPositionForNewNodeBestAreaFit(width, height, ref score1, ref score2); break;
            }

            if (newNode.Height == 0)
            {
                return(newNode);
            }

            int numRectanglesToProcess = freeRectangles.Count;

            for (int i = 0; i < numRectanglesToProcess; ++i)
            {
                if (SplitFreeNode(freeRectangles[i], ref newNode))
                {
                    freeRectangles.RemoveAt(i);
                    --i;
                    --numRectanglesToProcess;
                }
            }
            PruneFreeList();

            UsedRectangles.Add(newNode);
            return(newNode);
        }
示例#4
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)
                        {
                            int score = ScoreByHeuristic(rects[j].Width, rects[j].Height, freeRectangles[i], rectChoice);
                            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)
                        {
                            int score = ScoreByHeuristic(rects[j].Height, rects[j].Width, freeRectangles[i], rectChoice);
                            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.
                Rect newNode = new Rect
                {
                    X      = freeRectangles[bestFreeRect].X,
                    Y      = freeRectangles[bestFreeRect].Y,
                    Width  = rects[bestRect].Width,
                    Height = rects[bestRect].Height
                };

                if (bestFlipped)
                {
                    var temp = newNode.Width;
                    newNode.Width  = newNode.Height;
                    newNode.Height = temp;
                }

                // Remove the free space we lost in the bin.
                SplitFreeRectByHeuristic(freeRectangles[bestFreeRect], newNode, splitMethod);
                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);

                // Check that we're really producing correct packings here.
                disjointRects.Add(newNode);
            }
        }
示例#5
0
 public override void Init(int binWidth, int binHeight)
 {
     base.Init(binWidth, binHeight); UsedRectangles.Clear();
 }