public void Insert(List <SDL.SDL_Rect> rects, FreeRectChoiceHeuristic method) { while (rects.Count > 0) { int bestScore1 = int.MaxValue; int bestScore2 = int.MaxValue; int bestRectIndex = -1; SDL.SDL_Rect bestNode = new SDL.SDL_Rect(); for (int i = 0; i < rects.Count; ++i) { int score1 = 0; int score2 = 0; SDL.SDL_Rect newNode = ScoreRect(rects[i].w, rects[i].h, 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); } }
/// Inserts the given list of rectangles in an offline/batch mode, possibly rotated. /// @param rects The list of rectangles to insert. This vector will be destroyed in the process. /// @param dst [out] This list will contain the packed rectangles. The indices will not correspond to that of rects. /// @param method The rectangle placement rule to use when packing. public bool Insert(List<RectSize> rects, FreeRectChoiceHeuristic method) { int numRects = rects.Count; while (rects.Count > 0) { int bestScore1 = Int32.MaxValue; int bestScore2 = Int32.MaxValue; int bestRectIndex = -1; Rect bestNode = null; for (int i = 0; i < rects.Count; ++i) { int score1 = 0; int score2 = 0; Rect newNode = ScoreRect(rects[i].width, 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 usedRectangles.Count == numRects; PlaceRect(bestNode); rects.RemoveAt(bestRectIndex); } return usedRectangles.Count == numRects; }
public void Insert(List<Rect> rects, List<Rect> dst, FreeRectChoiceHeuristic method) { dst.Clear(); while(rects.Count > 0) { int bestScore1 = int.MaxValue; int bestScore2 = int.MaxValue; int bestRectIndex = -1; Rect bestNode = new Rect(); for(int i = 0; i < rects.Count; ++i) { int score1 = 0; int score2 = 0; Rect 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); } }
public Rect Insert(int width, int height, FreeRectChoiceHeuristic method) { Rect newNode = new Rect(); 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; } 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; }
// 计算放置给定矩形的位置得分 Rect ScoreRect(int width, int height, FreeRectChoiceHeuristic method, ref int score1, ref int score2) { Rect newNode = null; score1 = Int32.MaxValue; score2 = Int32.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; //反转得到最小的值,但接触点得分越大越好 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) { score1 = Int32.MaxValue; score2 = Int32.MaxValue; } return(newNode); }
public void Insert(List <Rect> rects, List <Rect> dst, FreeRectChoiceHeuristic method) { dst.Clear(); while (rects.Count > 0) { int bestScore1 = int.MaxValue; int bestScore2 = int.MaxValue; int bestRectIndex = -1; Rect bestNode = new Rect(); for (int i = 0; i < rects.Count; ++i) { int score1 = 0; int score2 = 0; Rect 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); } }
public Rect Insert (int width, int height, FreeRectChoiceHeuristic method) { Rect newNode = new Rect(); 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; } 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; }
Rect ScoreRect(int width, int height, FreeRectChoiceHeuristic method, ref int score1, ref int score2) { Rect newNode = new Rect(); 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); }
/// 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); }
public void Insert( Rectangle rect, FreeRectChoiceHeuristic rectChoice, out int freeRectIndex) { // Find where to put the new rectangle FindPositionForNewRect(rect, rectChoice, out freeRectIndex); }
public MaxRectsBinPack(int width, int height, FreeRectChoiceHeuristic method, IComparer<Rect> comparer) { binWidth = width; binHeight = height; Method = method; var n = new Rect(0, 0, width, height); FreeBoxes.Add(n); this.comparer = comparer; }
/// <summary> /// 插入一个Node /// </summary> public IntRect Insert(int width, int height, FreeRectChoiceHeuristic freeRectChoiceHeuristic) { IntRect newNode = IntRect.zero; // Unused in this function. We don't need to know the score after finding the position. int score1 = int.MaxValue; int score2 = int.MaxValue; switch (freeRectChoiceHeuristic) { case FreeRectChoiceHeuristic.RectBestShortSideFit: newNode = FindPositionForNewNodeBestShortSideFit(width, height, ref score1, ref score2); break; case FreeRectChoiceHeuristic.RectBestLongSideFit: newNode = FindPositionForNewNodeBottomLeft(width, height, ref score1, ref score2); break; case FreeRectChoiceHeuristic.RectContactPointRule: newNode = FindPositionForNewNodeContactPoint(width, height, ref score1); break; case FreeRectChoiceHeuristic.RectBottomLeftRule: newNode = FindPositionForNewNodeBestLongSideFit(width, height, ref score1, ref score2); break; case FreeRectChoiceHeuristic.RectBestAreaFit: newNode = FindPositionForNewNodeBestAreaFit(width, height, ref score1, ref score2); break; } if (newNode.height == 0) { return(newNode); } int numRectanglesToProcess = mFreeRectRangles.Count; for (int i = 0; i < numRectanglesToProcess; ++i) { if (SplitFreeNode(mFreeRectRangles[i], newNode)) { mFreeRectRangles.RemoveAt(i); --i; --numRectanglesToProcess; } } PruneFreeList(); mUsedRectangles.Add(newNode); return(newNode); }
/// <summary> /// Returns list of positions for newly added rects. /// Element in returned array corresponds to the element on same position in input array. /// </summary> /// <param name="rects">Rects.</param> /// <param name="method">Method.</param> public List <Rect> Insert(List <Rect> rects, FreeRectChoiceHeuristic method) { if (rects == null || rects.Count == 0) { return(null); } List <Rect> sortedUsedRects = new List <Rect>(new Rect[rects.Count]); List <int> indexesInOriginalArray = new List <int>(); for (int i = 0; i < rects.Count; i++) { indexesInOriginalArray.Add(i); } while (rects.Count > 0) { int bestScore1 = int.MaxValue; int bestScore2 = int.MaxValue; int bestRectIndex = -1; Rect bestNode = new Rect(); for (int i = 0; i < rects.Count; ++i) { int score1 = 0; int score2 = 0; Rect 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(null); } PlaceRect(bestNode); rects.RemoveAt(bestRectIndex); int indexInOriginalArray = indexesInOriginalArray[bestRectIndex]; sortedUsedRects[indexInOriginalArray] = bestNode; indexesInOriginalArray.RemoveAt(bestRectIndex); } return(sortedUsedRects); }
// For online packing use only. // Not useful here. /* * public Rect Insert( int width, int height, FreeRectChoiceHeuristic method ) * { * Rect newNode = new Rect(); * 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; * } * * 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; * }*/ // Returns true if all rects have been inserted, false otherwise public bool Insert(Dictionary <int, Rect> a_rRectsDict, FreeRectChoiceHeuristic a_ePackingMethod) { int iRectCount = a_rRectsDict.Count; while (iRectCount > 0) { int iBestScore1 = int.MaxValue; int iBestScore2 = int.MaxValue; int iBestRectIndex = -1; bool bBestIsFlipped = false; Rect oBestNode = new Rect(); foreach (KeyValuePair <int, Rect> rIndexedRect in a_rRectsDict) { int iScore1 = 0; int iScore2 = 0; bool bIsFlipped = false; // Score padded rect // Get a new padded (and probably flipped) rect Rect newNode = ScoreRect((int)(rIndexedRect.Value.width + rectPadding), (int)(rIndexedRect.Value.height + rectPadding), a_ePackingMethod, ref iScore1, ref iScore2, ref bIsFlipped); if (iScore1 < iBestScore1 || (iScore1 == iBestScore1 && iScore2 < iBestScore2)) { iBestScore1 = iScore1; iBestScore2 = iScore2; oBestNode = newNode; iBestRectIndex = rIndexedRect.Key; bBestIsFlipped = bIsFlipped; } } if (iBestRectIndex == -1) { return(false); } PlaceRect(iBestRectIndex, oBestNode, bBestIsFlipped); a_rRectsDict.Remove(iBestRectIndex); --iRectCount; } return(true); // iRectCount = 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); }
private static decimal ScoreByHeuristic( Rectangle rect, Rectangle freeRect, FreeRectChoiceHeuristic rectChoice) { switch (rectChoice) { case FreeRectChoiceHeuristic.RectBestAreaFit: return(ScoreBestAreaFit(rect, freeRect)); case FreeRectChoiceHeuristic.RectBestShortSideFit: return(ScoreBestShortSideFit(rect, freeRect)); default: throw new NotSupportedException($"rect choice is unsupported: {rectChoice}"); } }
public void Insert(List <ImRect> rects, List <ImRect> dst, FreeRectChoiceHeuristic method) { dst.Clear(); dst.AddRange(new ImRect[rects.Count]); var remaining = rects.Count; var completed = new bool[rects.Count]; while (remaining > 0) { int bestScore1 = int.MaxValue; int bestScore2 = int.MaxValue; int bestRectIndex = -1; ImRect bestNode = new ImRect(); for (int i = 0; i < rects.Count; ++i) { if (!completed[i]) { int score1 = 0; int score2 = 0; ImRect 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); completed[bestRectIndex] = true; dst[bestRectIndex] = bestNode; remaining--; //rects.RemoveAt(bestRectIndex); } }
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); }
/// <summary> /// For each rectangle, packs each one then chooses the best and packs that. Slow! /// </summary> public Page Pack(List <Rect> rects, FreeRectChoiceHeuristic method) { rects = new List <Rect>(rects); while (rects.Count > 0) { int bestRectIndex = -1; Rect bestNode = new Rect() { Score1 = int.MaxValue, Score2 = int.MaxValue, }; for (int i = 0; i < rects.Count; i++) { Rect newNode = ScoreRect(rects[i], method); if (newNode.Score1 < bestNode.Score1 || (newNode.Score1 == bestNode.Score1 && newNode.Score2 < bestNode.Score2)) { bestNode.Set(rects[i]); bestNode.Score1 = newNode.Score1; bestNode.Score2 = newNode.Score2; bestNode.X = newNode.X; bestNode.Y = newNode.Y; bestNode.Width = newNode.Width; bestNode.Height = newNode.Height; bestNode.Rotated = newNode.Rotated; bestRectIndex = i; } } if (bestRectIndex == -1) { break; } PlaceRect(bestNode); rects.RemoveAt(bestRectIndex); } Page result = GetResult(); result.RemainingRects = rects; return(result); }
static int ScoreByHeuristic(int width, int height, ref BinRect freeRect, FreeRectChoiceHeuristic rectChoice) { switch (rectChoice) { case FreeRectChoiceHeuristic.RectBestAreaFit: return(ScoreBestAreaFit(width, height, ref freeRect)); case FreeRectChoiceHeuristic.RectBestShortSideFit: return(ScoreBestShortSideFit(width, height, ref freeRect)); case FreeRectChoiceHeuristic.RectBestLongSideFit: return(ScoreBestLongSideFit(width, height, ref freeRect)); case FreeRectChoiceHeuristic.RectWorstAreaFit: return(ScoreWorstAreaFit(width, height, ref freeRect)); case FreeRectChoiceHeuristic.RectWorstShortSideFit: return(ScoreWorstShortSideFit(width, height, ref freeRect)); case FreeRectChoiceHeuristic.RectWorstLongSideFit: return(ScoreWorstLongSideFit(width, height, ref freeRect)); default: return(int.MaxValue); } }
private Rect Insert(int width, int height, FreeRectChoiceHeuristic method) { var newNode = new Rect(); var score1 = 0; var 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; } if (newNode.height == 0) { return(newNode); } var numRectanglesToProcess = freeRectangles.Count; for (var i = 0; i < numRectanglesToProcess; ++i) { if (SplitFreeNode(freeRectangles[i], ref newNode)) { freeRectangles.RemoveAt(i); --i; --numRectanglesToProcess; } } PruneFreeList(); usedRectangles.Add(newNode); return(newNode); }
private Rect ScoreRect(Rect rect, FreeRectChoiceHeuristic method) { int width = rect.Width; int height = rect.Height; int rotatedWidth = height - _outer._settings.PaddingY + _outer._settings.PaddingX; int rotatedHeight = width - _outer._settings.PaddingX + _outer._settings.PaddingY; bool rotate = rect.CanRotate && _outer._settings.Rotation; Rect newNode = null; switch (method) { case FreeRectChoiceHeuristic.BestShortSideFit: newNode = FindPositionForNewNodeBestShortSideFit(width, height, rotatedWidth, rotatedHeight, rotate); break; case FreeRectChoiceHeuristic.BottomLeftRule: newNode = FindPositionForNewNodeBottomLeft(width, height, rotatedWidth, rotatedHeight, rotate); break; case FreeRectChoiceHeuristic.ContactPointRule: newNode = FindPositionForNewNodeContactPoint(width, height, rotatedWidth, rotatedHeight, rotate); newNode.Score1 = -newNode.Score1; break; case FreeRectChoiceHeuristic.BestLongSideFit: newNode = FindPositionForNewNodeBestLongSideFit(width, height, rotatedWidth, rotatedHeight, rotate); break; case FreeRectChoiceHeuristic.BestAreaFit: newNode = FindPositionForNewNodeBestAreaFit(width, height, rotatedWidth, rotatedHeight, rotate); break; } if (newNode.Height == 0) { newNode.Score1 = int.MaxValue; newNode.Score2 = int.MaxValue; } return(newNode); }
public void Insert(Span <PackRect> rects, Span <PackRect> dst, FreeRectChoiceHeuristic method) { var remaining = rects.Length; var completed = new bool[rects.Length]; while (remaining > 0) { int bestScore1 = int.MaxValue; int bestScore2 = int.MaxValue; int bestRectIndex = -1; PackRect bestNode = new PackRect(); for (int i = 0; i < rects.Length; ++i) { if (!completed[i]) { int score1 = 0; int score2 = 0; PackRect 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); completed[bestRectIndex] = true; dst[bestRectIndex] = bestNode; remaining--; } }
public void Insert(List <IntRect> rects, List <IntRect> dst, FreeRectChoiceHeuristic freeRectChoiceHeuristic) { dst.Clear(); while (rects.Count > 0) { int bestScore1 = int.MaxValue; int bestScore2 = int.MaxValue; int bestRectIndex = -1; IntRect bestNode = IntRect.zero; for (int i = 0; i < rects.Count; ++i) { int score1 = int.MaxValue; int score2 = int.MaxValue; IntRect newNode = ScoreRect(rects[i].x, rects[i].y, freeRectChoiceHeuristic, ref score1, ref score2); if (score1 < bestScore1 || (score1 == bestScore1 && score2 < bestScore2)) { bestScore1 = score1; bestScore2 = score2; bestNode = newNode; bestRectIndex = i; } } if (bestRectIndex == -1 || bestNode == IntRect.zero) { return; } PlaceRect(bestNode); dst.Add(bestNode); rects.RemoveAt(bestRectIndex); } }
private Rect ScoreRect(int width, int height, FreeRectChoiceHeuristic method, ref int score1, ref int score2) { var newNode = new Rect(); 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; 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) { score1 = int.MaxValue; score2 = int.MaxValue; } return(newNode); }
/// <summary> /// IntRect的匹配度计算 /// </summary> private IntRect ScoreRect(int width, int height, FreeRectChoiceHeuristic freeRectChoiceHeuristic, ref int score1, ref int score2) { IntRect newNode = IntRect.zero; score1 = int.MaxValue; score2 = int.MaxValue; switch (freeRectChoiceHeuristic) { 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; } if (newNode.height == 0) { score1 = int.MaxValue; score2 = int.MaxValue; } return(newNode); }
/// <summary> /// Packs a single image. Order is defined externally. /// </summary> public Rect Insert(Rect rect, FreeRectChoiceHeuristic method) { Rect newNode = ScoreRect(rect, method); if (newNode.Height == 0) { return(null); } int numRectanglesToProcess = _freeRectangles.Count; for (int i = 0; i < numRectanglesToProcess; i++) { if (SplitFreeNode(_freeRectangles[i], newNode)) { _freeRectangles.RemoveAt(i); i--; numRectanglesToProcess--; } } PruneFreeList(); Rect bestNode = new Rect(); bestNode.Set(rect); bestNode.Score1 = newNode.Score1; bestNode.Score2 = newNode.Score2; bestNode.X = newNode.X; bestNode.Y = newNode.Y; bestNode.Width = newNode.Width; bestNode.Height = newNode.Height; bestNode.Rotated = newNode.Rotated; _usedRectangles.Add(bestNode); return(bestNode); }
/// Inserts the given list of rectangles in an offline/batch mode, possibly rotated. /// @param rects The list of rectangles to insert. This vector will be destroyed in the process. /// @param dst [out] This list will contain the packed rectangles. The indices will not correspond to that of rects. /// @param method The rectangle placement rule to use when packing. public bool Insert(List <RectSize> rects, FreeRectChoiceHeuristic method) { int numRects = rects.Count; while (rects.Count > 0) { int bestScore1 = Int32.MaxValue; int bestScore2 = Int32.MaxValue; int bestRectIndex = -1; Rect bestNode = null; for (int i = 0; i < rects.Count; ++i) { int score1 = 0; int score2 = 0; Rect newNode = ScoreRect(rects[i].width, 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(usedRectangles.Count == numRects); } PlaceRect(bestNode); rects.RemoveAt(bestRectIndex); } return(usedRectangles.Count == numRects); }
/// 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); } }
public Rect Insert(Vector2 size, FreeRectChoiceHeuristic method) { return(Insert((int)size.x, (int)size.y, method)); }
/// Goes through the list of free rectangles and finds the best one to place a rectangle of given size into. /// Running time is Theta(|freeRectangles|). /// @param nodeIndex [out] The index of the free rectangle in the freeRectangles array into which the new /// rect was placed. /// @return A Rect structure that represents the placement of the new rect into the best free rectangle. private Rect FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, ref int nodeIndex) { Rect bestNode = new Rect(); int bestScore = int.MaxValue; /// Try each free rectangle to find the best one for placement. for (int i = 0; i < freeRectangles.Count; ++i) { // If this is a perfect fit upright, choose it immediately. if (width == freeRectangles[i].Width && height == freeRectangles[i].Height) { bestNode.X = freeRectangles[i].X; bestNode.Y = freeRectangles[i].Y; bestNode.Width = width; bestNode.Height = height; nodeIndex = i; disjointRects.Disjoint(bestNode); break; } // If this is a perfect fit sideways, choose it. else if (height == freeRectangles[i].Width && width == freeRectangles[i].Height) { bestNode.X = freeRectangles[i].X; bestNode.Y = freeRectangles[i].Y; bestNode.Width = height; bestNode.Height = width; nodeIndex = i; disjointRects.Disjoint(bestNode); break; } // Does the rectangle fit upright? else if (width <= freeRectangles[i].Width && height <= freeRectangles[i].Height) { int score = ScoreByHeuristic(width, height, freeRectangles[i], rectChoice); if (score < bestScore) { bestNode.X = freeRectangles[i].X; bestNode.Y = freeRectangles[i].Y; bestNode.Width = width; bestNode.Height = height; bestScore = score; nodeIndex = i; disjointRects.Disjoint(bestNode); } } // Does the rectangle fit sideways? else if (height <= freeRectangles[i].Width && width <= freeRectangles[i].Height) { int score = ScoreByHeuristic(height, width, freeRectangles[i], rectChoice); if (score < bestScore) { bestNode.X = freeRectangles[i].X; bestNode.Y = freeRectangles[i].Y; bestNode.Width = height; bestNode.Height = width; bestScore = score; nodeIndex = i; disjointRects.Disjoint(bestNode); } } } return(bestNode); }
public static Rect[] PackTexturesSpec(Texture2D texture, Texture2D[] textures, int width, int height, int padding, int maxSize, FreeRectChoiceHeuristic heuristic) { if (width > maxSize && height > maxSize) return null; if (width > maxSize || height > maxSize) { int temp = width; width = height; height = temp; } // Force square by sizing up if (NGUISettings.forceSquareAtlas) { if (width > height) height = width; else if (height > width) width = height; } Storage[] storage; using (var bp = new UITexturePackerSpec(width, height, false)) { storage = new Storage[textures.Length]; for (int i = 0; i < textures.Length; i++) { Texture2D tex = textures[i]; if (!tex) continue; Rect rect = new Rect(); int xPadding = 1; int yPadding = 1; for (xPadding = 1; xPadding >= 0; --xPadding) { for (yPadding = 1; yPadding >= 0; --yPadding) { rect = bp.Insert(tex.width + (xPadding * padding), tex.height + (yPadding * padding), heuristic); if (rect.width > 0 && rect.height > 0) break; // After having no padding if it still doesn't fit -- increase texture size. else if (xPadding == 0 && yPadding == 0) { return PackTexturesSpec(texture, textures, width * (width <= height ? 2 : 1), height * (height < width ? 2 : 1), padding, maxSize, heuristic); } } if (rect.width > 0 && rect.height > 0) break; } storage[i] = new Storage(); storage[i].rect = rect; storage[i].paddingX = (xPadding != 0); storage[i].paddingY = (yPadding != 0); } } texture.Resize(width, height); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { texture.SetPixel(i, j, new Color()); } } // The returned rects Rect[] rects = new Rect[textures.Length]; for (int i = 0; i < textures.Length; i++) { Texture2D tex = textures[i]; if (!tex) continue; Rect rect = storage[i].rect; int xPadding = (storage[i].paddingX ? padding : 0); int yPadding = (storage[i].paddingY ? padding : 0); Color[] colors = tex.GetPixels(); // Would be used to rotate the texture if need be. if (rect.width != tex.width + xPadding) { Color[] newColors = tex.GetPixels(); for (int x = 0; x < rect.width; x++) { for (int y = 0; y < rect.height; y++) { int prevIndex = ((int)rect.height - (y + 1)) + x * (int)tex.width; newColors[x + y * (int)rect.width] = colors[prevIndex]; } } colors = newColors; } texture.SetPixels((int)rect.x, (int)rect.y, (int)rect.width - xPadding, (int)rect.height - yPadding, colors); rect.x /= width; rect.y /= height; rect.width = (rect.width - xPadding) / width; rect.height = (rect.height - yPadding) / height; rects[i] = rect; } texture.Apply(); return rects; }
private Rect ScoreRect(int width, int height, FreeRectChoiceHeuristic method, out int score1, out int score2) { Rect newNode = new Rect(); score1 = int.MaxValue; score2 = int.MaxValue; switch (method) { case FreeRectChoiceHeuristic.RectBestShortSideFit: newNode = FindPositionForNewNodeBestShortSideFit(width, height, ref score1, ref score2); 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 == null) { score1 = int.MaxValue; score2 = int.MaxValue; } return newNode; }
private void FindPositionForNewRect( Rectangle rect, FreeRectChoiceHeuristic rectChoice, out int freeRectIndex) { decimal width = rect.Width; decimal height = rect.Height; decimal bestScore = decimal.MaxValue; freeRectIndex = -1; // Try each free rectangle to find the best one for placement for (int index = 0; index < _freeRectangles.Count; ++index) { // If this is a perfect fit upright, choose it immediately. var freeRectangle = _freeRectangles[index]; if (width == freeRectangle.Width && height == freeRectangle.Height) { rect.IsPlaced = true; rect.X = freeRectangle.X; rect.Y = freeRectangle.Y; rect.Width = width; rect.Height = height; freeRectIndex = index; break; } // If this is a perfect fit sideways, choose it. else if (height == freeRectangle.Width && width == freeRectangle.Height) { rect.IsPlaced = true; rect.X = freeRectangle.X; rect.Y = freeRectangle.Y; rect.Width = height; rect.Height = width; freeRectIndex = index; break; } // Does the rectangle fit upright? if (width <= freeRectangle.Width && height <= freeRectangle.Height) { decimal score = ScoreByHeuristic(rect, freeRectangle, rectChoice); if (score < bestScore) { rect.IsPlaced = true; rect.X = freeRectangle.X; rect.Y = freeRectangle.Y; rect.Width = width; rect.Height = height; bestScore = score; freeRectIndex = index; } } // Does the rectangle fit sideways? if (height <= freeRectangle.Width && width <= freeRectangle.Height) { decimal score = ScoreByHeuristic(rect, freeRectangle, rectChoice); if (score < bestScore) { rect.IsPlaced = true; rect.X = freeRectangle.X; rect.Y = freeRectangle.Y; rect.Width = height; rect.Height = width; bestScore = score; freeRectIndex = index; } } } }
// For online packing use only. // Not useful here. /* public Rect Insert( int width, int height, FreeRectChoiceHeuristic method ) { Rect newNode = new Rect(); 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; } 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; }*/ // Returns true if all rects have been inserted, false otherwise public bool Insert( Dictionary<int,Rect> a_rRectsDict, FreeRectChoiceHeuristic a_ePackingMethod ) { int iRectCount = a_rRectsDict.Count; while( iRectCount > 0 ) { int iBestScore1 = int.MaxValue; int iBestScore2 = int.MaxValue; int iBestRectIndex = -1; bool bBestIsFlipped = false; Rect oBestNode = new Rect(); foreach( KeyValuePair<int,Rect> rIndexedRect in a_rRectsDict ) { int iScore1 = 0; int iScore2 = 0; bool bIsFlipped = false; // Score padded rect // Get a new padded (and probably flipped) rect Rect newNode = ScoreRect( (int) ( rIndexedRect.Value.width + rectPadding ), (int) ( rIndexedRect.Value.height + rectPadding ), a_ePackingMethod, ref iScore1, ref iScore2, ref bIsFlipped ); if( iScore1 < iBestScore1 || ( iScore1 == iBestScore1 && iScore2 < iBestScore2 ) ) { iBestScore1 = iScore1; iBestScore2 = iScore2; oBestNode = newNode; iBestRectIndex = rIndexedRect.Key; bBestIsFlipped = bIsFlipped; } } if( iBestRectIndex == -1 ) { return false; } PlaceRect( iBestRectIndex, oBestNode, bBestIsFlipped ); a_rRectsDict.Remove( iBestRectIndex ); --iRectCount; } return true; // iRectCount = 0 }
public static Rect[] PackTexturesSpec(Texture2D texture, Texture2D[] textures, int width, int height, int padding, int maxSize, FreeRectChoiceHeuristic heuristic) { if (width > maxSize && height > maxSize) { return(null); } if (width > maxSize || height > maxSize) { int temp = width; width = height; height = temp; } // Force square by sizing up if (NGUISettings.forceSquareAtlas) { if (width > height) { height = width; } else if (height > width) { width = height; } } Storage[] storage; using (var bp = new UITexturePackerSpec(width, height, false)) { storage = new Storage[textures.Length]; for (int i = 0; i < textures.Length; i++) { Texture2D tex = textures[i]; if (!tex) { continue; } Rect rect = new Rect(); int xPadding = 1; int yPadding = 1; for (xPadding = 1; xPadding >= 0; --xPadding) { for (yPadding = 1; yPadding >= 0; --yPadding) { rect = bp.Insert(tex.width + (xPadding * padding), tex.height + (yPadding * padding), heuristic); if (rect.width > 0 && rect.height > 0) { break; } // After having no padding if it still doesn't fit -- increase texture size. else if (xPadding == 0 && yPadding == 0) { return(PackTexturesSpec(texture, textures, width * (width <= height ? 2 : 1), height * (height < width ? 2 : 1), padding, maxSize, heuristic)); } } if (rect.width > 0 && rect.height > 0) { break; } } storage[i] = new Storage(); storage[i].rect = rect; storage[i].paddingX = (xPadding != 0); storage[i].paddingY = (yPadding != 0); } } texture.Resize(width, height); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { texture.SetPixel(i, j, new Color()); } } // The returned rects Rect[] rects = new Rect[textures.Length]; for (int i = 0; i < textures.Length; i++) { Texture2D tex = textures[i]; if (!tex) { continue; } Rect rect = storage[i].rect; int xPadding = (storage[i].paddingX ? padding : 0); int yPadding = (storage[i].paddingY ? padding : 0); Color[] colors = tex.GetPixels(); // Would be used to rotate the texture if need be. if (rect.width != tex.width + xPadding) { Color[] newColors = tex.GetPixels(); for (int x = 0; x < rect.width; x++) { for (int y = 0; y < rect.height; y++) { int prevIndex = ((int)rect.height - (y + 1)) + x * (int)tex.width; newColors[x + y * (int)rect.width] = colors[prevIndex]; } } colors = newColors; } texture.SetPixels((int)rect.x, (int)rect.y, (int)rect.width - xPadding, (int)rect.height - yPadding, colors); rect.x /= width; rect.y /= height; rect.width = (rect.width - xPadding) / width; rect.height = (rect.height - yPadding) / height; rects[i] = rect; } texture.Apply(); return(rects); }
Rect ScoreRect(int width, int height, FreeRectChoiceHeuristic method, ref int score1, ref int score2) { Rect newNode = new Rect(); 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; }
/// Goes through the list of free rectangles and finds the best one to place a rectangle of given size into. /// Running time is Theta(|freeRectangles|). /// @param nodeIndex [out] The index of the free rectangle in the freeRectangles array into which the new /// rect was placed. /// @return A Rect structure that represents the placement of the new rect into the best free rectangle. public BinRect FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, ref int nodeIndex) { BinRect bestNode = new BinRect(); int bestScore = int.MaxValue; /// Try each free rectangle to find the best one for placement. for (int i = 0; i < freeRectangles.Count; ++i) { // If this is a perfect fit upright, choose it immediately. if (width == freeRectangles[i].width && height == freeRectangles[i].height) { bestNode.x = freeRectangles[i].x; bestNode.y = freeRectangles[i].y; bestNode.width = width; bestNode.height = height; bestScore = int.MinValue; break; } // If this is a perfect fit sideways, choose it. else if (height == freeRectangles[i].width && width == freeRectangles[i].height) { bestNode.x = freeRectangles[i].x; bestNode.y = freeRectangles[i].y; bestNode.width = height; bestNode.height = width; bestScore = int.MinValue; break; } // Does the rectangle fit upright? else if (width <= freeRectangles[i].width && height <= freeRectangles[i].height) { var item = freeRectangles[i]; int score = ScoreByHeuristic(width, height, ref item, rectChoice); freeRectangles[i] = item; if (score < bestScore) { bestNode.x = freeRectangles[i].x; bestNode.y = freeRectangles[i].y; bestNode.width = width; bestNode.height = height; bestScore = score; } } // Does the rectangle fit sideways? else if (height <= freeRectangles[i].width && width <= freeRectangles[i].height) { var item = freeRectangles[i]; int score = ScoreByHeuristic(width, height, ref item, rectChoice); freeRectangles[i] = item; if (score < bestScore) { bestNode.x = freeRectangles[i].x; bestNode.y = freeRectangles[i].y; bestNode.width = height; bestNode.height = width; bestScore = score; } } } return(bestNode); }