/// <summary> /// Próbuje pierwsze puste pole z listy u¿ywaj¹c najmniejszych pokrywaj¹cych prostok¹tów /// </summary> /// <param name="container"></param> /// <param name="r"></param> private bool SimpleMend(RectangleContainer container, Rectangle r) { if (container == null || r == null) throw new ArgumentNullException(); Rectangle empty = container.EmptyFields[0]; if (empty == null) return false; if (empty.LongerSide > r.LongerSide || empty.ShorterSide > r.ShorterSide) return false; if (!empty.RectangleOrientation.Equals(r.RectangleOrientation)) r.Rotate(); Point nLT = new Point(empty.RightDown.X - r.SideA, empty.RightDown.Y - r.SideB); if (nLT.X >= 0 && nLT.Y >= 0) { r.Move(nLT); rects.RemoveRectangle(r); } container.InsertRectangle(r); return true; }
public Rectangle ComputeMaximumRectangle(List<Rectangle> rectanglesList) { if (rectanglesList == null) throw new ArgumentNullException(); if (rectanglesList.Count == 0) throw new ArgumentException("Empty rectangles list"); k = (int)(rectanglesList.Count * 0.75); RectangleContainer container = new RectangleContainer(); rects = new RectanglesList(rectanglesList); rectangle = rects.GetLargestRect(); container.InsertRectangle(rectangle, Rectangle.Orientation.Vertical); Rectangle bestWithShapeCondition = null; if(IsShapeConditionValid(rectangle.SideA, rectangle.SideB)) bestWithShapeCondition = rectangle; Rectangle w; while (!rects.IsEmpty() && running) { w = container.MaxCorrectRect; if (IsShapeConditionValid(w.SideA, w.SideB)) bestWithShapeCondition = w; Rectangle n = rects.GetLongestRect(w.LongerSide); if (n == null) break; bool simpleMendDone = false; bool addingToLeft = true; if (w.RectangleOrientation.Equals(Rectangle.Orientation.Vertical)) { n.Move(new Point(w.RightDown.X, 0)); if (!n.RectangleOrientation.Equals(w.RectangleOrientation)) n.Rotate(); } else { addingToLeft = false; if (!n.RectangleOrientation.Equals(w.RectangleOrientation)) n.Rotate(); n.Move(new Point(0, w.RightDown.Y)); } container.InsertRectangle(n); if (container.IsCorrectRectangle) continue; //k-ty krok to SimpleMend czyli proste zalepianie int pathWidth = n.ShorterSide; for (int i = 0; i < k - 1; i++) { Rectangle t = rects.PeekSmallestNotShorterThan(pathWidth); if (t == null) break; //jeœli jest wiêkszy ni¿ puste, przejdŸmy od razu do k-tego kroku zalepiania if (t.Area >= container.EmptyFieldsArea) { if (SimpleMend(container, t)) { simpleMendDone = true; break; } } //uwzgledniamy czy ostatnio dodany prostok¹t by³ doklejany z boku czy z dolu // z boku Point nLT; if (addingToLeft) { if (!t.RectangleOrientation.Equals(Rectangle.Orientation.Horizontal)) t.Rotate(); nLT = new Point(n.RightDown.X - t.SideA, n.RightDown.Y); } else { if (!t.RectangleOrientation.Equals(Rectangle.Orientation.Vertical)) t.Rotate(); nLT = new Point(n.RightDown.X, n.RightDown.Y - t.SideB); } if (nLT.X >= 0 && nLT.Y >= 0) { t.Move(nLT); container.InsertRectangle(t); rects.RemoveRectangle(t); n = t; } } if (!simpleMendDone) SimpleMend(container); if (!container.IsCorrectRectangle) break; } rectangle = container.MaxCorrectRect; if (!IsShapeConditionValid(rectangle.SideA, rectangle.SideB)) { //Console.WriteLine("Najlepsze znalezione rozwi¹zanie " + rectangle + " nie spe³nia warunku 2:1"); if (bestWithShapeCondition == null) { int bestIndex = -1, largestArea = 0; int i = 0; foreach (Rectangle rec in rectanglesList) { if (IsShapeConditionValid(rec.SideA, rec.SideB) && largestArea < rec.Area) { bestIndex = i; largestArea = rec.Area; } i++; } if (bestIndex > 0) bestWithShapeCondition = rectanglesList[bestIndex]; } rectangle = bestWithShapeCondition; //Console.WriteLine("Za rozwi¹zanie przyjmujê " + rectangle); } //rectangle = resultRectangle; return rectangle; }
/// <summary> /// Próbuje za³ataæ puste pola u¿ywaj¹c najmniejszych pokrywaj¹cych prostok¹tów /// </summary> /// <param name="container"></param> private void SimpleMend(RectangleContainer container) { List<Rectangle> cover = new List<Rectangle>(); foreach (Rectangle empty in container.EmptyFields) { Rectangle t = rects.PeekSmallestCovering(empty.SideA, empty.SideB); if (t != null) { if (!empty.RectangleOrientation.Equals(t.RectangleOrientation)) t.Rotate(); Point nLT = new Point(empty.RightDown.X - t.SideA, empty.RightDown.Y - t.SideB); if (nLT.X >= 0 && nLT.Y >= 0) { t.Move(nLT); rects.RemoveRectangle(t); } cover.Add(t); } } foreach (Rectangle r in cover) container.InsertRectangle(r); }
//Znajduje najwiekszy pojedynczy prostokat ktore spelnia warunki na ksztalt private Rectangle FindBiggestSingleRect(List<Rectangle> rects) { int index = -1; int maxArea = -1; Rectangle rectangle = null; for (int i = 0; i < rects.Count; ++i) { Rectangle rect = rects[i]; if (IsShapeConditionValid(rect.SideA, rect.SideB) && rect.Area > maxArea) { index = i; maxArea = rect.Area; } } if (index != -1) { RectangleContainer rc = new RectangleContainer(); rectangle = new Rectangle(rects[index].SideA, rects[index].SideB); rectangle.Number = rects[index].Number; rc.InsertRectangle(rectangle); rectangle = rc.MaxCorrectRect; } return rectangle; }
//glowna petla algorytmu public Rectangle ComputeMaximumRectangle(List<Rectangle> rects) { //znajdujemy maksymalne mozliwe pole prostokata int maxArea = ComputeMaximumArea(rects); bool onlySideChange = false; //na podstawie maxArea okreslamy jakie moga byc maksymalne boki wyjsciowego prostokata SetMaximumSides(maxArea); //znajdujemy maksymalny pojedynczy poprawny prostokat Rectangle bigestSingleRect = FindBiggestSingleRect(rects); //usuwamy te prostokaty ktore maja dluzsze boki niz te obliczone w SetMaximumSide List<Rectangle> correctRects = RemoveTooBigRectangles(rects); //znajdz prostokat o najwiekszym polu Rectangle startRect = FindRectangleWithMaxArea(correctRects); bool change = true; int currentSide = (startRect.LongerSide == startRect.SideA) ? startRect.SideA : startRect.SideB; Taio.Rectangle.Orientation orientation = (currentSide == startRect.SideA) ? Taio.Rectangle.Orientation.Horizontal : Taio.Rectangle.Orientation.Vertical; List<Rectangle> tempRectsList = new List<Rectangle>(); while (change && correctRects.Count > 0 && running) { change = false; //szukamy prostokata ktory bedzie najlepiej pasowal do juz istniejacych Rectangle tempRect = TryFindRectangleToThenNextStep(currentSide, correctRects, orientation); if (tempRect != null) { int currentSum = tempRect.LongerSide; tempRectsList.Add(tempRect); //probujemy utworzyc linie zlozonona z prostokatow ktora da sie dolaczyc do juz istniejacych //elemento bool foundLine = TryFillLine(currentSum, currentSide, tempRect, correctRects, tempRectsList, orientation); if (foundLine) { //probujemy dodac znaleziono linie i sprawdzamy czy powstaly prostokat spelnia warunki //na ksztalt Rectangle maxCorrect = AddFoundRectanglesToStartRect(tempRectsList, startRect, orientation); if (maxCorrect == null || !IsShapeConditionValid(maxCorrect.SideA, maxCorrect.SideB)) foreach (Rectangle r in tempRectsList) correctRects.Add(r); else { change = true; onlySideChange = false; startRect = maxCorrect; } } tempRectsList.Clear(); } if (!change && !onlySideChange) { change = true; onlySideChange = true; currentSide = (currentSide == startRect.SideA) ? startRect.SideB : startRect.SideA; orientation = (currentSide == startRect.SideA) ? Taio.Rectangle.Orientation.Horizontal : Taio.Rectangle.Orientation.Vertical; } } if (startRect.ContainedRectangles.Count == 0) { RectangleContainer rc = new RectangleContainer(); rc.InsertRectangle(startRect); startRect = rc.MaxCorrectRect; } if(IsShapeConditionValid(startRect.SideA, startRect.SideB)) rectangle = startRect; if (bigestSingleRect != null) if (bigestSingleRect.Area >= startRect.Area) rectangle = bigestSingleRect; return rectangle; }
//dodaje znaleziono linie prostokatow do istniejacego prostokata private static Rectangle AddFoundRectanglesToStartRect(List<Rectangle> foundRects, Rectangle startRect, Rectangle.Orientation orientation) { RectangleContainer rc = new RectangleContainer(); rc.InsertRectangle(startRect); int minHeight = FindMinHeight(foundRects, orientation); int offset = 0; int startVal = (orientation == Rectangle.Orientation.Horizontal) ? startRect.SideB : startRect.SideA; foreach (Rectangle r in foundRects) { if (orientation == Rectangle.Orientation.Horizontal) { if ((offset + r.SideA) > startRect.SideA) offset = startRect.SideA - r.SideA; if (startVal + minHeight - r.SideB < 0) return null; rc.InsertRectangle(r, new Point(offset, startVal + minHeight - r.SideB)); offset += r.SideA; } else { if ((offset + r.SideB) > startRect.SideB) offset = startRect.LongerSide - r.SideB; if (startVal + minHeight - r.SideA < 0) return null; rc.InsertRectangle(r, new Point(startVal + minHeight - r.SideA, offset)); offset += r.SideB; } } return rc.MaxCorrectRect; }
/// <summary> /// Metoda zwraca prostok�t o maksymalnym polu, spe�niaj�cy warunki zadania, /// zbudowany z listy prostok�t�w. /// </summary> /// <param name="rectangles">lista prostokat�w do budowy</param> /// <returns>maksymalny prostok�t</returns> private Rectangle maxCorrectRectangle(List<Rectangle> rectangles) { Rectangle result = null; RectangleContainer rc = new RectangleContainer(); correctRectangles(rectangles); foreach (Rectangle rect in rectangles) { rc.InsertRectangle(rect, rect.LeftTop); } result = rc.MaxCorrectRect; return result; }