public void MaxRectsFreeRectanglePostProcessorTestSingleIntersectionInCorner() { //Arrange var postProcessor = new MaxRectsFreeRectanglePostProcessor(); var freeRects = new List <PPRect>() { new PPRect(0, 0, 50, 50), new PPRect(50, 0, 100, 50) }; var rectJustPlaced = new PPRect(0, 0, 20, 20); //Act postProcessor.PostProcess(freeRects, rectJustPlaced); //Assert Assert.AreEqual(3, freeRects.Count); var sortedList = freeRects.OrderBy(x => x.Left).ThenBy(x => x.Top).ToList(); Assert.AreEqual(sortedList[0].Left, 0); Assert.AreEqual(sortedList[0].Top, 20); Assert.AreEqual(sortedList[0].Width, 50); Assert.AreEqual(sortedList[0].Height, 30); Assert.AreEqual(sortedList[1].Left, 20); Assert.AreEqual(sortedList[1].Top, 0); Assert.AreEqual(sortedList[1].Width, 30); Assert.AreEqual(sortedList[1].Height, 50); Assert.AreEqual(sortedList[2].Left, 50); Assert.AreEqual(sortedList[2].Top, 0); Assert.AreEqual(sortedList[2].Width, 50); Assert.AreEqual(sortedList[2].Height, 50); }
public void MaxRectsFreeRectangleSortedMergerTestMergeSimple() { //Arrange var freeRectangles = new List <PPRect>() { new PPRect(0, 0, 10, 12), new PPRect(0, 0, 10, 13), new PPRect(0, 0, 1000, 200) }; var merger = new MaxRectsFreeRectangleSortedMerger(); var freeRect1 = new PPRect(0, 0, 10, 14); var freeRect2 = new PPRect(0, 0, 1000, 201); var oldSize = freeRectangles.Count; //Act merger.MergeFreeRectangles(freeRectangles, new PPRect[] { freeRect1, freeRect2 }); //Assert Assert.AreEqual(oldSize + 2, freeRectangles.Count); Assert.AreEqual(10, freeRectangles[0].Width); Assert.AreEqual(12, freeRectangles[0].Height); Assert.AreEqual(10, freeRectangles[1].Width); Assert.AreEqual(13, freeRectangles[1].Height); Assert.AreEqual(10, freeRectangles[2].Width); Assert.AreEqual(14, freeRectangles[2].Height); Assert.AreEqual(1000, freeRectangles[3].Width); Assert.AreEqual(200, freeRectangles[3].Height); Assert.AreEqual(1000, freeRectangles[4].Width); Assert.AreEqual(201, freeRectangles[4].Height); }
/// <summary> /// Tries to improve (decrease its area) the current minimum bounding box /// </summary> /// <param name="currentRect"></param> /// <param name="possibleIntersections"></param> /// <param name="direction">0 for try to move up, 1 for try to move left</param> /// <returns></returns> private bool TryImprove(ref PPRect currentRect, IEnumerable <PPRect> possibleIntersections, int direction) { //adjust the improvemet to improve by higher steps (using bin search ?) bool ret = false; PPRect toTest = currentRect; if (direction == 0) { toTest.Top--; while (toTest.Top >= 0 && !Intersects(toTest, possibleIntersections)) { toTest.Top--; ret = true; } toTest.Top++; } else { toTest.Left--; while (toTest.Left >= 0 && !Intersects(toTest, possibleIntersections)) { toTest.Left--; ret = true; } toTest.Left++; } currentRect = toTest; if (ret) { TryImprove(ref currentRect, possibleIntersections, (direction + 1) % 2); } return(ret); }
public void BestAreaFitFreeRectangleExtractorTestFitMany() { //Arrange var rects = new List <PPRect>() { new PPRect(0, 0, 32, 16), new PPRect(0, 0, 66, 65), new PPRect(0, 0, 65, 65), new PPRect(0, 0, 65, 65), new PPRect(0, 0, 32, 160), new PPRect(0, 0, 320, 16), }; var currentRect = new PPRect(0, 0, 64, 65); var extractor = new BestAreaFitFreeRectangleExtractor(); //Act var result = extractor.ExtractFreeRectangle(rects, currentRect); //Assert Assert.AreNotEqual(null, result); Assert.AreEqual(65, result.Value.Width); Assert.AreEqual(65, result.Value.Height); Assert.AreEqual(0, result.Value.Left); Assert.AreEqual(0, result.Value.Top); }
public void BestAreaFitFreeRectangleExtractorTestFitMany2() { //Arrange var rects = new List <PPRect>() { new PPRect(7, 6, 7 + 32, 6 + 16), new PPRect(6, 1, 6 + 66, 1 + 65), new PPRect(14, 89, 14 + 65, 89 + 65), new PPRect(31, 124, 31 + 65, 124 + 65), new PPRect(89, 13, 89 + 32, 13 + 160), new PPRect(78, 500, 78 + 320, 500 + 16), }; var currentRect = new PPRect(0, 0, 64, 65); var extractor = new BestAreaFitFreeRectangleExtractor(); //Act var result = extractor.ExtractFreeRectangle(rects, currentRect); //Assert Assert.AreNotEqual(null, result); Assert.AreEqual(65, result.Value.Width); Assert.AreEqual(65, result.Value.Height); Assert.IsTrue(14 == result.Value.Left || result.Value.Left == 31); Assert.IsTrue(89 == result.Value.Top || result.Value.Left == 124); }
/// <summary> /// Performs a split of <paramref name="freeRectangle"/> by a vertical axis /// </summary> /// <param name="freeRectangle">The free rectangle that was selected for a placement of rectangle to be placed</param> /// <param name="justPlacedRect">The rectangle that was just placed into <paramref name="freeRectangle"/></param> /// <returns></returns> private IEnumerable <PPRect> SplitFreeRectangleVertical(ref PPRect freeRectangle, PPRect justPlacedRect) { int splitX = freeRectangle.Left + justPlacedRect.Width; PPRect freeRect1 = new PPRect(freeRectangle.Left, freeRectangle.Top + justPlacedRect.Height, splitX, freeRectangle.Bottom); PPRect freeRect2 = new PPRect(splitX, freeRectangle.Top, freeRectangle.Right, freeRectangle.Bottom); return(new PPRect[] { freeRect1, freeRect2 }.Where(x => x.Width > 0 && x.Height > 0)); }
public void BestAreaFitFreeRectangleExtractorTestNull() { //Arrange var extractor = new BestAreaFitFreeRectangleExtractor(); var currentRect = new PPRect(0, 0, 32, 32); //Act extractor.ExtractFreeRectangle(null, currentRect); }
/// <summary> /// Utility method for sorted (based on order given by <see cref="PPRectAreaComparer"/>) insertion /// </summary> /// <param name="list">List of rectangles</param> /// <param name="item">Rectangle that should be inserted</param> private void SortedInsertion(List <PPRect> list, PPRect item) { int position = list.BinarySearch(item, new PPRectAreaComparer()); if (position < 0) { position = ~position; } list.Insert(position, item); }
/// <inheritdoc /> /// <remarks> /// Performs the post-processing after placing the rectangle <paramref name="rectJustPlaced"/> /// This includes a "repair" of all the free rectangles that intersects with a <paramref name="rectJustPlaced"/> and removal of free rectangles that are fully included in other free rectangle /// </remarks> /// <exception cref="ArgumentNullException">Is thrown when the <paramref name="freeRectangles"/> is null</exception> public void PostProcess(List <PPRect> freeRectangles, PPRect rectJustPlaced) { if (freeRectangles == null) { throw new ArgumentNullException($"The {nameof(freeRectangles)} cannot be null"); } List <PPRect> rectsToAdd = new List <PPRect>(); PPRect[] resultingFreeRects = new PPRect[4]; for (int i = 0; i < freeRectangles.Count;) { if (freeRectangles[i].IntersectsWith(rectJustPlaced)) { //This is very similar to splitting a free rectangle but it is not the same, because this code does not assume (unlike the IFreeRectangleSplitter) that a rectangles are placed into a bottom-left of the free rectangle //Calculate FreeRect \ rectJustPlaced and split it into at most four free rects //make it always four (save NEW's and just set 0 dimension to nonused, then filter these upon addition) resultingFreeRects[0] = new PPRect(freeRectangles[i].Left, freeRectangles[i].Top, rectJustPlaced.Left, freeRectangles[i].Bottom); //LEFT resultingFreeRects[1] = new PPRect(freeRectangles[i].Left, freeRectangles[i].Top, freeRectangles[i].Right, rectJustPlaced.Top); //TOP resultingFreeRects[2] = new PPRect(rectJustPlaced.Right, freeRectangles[i].Top, freeRectangles[i].Right, freeRectangles[i].Bottom); //RIGHT resultingFreeRects[3] = new PPRect(freeRectangles[i].Left, rectJustPlaced.Bottom, freeRectangles[i].Right, freeRectangles[i].Bottom); //BOTTOM //(PPRect freeRect1, PPRect freeRect2) = splitter.SplitFreeRectangle(freeRectangles[i], rectJustPlaced); freeRectangles.RemoveAt(i); //rectsToAdd.Add(freeRect1); //rectsToAdd.Add(freeRect2); rectsToAdd.AddRange(resultingFreeRects.Where(x => x.Width > 0 && x.Height > 0)); } else { i++; } } freeRectangles.AddRange(rectsToAdd); List <PPRect> rectsToRemove = new List <PPRect>(); for (int i = 0; i < freeRectangles.Count; i++) { for (int j = 0; j < freeRectangles.Count; j++) { if (i != j && freeRectangles[i].Contains(freeRectangles[j])) { rectsToRemove.Add(freeRectangles[j]); } } } foreach (var toRemove in rectsToRemove) { freeRectangles.Remove(toRemove); } }
/// <summary> /// For a given rectangle that is being placed, selets the split direction (axis) /// </summary> /// <param name="rectToBePlaced">The rectangle that will be placed</param> /// <remarks>The direction is determined only be the <paramref name="rectToBePlaced"/> not by a free rectangle where it will be placed</remarks> /// <returns>The SplitDirection (the longer axis)</returns> private SplitDirection SelectSplitDirection(PPRect rectToBePlaced) { if (rectToBePlaced.Width > rectToBePlaced.Height) { return(SplitDirection.HORIZONTAL); } else { return(SplitDirection.VERTICAL); } }
//reimplement it using more efficient sweep a line algorithm private static bool Intersects(PPRect tested, IEnumerable <PPRect> possibleIntersections) { foreach (var x in possibleIntersections) { if (tested.IntersectsWith(x)) { return(true); } } return(false); }
public void LongerAxisGuillotineFreeRectangleSplitterTestFullBoth() { //Arrange var splitter = new LongerAxisGuillotineFreeRectangleSplitter(); var freeRectangle = new PPRect(0, 0, 100, 100); var rectToBePlaced = new PPRect(0, 0, 100, 100); //Act var result = splitter.SplitFreeRectangle(freeRectangle, rectToBePlaced); //Assert Assert.AreEqual(0, result.Count()); }
public void MaxRectsFreeRectangleSplitterTestFullBoth() { //Arrange var splitter = new MaxRectsFreeRectangleSplitter(); var freeRect = new PPRect(0, 0, 100, 100); var rectJustPlaced = new PPRect(0, 0, 100, 100); //Act var result = splitter.SplitFreeRectangle(freeRect, rectJustPlaced); //Assert Assert.AreEqual(0, result.Count()); }
public void BestAreaFitFreeRectangleExtractorTestEmpty() { //Arrange var rects = Enumerable.Empty <PPRect>().ToList(); var currentRect = new PPRect(0, 0, 32, 32); var extractor = new BestAreaFitFreeRectangleExtractor(); //Act var result = extractor.ExtractFreeRectangle(rects, currentRect); //Assert Assert.AreEqual(null, result); }
public void BestAreaFitFreeRectangleExtractorTestFitNone() { //Arrange var rects = Enumerable.Repeat(new PPRect(0, 0, 64, 64), 16).ToList(); var currentRect = new PPRect(0, 0, 64, 65); var extractor = new BestAreaFitFreeRectangleExtractor(); //Act var result = extractor.ExtractFreeRectangle(rects, currentRect); //Assert Assert.AreEqual(null, result); }
public void LongerAxisGuillotineFreeRectangleSplitterTestPositionHasNoEffect() { //Arrange var splitter = new LongerAxisGuillotineFreeRectangleSplitter(); var freeRectangle = new PPRect(0, 0, 100, 100); var freeRectangle2 = new PPRect(76, 54, 76 + 100, 54 + 100); var freeRectangle3 = new PPRect(220, 11, 220 + 100, 11 + 100); var rectToBePlaced = new PPRect(0, 0, 50, 50); //Act var result = splitter.SplitFreeRectangle(freeRectangle, rectToBePlaced); var result2 = splitter.SplitFreeRectangle(freeRectangle2, rectToBePlaced); var result3 = splitter.SplitFreeRectangle(freeRectangle3, rectToBePlaced); //Assert Assert.AreEqual(2, result.Count()); var item1 = result.First(); var item2 = result.Skip(1).First(); Assert.AreEqual(50, item1.Width); Assert.AreEqual(50, item2.Width); Assert.IsTrue(item1.Height == 50 || item1.Height == 100); if (item1.Height == 50) { //Then the second must have 100 Assert.AreEqual(100, item2.Height); } else { Assert.AreEqual(50, item2.Height); } Assert.AreEqual(2, result3.Count()); item1 = result2.First(); item2 = result2.Skip(1).First(); Assert.AreEqual(item1.Width, item1.Width); Assert.AreEqual(item1.Height, item1.Height); Assert.AreEqual(item2.Width, item2.Width); Assert.AreEqual(item2.Height, item2.Height); Assert.AreEqual(2, result3.Count()); item1 = result3.First(); item2 = result3.Skip(1).First(); Assert.AreEqual(item1.Width, item1.Width); Assert.AreEqual(item1.Height, item1.Height); Assert.AreEqual(item2.Width, item2.Width); Assert.AreEqual(item2.Height, item2.Height); }
public void MaxRectsFreeRectanglePostProcessorTestSingleIntersectionExactFit() { //Arrange var postProcessor = new MaxRectsFreeRectanglePostProcessor(); var freeRects = new List <PPRect>() { new PPRect(0, 0, 100, 100) }; var rectJustPlaced = new PPRect(0, 0, 100, 100); //Act postProcessor.PostProcess(freeRects, rectJustPlaced); //Assert Assert.AreEqual(0, freeRects.Count); }
/// <inheritdoc /> /// <summary> /// Split the <paramref name="selectedFreeRectangle"/> by it's longer axis /// </summary> /// <param name="selectedFreeRectangle">The free rectangle that was selected for a placement of <paramref name="rectToBePlaced"/></param> /// <param name="rectToBePlaced">The rectangle that should be placed</param> /// <returns>Free rectangle that results from the splitting of <paramref name="selectedFreeRectangle"/></returns> public IEnumerable <PPRect> SplitFreeRectangle(PPRect selectedFreeRectangle, PPRect rectToBePlaced) { SplitDirection splitDirection = SelectSplitDirection(/*selectedFreeRectangle, */ rectToBePlaced); switch (splitDirection) { case SplitDirection.HORIZONTAL: return(SplitFreeRectangleHorizontal(ref selectedFreeRectangle, rectToBePlaced)); case SplitDirection.VERTICAL: return(SplitFreeRectangleVertical(ref selectedFreeRectangle, rectToBePlaced)); default: throw new InvalidOperationException(); } }
public void MaxRectsFreeRectangleSortedMergerTestMergeOneHasZeroSize() { //Arrange var freeRectangles = new List <PPRect>(); var merger = new MaxRectsFreeRectangleSortedMerger(); var freeRect1 = new PPRect(0, 0, 100, 20); var freeRect2 = new PPRect(0, 0, 100, 0); var oldSize = freeRectangles.Count; //Act merger.MergeFreeRectangles(freeRectangles, new PPRect[] { freeRect1, freeRect2 }); //Assert Assert.AreEqual(oldSize + 1, freeRectangles.Count); Assert.AreEqual(100, freeRectangles[0].Width); Assert.AreEqual(20, freeRectangles[0].Height); }
public void LongerAxisGuillotineFreeRectangleSplitterTestFullHeight() { //Arrange var splitter = new LongerAxisGuillotineFreeRectangleSplitter(); var freeRectangle = new PPRect(0, 0, 200, 100); var rectToBePlaced = new PPRect(0, 0, 20, 100); //Act var result = splitter.SplitFreeRectangle(freeRectangle, rectToBePlaced); //Assert Assert.AreEqual(1, result.Count()); var item1 = result.First(); Assert.AreEqual(180, item1.Width); Assert.AreEqual(100, item1.Height); }
public void MaxRectsFreeRectangleSplitterTestFullHeight() { //Arrange var splitter = new MaxRectsFreeRectangleSplitter(); var freeRect = new PPRect(0, 0, 100, 100); var rectJustPlaced = new PPRect(0, 0, 50, 100); var expectedFreeRects = new List <PPRect>() { new PPRect(50, 0, 100, 100) }; //Act var result = splitter.SplitFreeRectangle(freeRect, rectJustPlaced); //Assert CollectionAssert.AreEquivalent(expectedFreeRects, result.ToList()); }
/// <inheritdoc /> /// <summary> /// Splits a free rectangle by both vertical and horizontal axis /// </summary> /// <param name="freeRect">Free rectangle that should be splitted</param> /// <param name="rectJustPlaced">The rectangle that should be placed to the <paramref name="freeRect"/></param> /// <returns></returns> public IEnumerable <PPRect> SplitFreeRectangle(PPRect freeRect, PPRect rectJustPlaced) { int splitX = freeRect.Left + rectJustPlaced.Width; int splitY = freeRect.Top + rectJustPlaced.Height; //Perform the split by horizontal axis //Rect above the horizontal axis var freeRectAbove = new PPRect(freeRect.Left, splitY, freeRect.Right, freeRect.Bottom); //Rect below the horizontal axis var freeRectBelow = new PPRect(freeRect.Left + rectJustPlaced.Width, freeRect.Top, freeRect.Right, splitY); //Perform the split by vertical axis //Rect to the right of the vertical axis var freeRectRight = new PPRect(splitX, freeRect.Top, freeRect.Right, freeRect.Bottom); //Rect to the left of the vertical axis var freeRectLeft = new PPRect(freeRect.Left, freeRect.Top + rectJustPlaced.Height, splitX, freeRect.Bottom); return(new PPRect[] { freeRectAbove, freeRectRight, freeRectBelow, freeRectLeft }.Where(x => x.Width > 0 && x.Height > 0).Distinct()); }
public void LongerAxisGuillotineFreeRectangleSplitterTestSplitByVerticalAxis() { //Arrange var splitter = new LongerAxisGuillotineFreeRectangleSplitter(); var freeRectangle = new PPRect(0, 0, 100, 200); var rectToBePlaced = new PPRect(0, 0, 10, 20); //Act var result = splitter.SplitFreeRectangle(freeRectangle, rectToBePlaced); //Assert Assert.AreEqual(2, result.Count()); var item1 = result.First(); var item2 = result.Skip(1).First(); Assert.IsTrue((item1.Height == 180 && item1.Width == 10 && item2.Height == 200 && item2.Width == 90) || (item2.Height == 180 && item2.Width == 10 && item1.Height == 200 && item1.Width == 90)); }
/// <summary> /// Selects free rectangle from freeLists. /// For BestAreaFit it means to select free rectangle of smallest area to which currentRectToPack can fit /// </summary> /// <param name="freeRects">Free rectangles</param> /// <param name="currentRectToPack">Rectangle that will be placed to the selected rectangle</param> /// <exception cref="ArgumentNullException">Is thrown when the <paramref name="freeRects"/> is null</exception> /// <returns>The best rectangle from <paramref name="freeRects"/> where the <paramref name="currentRectToPack"/> could be placed</returns> public PPRect?ExtractFreeRectangle(List <PPRect> freeRects, PPRect currentRectToPack) { if (freeRects == null) { throw new ArgumentNullException($"The {nameof(freeRects)} cannot be null"); } PPRect selectedRect = freeRects .OrderBy(x => ((long)x.Width * x.Height) - ((long)currentRectToPack.Width) * currentRectToPack.Height) .FirstOrDefault(x => x.Width >= currentRectToPack.Width && x.Height >= currentRectToPack.Height); if (selectedRect == null || selectedRect.Width <= 0 || selectedRect.Height <= 0) { return(null); } freeRects.Remove(selectedRect); return(selectedRect); }
void FlushPixelBuffer() { if (!IsContextValid) { return; } // Note that the pixel lock is held while the buffer is copied into the // device context and then flushed. PPRect srcRect = new PPRect(Size); graphics2DContext.PaintImageData(pixelBuffer, PPPoint.Zero, srcRect); if (FlushPending) { return; } FlushPending = true; graphics2DContext.Flush(); }
public void MaxRectsFreeRectanglePostProcessorTestMultiIntersection() { //Arrange var postProcessor = new MaxRectsFreeRectanglePostProcessor(); var freeRects = new List <PPRect>() { new PPRect(0, 0, 50, 50), new PPRect(40, 40, 40 + 50, 40 + 50) }; var rectJustPlaced = new PPRect(40, 40, 50, 50); //Act postProcessor.PostProcess(freeRects, rectJustPlaced); //Assert Assert.AreEqual(4, freeRects.Count); var sortedList = freeRects.OrderBy(x => x.Left).ThenBy(x => x.Top).ThenBy(x => x.Right).ToList(); Assert.AreEqual(0, sortedList[0].Left); Assert.AreEqual(0, sortedList[0].Top); Assert.AreEqual(40, sortedList[0].Width); Assert.AreEqual(50, sortedList[0].Height); Assert.AreEqual(0, sortedList[1].Left); Assert.AreEqual(0, sortedList[1].Top); Assert.AreEqual(50, sortedList[1].Width); Assert.AreEqual(40, sortedList[1].Height); Assert.AreEqual(40, sortedList[2].Left); Assert.AreEqual(50, sortedList[2].Top); Assert.AreEqual(50, sortedList[2].Width); Assert.AreEqual(40, sortedList[2].Height); Assert.AreEqual(50, sortedList[3].Left); Assert.AreEqual(40, sortedList[3].Top); Assert.AreEqual(40, sortedList[3].Width); Assert.AreEqual(50, sortedList[3].Height); }
public void MaxRectsFreeRectanglePostProcessorTestSingleIntersectionInMiddle() { //Arrange var postProcessor = new MaxRectsFreeRectanglePostProcessor(); var freeRects = new List <PPRect>() { new PPRect(0, 0, 50, 50), new PPRect(50, 0, 50 + 50, 50) }; var rectJustPlaced = new PPRect(10, 20, 10 + 20, 20 + 20); //Act postProcessor.PostProcess(freeRects, rectJustPlaced); //Assert Assert.AreEqual(5, freeRects.Count); //First free rectangle was divided into four parts var sortedList = freeRects.OrderBy(x => x.Left).ThenBy(x => x.Top).ThenBy(x => x.Right).ToList(); Assert.AreEqual(0, sortedList[0].Left); Assert.AreEqual(0, sortedList[0].Top); Assert.AreEqual(10, sortedList[0].Width); Assert.AreEqual(50, sortedList[0].Height); Assert.AreEqual(0, sortedList[1].Left); Assert.AreEqual(0, sortedList[1].Top); Assert.AreEqual(50, sortedList[1].Width); Assert.AreEqual(20, sortedList[1].Height); Assert.AreEqual(0, sortedList[2].Left); Assert.AreEqual(40, sortedList[2].Top); Assert.AreEqual(50, sortedList[2].Width); Assert.AreEqual(10, sortedList[2].Height); Assert.AreEqual(30, sortedList[3].Left); Assert.AreEqual(0, sortedList[3].Top); Assert.AreEqual(20, sortedList[3].Width); Assert.AreEqual(50, sortedList[3].Height); }
/// <inheritdoc /> public PackingResult PlaceRects(int width, int height, IEnumerable <PPRect> rects, CancellationToken token = default) { Progress = 0; if (width < 0 || height < 0) { throw new ArgumentOutOfRangeException($"The {nameof(width)} and {nameof(height)} should be non-negative"); } var sortedInput = sorter.SortImages(rects); int inputSize = rects.Count(); int placedRects = 0; int actualWidth = 0; int actualHeight = 0; RectComparer rectComparer = new RectComparer(); PointComparer ptComparer = new PointComparer(); SortedSet <PPRect> currentPacking = new SortedSet <PPRect>(rectComparer); SortedDictionary <SKPointI, int> pointsToTry = new SortedDictionary <SKPointI, int>(ptComparer) { { new SKPointI(0, 0), -1 } //the current packing is empty, so only point to try is point [0,0] }; SKPointI[] pointsToAdd = new SKPointI[2]; foreach (var x in sortedInput) { if (token.IsCancellationRequested) { Progress = 0; return(null); } SKPointI?pointToRemove = null; foreach (var ptToTry in pointsToTry) { PPRect tested = new PPRect(ptToTry.Key.X, ptToTry.Key.Y, ptToTry.Key.X + x.Width, ptToTry.Key.Y + x.Height); var possibleIntersections = currentPacking.AsEnumerable(); //have to test everything if (ptToTry.Key.X + x.Width <= width && ptToTry.Key.Y + x.Height <= height && !Intersects(tested, possibleIntersections)) //safe to pack here { if (ptToTry.Key.X + x.Width > actualWidth) { actualWidth = ptToTry.Key.X + x.Width; } if (ptToTry.Key.Y + x.Height > actualHeight) { actualHeight = ptToTry.Key.Y + x.Height; } int improved = 0; if (TryImprove(ref tested, currentPacking, 0)) //Try to position it further to the top / left { improved++; } //Add it to the packing tested.Image = x.Image; currentPacking.Add(tested); if (improved == 0) { pointToRemove = ptToTry.Key; } pointsToAdd[0] = new SKPointI(ptToTry.Key.X + x.Width, ptToTry.Key.Y); pointsToAdd[1] = new SKPointI(ptToTry.Key.X, ptToTry.Key.Y + x.Height); break; } } if (pointToRemove != null) { pointsToTry.Remove(pointToRemove.Value); pointsToTry[pointsToAdd[0]] = -1; pointsToTry[pointsToAdd[1]] = -1; Progress = (int)((++placedRects / (double)inputSize) * 100.0); ProgressChange?.Invoke(this, Progress); } else { Progress = 100; return(null); //we cannot pack it anywhere } } //var result = new PackingResult(width, height, currentPacking.Select(x => (x.Value, x.Key))); // probably better to return result with actual width & height instead of those needed //actual height can be lower than height specified, width also BUT THIS IS NOT DESIRED, BECAUSE THIS CAN BE CALLED FROM FIXEDSIZE..? OR chhange size in FixedSize.. var result = new PackingResult(actualWidth, actualHeight, currentPacking); return(result); }
/// <summary> /// Decides the orientation of the rectangle /// </summary> /// <remarks> /// The rectangle could either be rotated by 90 degrees, or not rotated at all /// This default orientation does not rotate /// </remarks> /// <param name="rect">The rect for which the orientation should be selected</param> /// <returns>The <paramref name="rect"/>, possibly rotated</returns> private PPRect DecideOrientationOfRect(PPRect rect) { return(rect); }
/// <summary> /// Creates a ViewModel for a given <paramref name="rect"/> /// </summary> /// <param name="rect">The rectangle for which the view model should be created</param> public RectangleViewModel(PPRect rect) { Rectangle = rect; }