Example #1
0
        /// <summary>
        /// Pack a list of supplied rectangles into the supplied bin.
        /// </summary>
        /// <param name="items">The rectangles to pack.</param>
        /// <param name="container">The container to pack into, clearing any previously initialised bin.</param>
        /// <param name="packingStrategy">The method to use when packing.</param>
        public void PackOneContainer(
            List <Rectangle> items,
            Rectangle container,
            RectanglePackingStrategy packingStrategy)
        {
            this.InitialiseBinFromRectangle(container);

            if (this.FreeRectangles.Count == 0)
            {
                throw new InvalidOperationException("Bin has not been initialised");
            }
            if (items.Count == 0)
            {
                throw new ArgumentNullException(nameof(items));
            }

            for (int i = 0; i < items.Count; i++)
            {
                // skip already placed rectangles
                var rect = items[i];
                if (rect == null)
                {
                    continue;
                }

                var placed = this.PlaceItem(rect, packingStrategy, i);
                if (placed)
                {
                    items[i] = null;
                }
            }
        }
Example #2
0
        public static Dictionary <string, object> PackRectangles(
            List <Rectangle> items,
            List <Rectangle> containers,
            [DefaultArgument("RectanglePackingStrategy.BestAreaFits")] RectanglePackingStrategy strategy)
        {
            var packer  = new RectanglePacker();
            var results = packer.PackMultipleContainers(items, containers, strategy);

            return(results.ToDictionary());
        }
Example #3
0
        /// <summary>
        /// Chooses the best free rectangle for an item based on the placement method.
        /// Rectangles are formed from the leftover free space in the bin.
        /// </summary>
        /// <param name="item">The rectangle to place</param>
        /// <param name="placementMethod">The placement method</param>
        /// <param name="this">The bin packing result to investigate.</param>
        /// <returns>The free rectangle with best score</returns>
        private FreeRectangle GetBestFreeRectangle(
            Rectangle item,
            RectanglePackingStrategy placementMethod)
        {
            var freeRectangles = new List <FreeRectangle>();

            for (int i = 0; i < this.FreeRectangles.Count; i++)
            {
                var fRect = this.FreeRectangles[i];

                FreeRectangle chosenFreeRect;
                var           fitsItem = new List <FreeRectangle>
                {
                    ScoreRectanglePlacementInBin(item, placementMethod, fRect, true),
                    ScoreRectanglePlacementInBin(item, placementMethod, fRect, false)
                };
                fitsItem.RemoveAll(x => x == null);

                if (fitsItem.Count == 1)
                {
                    chosenFreeRect = fitsItem[0];
                    fRect.score    = chosenFreeRect.score;
                    fRect.rotate   = chosenFreeRect.rotate;
                    freeRectangles.Add(fRect);
                }
                else if (fitsItem.Count == 2)
                {
                    // Choose free rect with smallest score
                    chosenFreeRect = fitsItem.Aggregate((f1, f2) => f1.score < f2.score ? f1 : f2);
                    fRect.score    = chosenFreeRect.score;
                    fRect.rotate   = chosenFreeRect.rotate;
                    freeRectangles.Add(fRect);
                }
            }
            if (freeRectangles.Count > 0)
            {
                // Choose free rect with smallest score
                return(freeRectangles.Aggregate((f1, f2) => f1.score < f2.score ? f1 : f2));
            }
            else
            {
                return(null);
            }
        }
Example #4
0
 private static double Score(
     FreeRectangle freeRect,
     Rectangle item,
     RectanglePackingStrategy placementMethod)
 {
     if (placementMethod == RectanglePackingStrategy.BestShortSideFits)
     {
         return(BSSF_Score(freeRect, item));
     }
     else if (placementMethod == RectanglePackingStrategy.BestLongSideFits)
     {
         return(BLSF_Score(freeRect, item));
     }
     else if (placementMethod == RectanglePackingStrategy.BestAreaFits)
     {
         return(BAF_Score(freeRect, item));
     }
     return(0);
 }
Example #5
0
        /// <summary>
        /// Pack a list of supplied rectangles into the supplied containers.
        /// </summary>
        /// <param name="items">The rectangles to pack.</param>
        /// <param name="containers">The containers to pack into, clearing any previously initialised bin.</param>
        /// <param name="packingStrategy">The method to use when packing.</param>
        /// <returns>The list of packing results for each container.</returns>
        public List <IPacker <Rectangle, Rectangle> > PackMultipleContainers(
            List <Rectangle> items,
            List <Rectangle> containers,
            RectanglePackingStrategy packingStrategy)
        {
            // we need to keep track of packed items across containers
            // and then aggregate results, hence the lists external to BinPacker object
            var remainingRects = new List <Rectangle>(items);
            var packers        = new List <IPacker <Rectangle, Rectangle> >();

            for (var i = 0; i < containers.Count; i++)
            {
                var packer = new RectanglePacker();

                packer.PackOneContainer(remainingRects, containers[i], packingStrategy);
                packers.Add(packer as IPacker <Rectangle, Rectangle>);
            }
            return(packers);
        }
Example #6
0
        private static FreeRectangle ScoreRectanglePlacementInBin(Rectangle item, RectanglePackingStrategy placementMethod, FreeRectangle fRect, bool rotate)
        {
            if (!ItemFits(fRect, item, rotate))
            {
                return(null);
            }

            // TODO : we're doing un-necessary allocations in some cases, duplicating the fRect
            var newFree = new FreeRectangle
            {
                xPos   = fRect.xPos,
                yPos   = fRect.yPos,
                height = fRect.height,
                width  = fRect.width,
                rotate = rotate,
            };

            newFree.score = Score(newFree, item, placementMethod);

            return(newFree);
        }
Example #7
0
        /// <summary>
        /// Find best free rectangle and place next rectangle
        /// </summary>
        /// <param name="item"></param>
        /// <param name="placementMethod"></param>
        /// <param name="itemIndex"></param>
        private bool PlaceItem(
            Rectangle item,
            RectanglePackingStrategy placementMethod,
            int itemIndex)
        {
            FreeRectangle freeRect = this.GetBestFreeRectangle(item, placementMethod);

            if (freeRect == null)
            {
                this.RemainingItems.Add(item);
                return(false);
            }

            // translate rectangle to correct orientation and position
            if (freeRect.rotate)
            {
                item = Rotate(item);
            }
            var newCS      = CoordinateSystem.ByOrigin(freeRect.xPos, freeRect.yPos);
            var originCS   = CoordinateSystem.ByOrigin(item.StartPoint.X - item.Width, item.StartPoint.Y);
            var placedRect = (Rectangle)item.Transform(originCS, newCS);

            // place rectangle and update
            this.PackedItems.Add(placedRect);
            this.PackedIndices.Add(itemIndex);
            this.FreeRectangles.Remove(freeRect);

            // update remaining free space
            this.SplitFreeRectangle(freeRect, placedRect);

            List <double> itemBounds = RectBounds(placedRect);

            this.RemoveOverlaps(itemBounds);

            // Dispose Dynamo geometry
            newCS.Dispose();
            originCS.Dispose();

            return(true);
        }