Beispiel #1
0
 /// <summary>
 /// Split the free area into freeRectangles
 /// </summary>
 /// <param name="fRect"></param>
 /// <param name="item"></param>
 private static void SplitFreeRectangle(
     FreeRectangle fRect,
     Rectangle item)
 {
     if (item.Width < fRect.width)
     {
         double fW = fRect.width - item.Width;
         double fH = fRect.height;
         double fX = fRect.xPos + item.Width;
         double fY = fRect.yPos;
         freeRectangles.Add(new FreeRectangle
         {
             width  = fW,
             height = fH,
             xPos   = fX,
             yPos   = fY
         });
     }
     if (item.Height < fRect.height)
     {
         double fW = fRect.width;
         double fH = fRect.height - item.Height;
         double fX = fRect.xPos;
         double fY = fRect.yPos + item.Height;
         freeRectangles.Add(new FreeRectangle
         {
             width  = fW,
             height = fH,
             xPos   = fX,
             yPos   = fY
         });
     }
 }
Beispiel #2
0
        /// <summary>
        /// Find best freerectangle and place next rectangle
        /// </summary>
        /// <param name="item"></param>
        /// <param name="placementMethod"></param>
        /// <param name="idx"></param>
        private static void PlaceItem(
            Rectangle item,
            PlacementMethods placementMethod,
            int idx)
        {
            FreeRectangle f = BestFreeRect(item, placementMethod);

            if (f != null)
            {
                if (f.rotate)
                {
                    item = Rotate(item);
                }
                CoordinateSystem newCS      = CoordinateSystem.ByOrigin(f.xPos, f.yPos);
                CoordinateSystem originCS   = CoordinateSystem.ByOrigin(item.StartPoint.X - item.Width, item.StartPoint.Y);
                Rectangle        placedRect = (Rectangle)item.Transform(originCS, newCS);
                packedRectangles.Add(placedRect);
                SplitFreeRectangle(f, placedRect);
                packedIndices.Add(idx);
                freeRectangles.Remove(f);

                List <double> itemBounds = RectBounds(placedRect);
                RemoveOverlaps(itemBounds);

                // Dispose Dynamo geometry
                newCS.Dispose();
                originCS.Dispose();
            }
            else
            {
                remainRectangles.Add(item);
            }
        }
Beispiel #3
0
 /// <summary>
 /// Split the free area into free rectangles
 /// </summary>
 /// <param name="fRect"></param>
 /// <param name="item"></param>
 private void SplitFreeRectangle(
     FreeRectangle fRect,
     Rectangle item)
 {
     if (item.Width < fRect.width)
     {
         var fW = fRect.width - item.Width;
         var fH = fRect.height;
         var fX = fRect.xPos + item.Width;
         var fY = fRect.yPos;
         this.FreeRectangles.Add(new FreeRectangle
         {
             width  = fW,
             height = fH,
             xPos   = fX,
             yPos   = fY
         });
     }
     if (item.Height < fRect.height)
     {
         var fW = fRect.width;
         var fH = fRect.height - item.Height;
         var fX = fRect.xPos;
         var fY = fRect.yPos + item.Height;
         this.FreeRectangles.Add(new FreeRectangle
         {
             width  = fW,
             height = fH,
             xPos   = fX,
             yPos   = fY
         });
     }
 }
Beispiel #4
0
        /// <summary>
        /// Scoring Method for Best Area Fits
        /// </summary>
        /// <param name="f"></param>
        /// <param name="item"></param>
        /// <returns>Score of Best Area Fits</returns>
        private static double BAF_Score(
            FreeRectangle f,
            Rectangle item)
        {
            double freeFArea = f.area();
            double rectArea  = item.Width * item.Height;

            return(freeFArea - rectArea);
        }
Beispiel #5
0
 /// <summary>
 /// Checks if the rectangle fits in the freeRectangle
 /// </summary>
 /// <param name="f"></param>
 /// <param name="rectangle"></param>
 /// <param name="rotate"></param>
 /// <returns>boolean</returns>
 private static bool ItemFits(
     FreeRectangle f,
     Rectangle rectangle,
     bool rotate)
 {
     if (rotate == false && rectangle.Width <= f.width && rectangle.Height <= f.height)
     {
         return(true);
     }
     if (rotate == true && rectangle.Height <= f.width && rectangle.Width <= f.height)
     {
         return(true);
     }
     return(false);
 }
