/// <summary> /// Calculates potential total blocked area by placing object on given position /// </summary> private double GetBelowUnavaibleArea(Position2D positionToPlace, SkylineContainer2D container2D, int objectWidth) { double totalBlockedArea = 0.0; int endOfObjectWidth = positionToPlace.X + objectWidth; foreach (var availableSkyline in container2D.AvailableSkylines.ToList()) { // Checks only skylines below place if (availableSkyline.Y <= positionToPlace.Y) { // Object completely cover skyline below - no unused space if (availableSkyline.X >= positionToPlace.X && availableSkyline.X2 <= endOfObjectWidth) { //totalBlockedArea += 0; continue; } // Object partially cover skyline below (left) - unused space on right if (availableSkyline.X < positionToPlace.X && availableSkyline.X2 <= endOfObjectWidth && availableSkyline.X2 > positionToPlace.X) { totalBlockedArea += (endOfObjectWidth - availableSkyline.X) * (positionToPlace.Y - availableSkyline.Y); continue; } // Object partially cover skyline below (right) - unused space on left if (availableSkyline.X >= positionToPlace.X && availableSkyline.X < endOfObjectWidth && availableSkyline.X2 > endOfObjectWidth) { totalBlockedArea += (availableSkyline.X2 - positionToPlace.X) * (positionToPlace.Y - availableSkyline.Y); continue; } // Object partially cover skyline below from both size -> unused space on left and right if (availableSkyline.X < positionToPlace.X && availableSkyline.X2 > endOfObjectWidth) { //left totalBlockedArea += (positionToPlace.X - availableSkyline.X) * (availableSkyline.Y * positionToPlace.Y); //right totalBlockedArea += (availableSkyline.X2 - endOfObjectWidth) * (availableSkyline.Y * positionToPlace.Y); } } } return(totalBlockedArea); }
public override void Execute(ObjectSet originalObjects) { double bestFitResult = Double.MaxValue; double currentFitResult; int selectedFitContainerIndex = 0; Position2D positionToPlace = null; SkylineContainer2D selectedContainer = containers.First() as SkylineContainer2D; var objectsCopy = originalObjects.ToObjectList(); while (objectsCopy.Any()) { Object2D selectedObject = objectsCopy.First() as Object2D; for (int i = 0; i < containers.Count; i++) { currentFitResult = FindBestFitWithinContainer(containers[i] as SkylineContainer2D, selectedObject, bestFitResult, ref positionToPlace); if (currentFitResult < bestFitResult) { bestFitResult = currentFitResult; selectedFitContainerIndex = i; break; } } // Object not placed, create new container, place object bottom-left if (positionToPlace == null) { AddContainer(); selectedContainer = containers.Last() as SkylineContainer2D; positionToPlace = new Position2D(0, 0); } else { selectedContainer = containers[selectedFitContainerIndex] as SkylineContainer2D; } objectsCopy.Remove(selectedObject); selectedContainer.PlaceNewObject(selectedObject, positionToPlace); selectedFitContainerIndex = 0; bestFitResult = Double.MaxValue; positionToPlace = null; } }
public override void Execute(ObjectSet originalObjects) { int selectedFitContainerIndex = 0; Position2D positionToPlace = null; SkylineContainer2D selectedContainer = containers.First() as SkylineContainer2D; var objectsCopy = originalObjects.ToObjectList(); while (objectsCopy.Any()) { Object2D selectedObject = objectsCopy.First() as Object2D; for (int i = 0; i < containers.Count; i++) { positionToPlace = FindMostBottomFittingSkyline(containers[i] as SkylineContainer2D, selectedObject); if (positionToPlace != null) { selectedFitContainerIndex = i; break; } } // Object not placed, create new container, place object bottom-left if (positionToPlace == null) { AddContainer(); selectedContainer = containers.Last() as SkylineContainer2D; positionToPlace = new Position2D(0, 0); } else { selectedContainer = containers[selectedFitContainerIndex] as SkylineContainer2D; } objectsCopy.Remove(selectedObject); selectedContainer.PlaceNewObject(selectedObject, positionToPlace); selectedFitContainerIndex = 0; } }
protected Position2D CheckShiftedPositionAvailability(SkylineContainer2D container2D, Object2D objectToPlace, Line currentSkyline) { //Skylines on left side of currently checked skyline, starting from nearest var skylinesOnLeft = container2D.AvailableSkylines.Where(x => x.X < currentSkyline.X).OrderByDescending(x => x.X).ToList(); Position2D mostLeftPosition = new Position2D(currentSkyline.X, currentSkyline.Y); // Look if object can be moved further to left, i.e. skyylines on left are below current skyline foreach (Line skyline in skylinesOnLeft) { if (skyline.Y < currentSkyline.Y) { mostLeftPosition.X = skyline.X; } else { break; } } // Part protruding on the right side of current skyline int protrudingPartLenght = mostLeftPosition.X + objectToPlace.Width - currentSkyline.X2; // If it exceed container width, then break if (protrudingPartLenght + currentSkyline.X2 > container2D.Width) { return(null); } //Skylines on right side of currently checked skyline covered by protruding part, starting from nearest var skylinesOnRight = container2D.AvailableSkylines.Where(x => x.X > currentSkyline.X && x.X < currentSkyline.X2 + protrudingPartLenght).OrderBy(x => x.X).ToList(); // Check if skylines on right are below object; If yes, it can be placed, otherwise object would overlap foreach (Line skyline in skylinesOnRight) { if (skyline.Y > currentSkyline.Y) { mostLeftPosition = null; break; } } return(mostLeftPosition); }
protected double FindBestFitWithinContainer(SkylineContainer2D container2D, Object2D objectToPlace, double globallyBestFit, ref Position2D bestGlobalFitPosition) { var sortedSkylines = container2D.AvailableSkylines.OrderBy(o => o.Y).ToList(); Position2D leftShiftedPosition, bestFitPosition = null; double currentFitValue, bestFitValueInContainer = Double.MaxValue; foreach (Line skyline in sortedSkylines) { // Skyline + object is higher than container; As skylines are sorted from lowest, break on first compatible statement if (skyline.Y + objectToPlace.Height > container2D.Height) { break; } leftShiftedPosition = CheckShiftedPositionAvailability(container2D, objectToPlace, skyline); if (leftShiftedPosition != null) { currentFitValue = GetBelowUnavaibleArea(leftShiftedPosition, container2D, objectToPlace.Width); if (currentFitValue < bestFitValueInContainer) { bestFitValueInContainer = currentFitValue; bestFitPosition = leftShiftedPosition; } } } if (bestFitValueInContainer < globallyBestFit) { bestGlobalFitPosition = bestFitPosition; return(bestFitValueInContainer); } else { return(globallyBestFit); } }
private Position2D FindMostBottomFittingSkyline(SkylineContainer2D container2D, Object2D objectToPlace) { var sortedSkylines = container2D.AvailableSkylines.OrderBy(o => o.Y); Position2D leftShiftedPosition = null; foreach (Line skyline in sortedSkylines) { // Skyline + object is higher than container; As skylines are sorted from lowest, break on first compatible statement if (skyline.Y + objectToPlace.Height > container2D.Height) { break; } // Object is wider than skyline leftShiftedPosition = CheckShiftedPositionAvailability(container2D, objectToPlace, skyline); if (leftShiftedPosition != null) { return(leftShiftedPosition); } } return(null); }