Exemple #1
0
        public void Insert(List <LORect> rects, List <LORect> dst, FreeRectChoiceHeuristic method)
        {
            dst.Clear();

            while (rects.Count > 0)
            {
                int    bestScore1    = int.MaxValue;
                int    bestScore2    = int.MaxValue;
                int    bestRectIndex = -1;
                LORect bestNode      = new LORect();

                for (int i = 0; i < rects.Count; ++i)
                {
                    int    score1  = 0;
                    int    score2  = 0;
                    LORect newNode = ScoreRect((int)rects[i].width, (int)rects[i].height, method, ref score1, ref score2);

                    if (score1 < bestScore1 || (score1 == bestScore1 && score2 < bestScore2))
                    {
                        bestScore1    = score1;
                        bestScore2    = score2;
                        bestNode      = newNode;
                        bestRectIndex = i;
                    }
                }

                if (bestRectIndex == -1)
                {
                    return;
                }

                PlaceRect(bestNode);
                rects.RemoveAt(bestRectIndex);
            }
        }
        LORect FindPositionForNewNodeBestAreaFit(int width, int height, ref int bestAreaFit, ref int bestShortSideFit)
        {
            LORect bestNode = new LORect();

            bestAreaFit = int.MaxValue;

            for (int i = 0; i < freeRectangles.Count; ++i)
            {
                int areaFit = (int)freeRectangles[i].width * (int)freeRectangles[i].height - width * height;

                // Try to place the rectangle in upright (non-flipped) orientation.
                if (freeRectangles[i].width >= width && freeRectangles[i].height >= height)
                {
                    int leftoverHoriz = Mathf.Abs((int)freeRectangles[i].width - width);
                    int leftoverVert  = Mathf.Abs((int)freeRectangles[i].height - height);
                    int shortSideFit  = Mathf.Min(leftoverHoriz, leftoverVert);

                    if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit))
                    {
                        bestNode.x       = freeRectangles[i].x;
                        bestNode.y       = freeRectangles[i].y;
                        bestNode.width   = width;
                        bestNode.height  = height;
                        bestShortSideFit = shortSideFit;
                        bestAreaFit      = areaFit;
                    }
                }
            }
            return(bestNode);
        }
        LORect FindPositionForNewNodeBottomLeft(int width, int height, ref int bestY, ref int bestX)
        {
            LORect bestNode = new LORect();

            bestY = int.MaxValue;

            for (int i = 0; i < freeRectangles.Count; ++i)
            {
                // Try to place the rectangle in upright (non-flipped) orientation.
                if (freeRectangles[i].width >= width && freeRectangles[i].height >= height)
                {
                    int topSideY = (int)freeRectangles[i].y + height;
                    if (topSideY < bestY || (topSideY == bestY && freeRectangles[i].x < bestX))
                    {
                        bestNode.x      = freeRectangles[i].x;
                        bestNode.y      = freeRectangles[i].y;
                        bestNode.width  = width;
                        bestNode.height = height;
                        bestY           = topSideY;
                        bestX           = (int)freeRectangles[i].x;
                    }
                }
            }
            return(bestNode);
        }
        LORect ScoreRect(int width, int height, FreeRectChoiceHeuristic method, ref int score1, ref int score2)
        {
            LORect newNode = new LORect();

            score1 = int.MaxValue;
            score2 = int.MaxValue;
            switch (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);
                score1 = -score1;                 // Reverse since we are minimizing, but for contact point score bigger is better.
                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;
            }

            // Cannot fit the current rectangle.
            if (newNode.height == 0)
            {
                score1 = int.MaxValue;
                score2 = int.MaxValue;
            }

            return(newNode);
        }
Exemple #5
0
 bool Intersects(LORect r1, LORect r2)
 {
     return(!(
                r2.x >= r1.x + r1.width ||
                r2.x + r2.width <= r1.x ||
                r2.y + r2.height <= r1.y ||
                r2.y >= r1.y + r1.height
                ));
 }
Exemple #6
0
        bool SplitFreeNode(LORect freeNode, ref LORect usedNode)
        {
            // Test with SAT if the rectangles even intersect.
            if (usedNode.x >= freeNode.x + freeNode.width || usedNode.x + usedNode.width <= freeNode.x ||
                usedNode.y >= freeNode.y + freeNode.height || usedNode.y + usedNode.height <= freeNode.y)
            {
                return(false);
            }

            if (usedNode.x < freeNode.x + freeNode.width && usedNode.x + usedNode.width > freeNode.x)
            {
                // New node at the top side of the used node.
                if (usedNode.y > freeNode.y && usedNode.y < freeNode.y + freeNode.height)
                {
                    LORect newNode = freeNode;
                    newNode.height = usedNode.y - newNode.y;
                    freeRectangles.Add(newNode);
                }

                // New node at the bottom side of the used node.
                if (usedNode.y + usedNode.height < freeNode.y + freeNode.height)
                {
                    LORect newNode = freeNode;
                    newNode.y      = usedNode.y + usedNode.height;
                    newNode.height = freeNode.y + freeNode.height - (usedNode.y + usedNode.height);
                    freeRectangles.Add(newNode);
                }
            }

            if (usedNode.y < freeNode.y + freeNode.height && usedNode.y + usedNode.height > freeNode.y)
            {
                // New node at the left side of the used node.
                if (usedNode.x > freeNode.x && usedNode.x < freeNode.x + freeNode.width)
                {
                    LORect newNode = freeNode;
                    newNode.width = usedNode.x - newNode.x;
                    freeRectangles.Add(newNode);
                }

                // New node at the right side of the used node.
                if (usedNode.x + usedNode.width < freeNode.x + freeNode.width)
                {
                    LORect newNode = freeNode;
                    newNode.x     = usedNode.x + usedNode.width;
                    newNode.width = freeNode.x + freeNode.width - (usedNode.x + usedNode.width);
                    freeRectangles.Add(newNode);
                }
            }

            return(true);
        }