Beispiel #6
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);
 }
Beispiel #7
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);
        }
Beispiel #8
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);
        }
Beispiel #9
0
        /// <summary>
        /// Scoring Method for Best Long Side Fits
        /// </summary>
        /// <param name="f"></param>
        /// <param name="item"></param>
        /// <returns>Score of Best Long Side Fits</returns>
        private static double BLSF_Score(
            FreeRectangle f,
            Rectangle item)
        {
            double widthDifference;
            double heightDifference;

            if (f.rotate)
            {
                widthDifference  = f.width - item.Height;
                heightDifference = f.height - item.Width;
            }
            else
            {
                widthDifference  = f.width - item.Width;
                heightDifference = f.height - item.Height;
            }

            return(new List <double> {
                widthDifference, heightDifference
            }.Max());
        }
Beispiel #10
0
        /// <summary>
        /// Checks if two rectangles overlaps
        /// https://www.geeksforgeeks.org/find-two-rectangles-overlap/
        /// </summary>
        /// <param name="f1"></param>
        /// <param name="rectBounds"></param>
        /// <returns>boolean</returns>
        private static bool RectangleOverlaps(
            FreeRectangle f1,
            List <double> rectBounds)
        {
            double f1BottomLeftX = f1.xPos;
            double f1BottomLeftY = f1.yPos;
            double f1TopRightX   = f1.xPos + f1.width;
            double f1TopRightY   = f1.yPos + f1.height;

            // If one rectangle is on left side of other
            if (f1TopRightY <= rectBounds[1] || f1BottomLeftY >= rectBounds[3])
            {
                return(false);
            }

            // If one rectangle is above other
            if (f1TopRightX <= rectBounds[0] || f1BottomLeftX >= rectBounds[2])
            {
                return(false);
            }

            return(true);
        }
Beispiel #11
0
        /// <summary>
        /// check if FreeRectangle is fully incapsulated in another
        /// </summary>
        /// <param name="f1"></param>
        /// <param name="f2"></param>
        /// <returns>boolean</returns>
        private static bool IsEncapsulated(
            FreeRectangle f1,
            FreeRectangle f2)
        {
            int precsion = 2;

            if (Math.Round(f2.xPos, precsion) < Math.Round(f1.xPos, precsion) || Math.Round(f2.xPos, precsion) > Math.Round(f1.xPos + f1.width, precsion))
            {
                return(false);
            }
            if (Math.Round((f2.xPos + f2.width), precsion) > Math.Round((f1.xPos + f1.width), precsion))
            {
                return(false);
            }
            if (Math.Round(f2.yPos, precsion) < Math.Round(f1.yPos, precsion) || Math.Round(f2.yPos, precsion) > Math.Round((f1.yPos + f1.height), precsion))
            {
                return(false);
            }
            if (Math.Round((f2.yPos + f2.height), precsion) > Math.Round((f1.yPos + f1.height), precsion))
            {
                return(false);
            }
            return(true);
        }
Beispiel #12
0
        /// <summary>
        /// Get the min/max points of the overlap BoundingBox
        /// </summary>
        /// <param name="f1"></param>
        /// <param name="rectBounds"></param>
        /// <returns>overlapping boundary</returns>
        private static List <double> OverlapBound(
            FreeRectangle f1,
            List <double> rectBounds)
        {
            // return bottom left x,y and top left x,y

            double x1 = f1.xPos;
            double y1 = f1.yPos;
            double x2 = f1.xPos + f1.width;
            double y2 = f1.yPos + f1.height;
            double x3 = rectBounds[0];
            double y3 = rectBounds[1];
            double x4 = rectBounds[2];
            double y4 = rectBounds[3];

            double overlapBotLeftX  = x1 > x3 ? x1 : x3;
            double overlapBotLeftY  = y1 > y3 ? y1 : y3;
            double overlapTopRightX = x2 < x4 ? x2 : x4;
            double overlapTopRightY = y2 < y4 ? y2 : y4;

            return(new List <double> {
                overlapBotLeftX, overlapBotLeftY, overlapTopRightX, overlapTopRightY
            });
        }
