ImRect ScoreRect(int width, int height, FreeRectChoiceHeuristic method, ref int score1, ref int score2) { ImRect newNode = new ImRect(); 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); }
bool SplitFreeNode(ImRect freeNode, ref ImRect 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) { ImRect 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) { ImRect 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) { ImRect 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) { ImRect newNode = freeNode; newNode.x = usedNode.x + usedNode.width; newNode.width = freeNode.x + freeNode.width - (usedNode.x + usedNode.width); freeRectangles.Add(newNode); } } return(true); }
ImRect FindPositionForNewNodeBestAreaFit(int width, int height, ref int bestAreaFit, ref int bestShortSideFit) { ImRect bestNode = new ImRect(); //memset(&bestNode, 0, sizeof(ImRect)); 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 = Math.Abs((int)freeRectangles[i].width - width); int leftoverVert = Math.Abs((int)freeRectangles[i].height - height); int shortSideFit = Math.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; } } if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width) { int leftoverHoriz = Math.Abs((int)freeRectangles[i].width - height); int leftoverVert = Math.Abs((int)freeRectangles[i].height - width); int shortSideFit = Math.Min(leftoverHoriz, leftoverVert); if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit)) { bestNode.x = freeRectangles[i].x; bestNode.y = freeRectangles[i].y; bestNode.width = height; bestNode.height = width; bestShortSideFit = shortSideFit; bestAreaFit = areaFit; } } } return(bestNode); }
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 void Init(int width, int height, bool rotations = true) { binWidth = width; binHeight = height; allowRotations = rotations; ImRect n = new ImRect(); n.x = 0; n.y = 0; n.width = width; n.height = height; usedRectangles.Clear(); freeRectangles.Clear(); freeRectangles.Add(n); }
void PlaceRect(ImRect 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); }
public void Clip(ImRect clip) { if (Min.x < clip.Min.x) { Min.x = clip.Min.x; } if (Min.y < clip.Min.y) { Min.y = clip.Min.y; } if (Max.x > clip.Max.x) { Max.x = clip.Max.x; } if (Max.y > clip.Max.y) { Max.y = clip.Max.y; } }
public void Add(ImRect rhs) { if (Min.x > rhs.Min.x) { Min.x = rhs.Min.x; } if (Min.y > rhs.Min.y) { Min.y = rhs.Min.y; } if (Max.x < rhs.Max.x) { Max.x = rhs.Max.x; } if (Max.y < rhs.Max.y) { Max.y = rhs.Max.y; } }
public ImRect Insert(int width, int height, FreeRectChoiceHeuristic method) { ImRect newNode = new ImRect(); 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); }
ImRect FindPositionForNewNodeBottomLeft(int width, int height, ref int bestY, ref int bestX) { ImRect bestNode = new ImRect(); //memset(bestNode, 0, sizeof(ImRect)); 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; } } if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width) { int topSideY = (int)freeRectangles[i].y + width; if (topSideY < bestY || (topSideY == bestY && freeRectangles[i].x < bestX)) { bestNode.x = freeRectangles[i].x; bestNode.y = freeRectangles[i].y; bestNode.width = height; bestNode.height = width; bestY = topSideY; bestX = (int)freeRectangles[i].x; } } } return(bestNode); }
ImRect FindPositionForNewNodeContactPoint(int width, int height, ref int bestContactScore) { ImRect bestNode = new ImRect(); //memset(&bestNode, 0, sizeof(ImRect)); 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; } } if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width) { int score = ContactPointScoreNode((int)freeRectangles[i].x, (int)freeRectangles[i].y, height, width); if (score > bestContactScore) { bestNode.x = (int)freeRectangles[i].x; bestNode.y = (int)freeRectangles[i].y; bestNode.width = height; bestNode.height = width; bestContactScore = score; } } } return(bestNode); }
bool IsContainedIn(ImRect a, ImRect 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); }
public bool Overlaps(ImRect r) { return(r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x); }
public bool Contains(ImRect r) { return(r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x < Max.x && r.Max.y < Max.y); }