private void SplitFreeCuboidAlongAxis( Cuboid freeCuboid, Cuboid placedCuboid, bool splitHorizontal) { var bottom = new Cuboid(); bottom.X = freeCuboid.X; bottom.Y = freeCuboid.Y; bottom.Z = freeCuboid.Z + placedCuboid.Depth; bottom.Depth = freeCuboid.Depth - placedCuboid.Depth; bottom.Height = placedCuboid.Height; var right = new Cuboid(); right.X = freeCuboid.X + placedCuboid.Width; right.Y = freeCuboid.Y; right.Z = freeCuboid.Z; right.Width = freeCuboid.Width - placedCuboid.Width; right.Height = placedCuboid.Height; var top = new Cuboid(); top.X = freeCuboid.X; top.Y = freeCuboid.Y + placedCuboid.Height; top.Z = freeCuboid.Z; top.Height = freeCuboid.Height - placedCuboid.Height; top.Width = freeCuboid.Width; top.Depth = freeCuboid.Depth; if (splitHorizontal) { bottom.Width = freeCuboid.Width; right.Depth = placedCuboid.Depth; } else // Split vertically { bottom.Width = placedCuboid.Width; right.Depth = freeCuboid.Depth; } // Add new free cuboids. if (bottom.Width > 0 && bottom.Height > 0 && bottom.Depth > 0) { AddFreeCuboid(bottom); } if (right.Width > 0 && right.Height > 0 && right.Depth > 0) { AddFreeCuboid(right); } if (top.Width > 0 && top.Height > 0 && top.Depth > 0) { AddFreeCuboid(top); } }
private decimal ScoreByHeuristic( Cuboid cuboid, Cuboid freeCuboid, FreeCuboidChoiceHeuristic cuboidChoice) { switch (cuboidChoice) { case FreeCuboidChoiceHeuristic.CuboidMinHeight: return(freeCuboid.Y + cuboid.Height); default: throw new NotSupportedException($"cuboid choice is unsupported: {cuboidChoice}"); } }
private void AddFreeCuboid(Cuboid freeCuboid) { if (freeCuboid.X < 0 || freeCuboid.Y < 0 || freeCuboid.Z < 0) { throw new ArithmeticException( $"add free cuboid failed: negative position, algorithm: {this}, cuboid: {freeCuboid}"); } if (freeCuboid.X + freeCuboid.Width > _binWidth || freeCuboid.Y + freeCuboid.Height > _binHeight || freeCuboid.Z + freeCuboid.Depth > _binDepth) { throw new ArithmeticException( $"add free cuboid failed: out of bin, algorithm: {this}, cuboid: {freeCuboid}"); } _freeCuboids.Add(freeCuboid); }
private void SplitFreeCuboidByHeuristic( Cuboid freeCuboid, Cuboid placedCuboid, GuillotineSplitHeuristic method) { // Compute the lengths of the leftover area. var w = freeCuboid.Width - placedCuboid.Width; var d = freeCuboid.Depth - placedCuboid.Depth; // Use the given heuristic to decide which choice to make. bool splitHorizontal; switch (method) { case GuillotineSplitHeuristic.SplitShorterLeftoverAxis: // Split along the shorter leftover axis. splitHorizontal = (w <= d); break; case GuillotineSplitHeuristic.SplitLongerLeftoverAxis: // Split along the longer leftover axis. splitHorizontal = (w > d); break; case GuillotineSplitHeuristic.SplitShorterAxis: // Split along the shorter total axis. splitHorizontal = (freeCuboid.Width <= freeCuboid.Depth); break; case GuillotineSplitHeuristic.SplitLongerAxis: // Split along the longer total axis. splitHorizontal = (freeCuboid.Width > freeCuboid.Depth); break; default: throw new NotSupportedException($"split method is unsupported: {method}"); } // Perform the actual split. SplitFreeCuboidAlongAxis(freeCuboid, placedCuboid, splitHorizontal); }
private void Insert(Cuboid cuboid, ShelfChoiceHeuristic method) { switch (method) { case ShelfChoiceHeuristic.ShelfNextFit: PutOnShelf(_shelves.Last(), cuboid); if (cuboid.IsPlaced) { AddToShelf(_shelves.Last(), cuboid); return; } break; case ShelfChoiceHeuristic.ShelfFirstFit: foreach (var shelf in _shelves) { PutOnShelf(shelf, cuboid); if (cuboid.IsPlaced) { AddToShelf(shelf, cuboid); return; } } break; } // The rectangle did not fit on any of the shelves. Open a new shelf. // Sort edges in decreasing order var edges = new List <decimal>() { cuboid.Width, cuboid.Height, cuboid.Depth }; edges.Sort(); var max = edges[2]; var middle = edges[1]; var min = edges[0]; var whdSet = new[] { new { w = middle, h = max, d = min }, new { w = max, h = middle, d = min }, new { w = middle, h = min, d = max } }; foreach (var whd in whdSet) { cuboid.Width = whd.w; cuboid.Height = whd.h; cuboid.Depth = whd.d; if (CanStartNewShelf(cuboid.Height)) { StartNewShelf(cuboid.Height); PutOnShelf(_shelves.Last(), cuboid); if (cuboid.IsPlaced) { AddToShelf(_shelves.Last(), cuboid); return; } } } // The rectangle didn't fit. }
private void PutOnShelf(Shelf shelf, Cuboid cuboid) { var width = cuboid.Width; var height = cuboid.Height; var depth = cuboid.Depth; // Sort edges in decreasing order var edges = new List <decimal>() { width, height, depth }; edges.Sort(); var max = edges[2]; var middle = edges[1]; var min = edges[0]; // Set cuboid's longest egde vertically if (max > shelf.Height) { // pass } else { var maxVerticalRect = new Rectangle(middle, min, 0, 0); var freeRectIndex = 0; shelf.Guillotine.Insert(maxVerticalRect, _rectChoice, out freeRectIndex); if (maxVerticalRect.IsPlaced) { shelf.Guillotine.InsertOnPosition(maxVerticalRect, _splitMethod, freeRectIndex); cuboid.IsPlaced = true; cuboid.Width = maxVerticalRect.Width; cuboid.Height = max; cuboid.Depth = maxVerticalRect.Height; cuboid.X = maxVerticalRect.X; cuboid.Z = maxVerticalRect.Y; return; } } // Set cuboid's second longest egde vertically if (middle > shelf.Height) { // pass } else { var middleVerticalRect = new Rectangle(min, max, 0, 0); var freeRectIndex = 0; shelf.Guillotine.Insert(middleVerticalRect, _rectChoice, out freeRectIndex); if (middleVerticalRect.IsPlaced) { shelf.Guillotine.InsertOnPosition(middleVerticalRect, _splitMethod, freeRectIndex); cuboid.IsPlaced = true; cuboid.Width = middleVerticalRect.Width; cuboid.Height = middle; cuboid.Depth = middleVerticalRect.Height; cuboid.X = middleVerticalRect.X; cuboid.Z = middleVerticalRect.Y; return; } } // Set cuboid's smallest egde vertically if (min > shelf.Height) { // pass } else { var minVerticalRect = new Rectangle(middle, max, 0, 0); var freeRectIndex = 0; shelf.Guillotine.Insert(minVerticalRect, _rectChoice, out freeRectIndex); if (minVerticalRect.IsPlaced) { shelf.Guillotine.InsertOnPosition(minVerticalRect, _splitMethod, freeRectIndex); cuboid.IsPlaced = true; cuboid.Width = minVerticalRect.Width; cuboid.Height = min; cuboid.Depth = minVerticalRect.Height; cuboid.X = minVerticalRect.X; cuboid.Z = minVerticalRect.Y; return; } } // Place failed }
private void FindPositionForNewNode( Cuboid cuboid, FreeCuboidChoiceHeuristic cuboidChoice, out int freeCuboidIndex) { var width = cuboid.Width; var height = cuboid.Height; var depth = cuboid.Depth; var bestScore = decimal.MaxValue; freeCuboidIndex = -1; // Try each free cuboid to find the best one for placement a given cuboid. // Rotate a cuboid in every possible way and find which choice is the best. for (int index = 0; index < _freeCuboids.Count; ++index) { var freeCuboid = _freeCuboids[index]; // Width x Height x Depth if (width <= freeCuboid.Width && height <= freeCuboid.Height && depth <= freeCuboid.Depth) { var score = ScoreByHeuristic(cuboid, freeCuboid, cuboidChoice); if (score < bestScore) { cuboid.IsPlaced = true; cuboid.X = freeCuboid.X; cuboid.Y = freeCuboid.Y; cuboid.Z = freeCuboid.Z; cuboid.Width = width; cuboid.Height = height; cuboid.Depth = depth; bestScore = score; freeCuboidIndex = index; } } // Width x Depth x Height if (width <= freeCuboid.Width && depth <= freeCuboid.Height && height <= freeCuboid.Depth) { var score = ScoreByHeuristic(cuboid, freeCuboid, cuboidChoice); if (score < bestScore) { cuboid.IsPlaced = true; cuboid.X = freeCuboid.X; cuboid.Y = freeCuboid.Y; cuboid.Z = freeCuboid.Z; cuboid.Width = width; cuboid.Height = depth; cuboid.Depth = height; bestScore = score; freeCuboidIndex = index; } } // Depth x Height x Width if (depth <= freeCuboid.Width && height <= freeCuboid.Height && width <= freeCuboid.Depth) { var score = ScoreByHeuristic(cuboid, freeCuboid, cuboidChoice); if (score < bestScore) { cuboid.IsPlaced = true; cuboid.X = freeCuboid.X; cuboid.Y = freeCuboid.Y; cuboid.Z = freeCuboid.Z; cuboid.Width = depth; cuboid.Height = height; cuboid.Depth = width; bestScore = score; freeCuboidIndex = index; } } // Depth x Width x Height if (depth <= freeCuboid.Width && width <= freeCuboid.Height && height <= freeCuboid.Depth) { var score = ScoreByHeuristic(cuboid, freeCuboid, cuboidChoice); if (score < bestScore) { cuboid.IsPlaced = true; cuboid.X = freeCuboid.X; cuboid.Y = freeCuboid.Y; cuboid.Z = freeCuboid.Z; cuboid.Width = depth; cuboid.Height = width; cuboid.Depth = height; bestScore = score; freeCuboidIndex = index; } } // Height x Width x Depth if (height <= freeCuboid.Width && width <= freeCuboid.Height && depth <= freeCuboid.Depth) { var score = ScoreByHeuristic(cuboid, freeCuboid, cuboidChoice); if (score < bestScore) { cuboid.IsPlaced = true; cuboid.X = freeCuboid.X; cuboid.Y = freeCuboid.Y; cuboid.Z = freeCuboid.Z; cuboid.Width = height; cuboid.Height = width; cuboid.Depth = depth; bestScore = score; freeCuboidIndex = index; } } // Height x Depth x Width if (height <= freeCuboid.Width && depth <= freeCuboid.Height && width <= freeCuboid.Depth) { var score = ScoreByHeuristic(cuboid, freeCuboid, cuboidChoice); if (score < bestScore) { cuboid.IsPlaced = true; cuboid.X = freeCuboid.X; cuboid.Y = freeCuboid.Y; cuboid.Z = freeCuboid.Z; cuboid.Width = height; cuboid.Height = depth; cuboid.Depth = width; bestScore = score; freeCuboidIndex = index; } } } }