Beispiel #13
0
        /// <summary>
        /// Clip overlap of overlapping free areas
        /// </summary>
        /// <param name="f1"></param>
        /// <param name="overlapBound"></param>
        /// <returns>free rectangles after clipping the overlap</returns>
        private static List <FreeRectangle> ClipOverlap(
            FreeRectangle f1,
            List <double> overlapBound)
        {
            double F1x = f1.xPos;
            double F1y = f1.yPos;

            // Bottom left x,y and top right x,y of overlap
            double overlapBotLeftX  = overlapBound[0];
            double overlapBotLeftY  = overlapBound[1];
            double overlapTopRightX = overlapBound[2];
            double overlapTopRightY = overlapBound[3];

            List <FreeRectangle> newFreeRects = new List <FreeRectangle>();

            // Left side
            if (overlapBotLeftX > F1x)
            {
                newFreeRects.Add(new FreeRectangle
                {
                    width  = overlapBotLeftX - F1x,
                    height = f1.height,
                    xPos   = F1x,
                    yPos   = F1y
                });
            }
            // Right side
            if (overlapTopRightX < F1x + f1.width)
            {
                newFreeRects.Add(new FreeRectangle
                {
                    width  = (F1x + f1.width) - overlapTopRightX,
                    height = f1.height,
                    xPos   = overlapTopRightX,
                    yPos   = F1y
                });
            }
            // Bottom Side
            if (overlapBotLeftY > F1y)
            {
                newFreeRects.Add(new FreeRectangle
                {
                    width  = f1.width,
                    height = overlapBotLeftY - F1y,
                    xPos   = F1x,
                    yPos   = F1y
                });
            }
            // Top Side
            if (overlapTopRightY < F1y + f1.height)
            {
                newFreeRects.Add(new FreeRectangle
                {
                    width  = f1.width,
                    height = (F1y + f1.height) - overlapTopRightY,
                    xPos   = F1x,
                    yPos   = overlapTopRightY
                });
            }
            return(newFreeRects);
        }
Beispiel #14
0
        /// <summary>
        /// Chooses the best free rectangle based on the placement method
        /// </summary>
        /// <param name="item"></param>
        /// <param name="placementMethod"></param>
        /// <returns>free rectangle with best score</returns>
        private static FreeRectangle BestFreeRect(
            Rectangle item,
            PlacementMethods placementMethod)
        {
            List <FreeRectangle> fRects = new List <FreeRectangle>();

            foreach (var fRect in freeRectangles)
            {
                FreeRectangle        chosenFreeRect;
                List <FreeRectangle> fitsItem = new List <FreeRectangle>();
                if (ItemFits(fRect, item, false))
                {
                    FreeRectangle newFree = new FreeRectangle
                    {
                        xPos   = fRect.xPos,
                        yPos   = fRect.yPos,
                        height = fRect.height,
                        width  = fRect.width,
                        rotate = false,
                    };
                    if (placementMethod == PlacementMethods.BestShortSideFits)
                    {
                        newFree.score = BSSF_Score(newFree, item);
                    }
                    else if (placementMethod == PlacementMethods.BestLongSideFits)
                    {
                        newFree.score = BLSF_Score(newFree, item);
                    }
                    else if (placementMethod == PlacementMethods.BestAreaFits)
                    {
                        newFree.score = BAF_Score(newFree, item);
                    }
                    fitsItem.Add(newFree);
                }
                if (ItemFits(fRect, item, true))
                {
                    FreeRectangle newFree = new FreeRectangle
                    {
                        xPos   = fRect.xPos,
                        yPos   = fRect.yPos,
                        height = fRect.height,
                        width  = fRect.width,
                        rotate = true,
                    };
                    if (placementMethod == PlacementMethods.BestShortSideFits)
                    {
                        newFree.score = BSSF_Score(newFree, item);
                    }
                    else if (placementMethod == PlacementMethods.BestLongSideFits)
                    {
                        newFree.score = BLSF_Score(newFree, item);
                    }
                    else if (placementMethod == PlacementMethods.BestAreaFits)
                    {
                        newFree.score = BAF_Score(newFree, item);
                    }
                    fitsItem.Add(newFree);
                }
                if (fitsItem.Count == 1)
                {
                    chosenFreeRect = fitsItem[0];
                    fRect.score    = chosenFreeRect.score;
                    fRect.rotate   = chosenFreeRect.rotate;
                    fRects.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;
                    fRects.Add(fRect);
                }
                else
                {
                    continue;
                }
            }
            if (fRects.Any())
            {
                // Choose free rect with smallest score
                return(fRects.Aggregate((f1, f2) => f1.score < f2.score ? f1 : f2));
            }
            else
            {
                return(null);
            }
        }