Exemple #7
0
        public void Init(int width, int height, bool rotations = true)
        {
            binWidth  = width;
            binHeight = height;

            LORect n = new LORect();

            n.x      = 0;
            n.y      = 0;
            n.width  = width;
            n.height = height;

            usedRectangles.Clear();

            freeRectangles.Clear();
            freeRectangles.Add(n);
        }
Exemple #8
0
        public bool Insert(int width, int height, FreeRectChoiceHeuristic method, RectTransform rt, out LORect packedRect)
        {
            LORect newNode = new LORect();
            int    score1  = 0;         // Unused in this function. We don't need to know the score after finding the position.
            int    score2  = 0;

            switch (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;
            }

            newNode.rectTransform = rt;

            if (newNode.height == 0)
            {
                packedRect = newNode;
                return(false);
            }

            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);
            packedRect = newNode;
            return(true);
        }
Exemple #9
0
        void PlaceRect(LORect 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);
        }
Exemple #10
0
        LORect FindPositionForNewNodeContactPoint(int width, int height, ref int bestContactScore)
        {
            LORect bestNode = new LORect();

            bestContactScore = -1;

            for (int i = 0; i < freeRectangles.Count; ++i)
            {
                // Try to place the rectangle in upright (non-flipped) orientation.
                if (freeRectangles[i].width >= width && freeRectangles[i].height >= height)
                {
                    int score = ContactPointScoreNode((int)freeRectangles[i].x, (int)freeRectangles[i].y, width, height);
                    if (score > bestContactScore)
                    {
                        bestNode.x       = (int)freeRectangles[i].x;
                        bestNode.y       = (int)freeRectangles[i].y;
                        bestNode.width   = width;
                        bestNode.height  = height;
                        bestContactScore = score;
                    }
                }
            }
            return(bestNode);
        }
Exemple #11
0
        public void ExpandRectsToFill(float w, float h)
        {
            // Run through all rects; make them the full width
            // find any other intersecting rects, mind our min X and max X
            for (int i = 0; i < usedRectangles.Count; i++)
            {
                LORect a = usedRectangles [i];

                float centerX = a.x + a.width * 0.5f;
                float minX    = 0;
                float maxX    = w;

                a.x     = 0;
                a.width = w;

                for (int j = 0; j < usedRectangles.Count; j++)
                {
                    if (i == j)
                    {
                        continue;
                    }

                    LORect b = usedRectangles [j];

                    if (Intersects(a, b))
                    {
                        // find a left edge which is > centerX && < maxX
                        if (b.x > centerX && b.x < maxX)
                        {
                            maxX = b.x;
                        }

                        // find a right edge which is < centerX && > minX
                        if ((b.x + b.width) < centerX && (b.x + b.width) > minX)
                        {
                            minX = (b.x + b.width);
                        }
                    }
                }

                a.x     = minX;
                a.width = maxX - minX;
                a.rectTransform.sizeDelta = new Vector2(a.width, a.rectTransform.sizeDelta.y);

                usedRectangles [i] = a;
            }


            // Same thing as above, but do it for the Y axis
            for (int i = 0; i < usedRectangles.Count; i++)
            {
                LORect a = usedRectangles [i];

                float centerY = a.y + a.height * 0.5f;
                float minY    = 0;
                float maxY    = h;

                a.y      = 0;
                a.height = h;

                for (int j = 0; j < usedRectangles.Count; j++)
                {
                    if (i == j)
                    {
                        continue;
                    }

                    LORect b = usedRectangles [j];

                    if (Intersects(a, b))
                    {
                        // find a top edge which is > centerY && < maxY
                        if (b.y > centerY && b.y < maxY)
                        {
                            maxY = b.y;
                        }

                        // find a bottom edge which is < centerY && > minY
                        if ((b.y + b.height) < centerY && (b.y + b.height) > minY)
                        {
                            minY = (b.y + b.height);
                        }
                    }
                }

                a.y      = minY;
                a.height = maxY - minY;
                a.rectTransform.sizeDelta = new Vector2(a.rectTransform.sizeDelta.x, a.height);

                usedRectangles [i] = a;
            }
        }
Exemple #12
0
 bool IsContainedIn(LORect a, LORect b)
 {
     return(a.x >= b.x && a.y >= b.y &&
            a.x + a.width <= b.x + b.width &&
            a.y + a.height <= b.y + b.height);
 }