private void TryAndStackItemsIntoSpace(PackedLayer layer, PackedItem prevItem, ItemList nextItems, int maxWidth, int maxLength, int maxDepth, int x, int y, int z, int rowLength ) { while (items.Count() > 0 && CheckNonDimensionalConstraints(items.Top())) { var stackedItem = GetOrientationForItem( items.Top(), prevItem, nextItems, items.Count == 1, maxWidth, maxLength, maxDepth, rowLength, x, y, z ); if (stackedItem != null) { remainingWeight -= items.Top().Weight; layer.Insert(PackedItem.FromOrientatedItem(stackedItem, x, y, z)); items.Extract(); maxDepth -= stackedItem.Depth; z += stackedItem.Depth; } else { break; } } }
/// <summary> /// Pack items into an individual vertical layer. /// </summary> /// <param name="startDepth"></param> /// <param name="widthLeft"></param> /// <param name="lengthLeft"></param> /// <param name="depthLeft"></param> protected void PackLayer(int startDepth, int widthLeft, int lengthLeft, int depthLeft) { var newLayer = new PackedLayer(); layers.Add(newLayer); int x, y, rowWidth, rowLength, layerDepth; x = y = rowWidth = rowLength = layerDepth = 0; PackedItem prevItem = null; while (items.Count > 0) { var itemToPack = items.Extract(); //skip items that are simply too heavy or too large if (!CheckNonDimensionalConstraints(itemToPack)) { RebuildItemList(); continue; } var orientedItem = GetOrientationForItem(itemToPack, prevItem, items, !HasItemsLeftToPack(), widthLeft, lengthLeft, depthLeft, rowLength, x, y, startDepth ); if (orientedItem != null) { var packedItem = PackedItem.FromOrientatedItem(orientedItem, x, y, startDepth); newLayer.Insert(packedItem); remainingWeight -= orientedItem.Item.Weight; widthLeft -= orientedItem.Width; rowWidth += orientedItem.Width; rowLength = Math.Max(rowLength, orientedItem.Length); layerDepth = Math.Max(layerDepth, orientedItem.Depth); //allow items to be stacked in place within the same footprint up to current layer depth var stackableDepth = layerDepth - orientedItem.Depth; TryAndStackItemsIntoSpace(newLayer, prevItem, items, orientedItem.Width, orientedItem.Length, stackableDepth, x, y, startDepth + orientedItem.Depth, rowLength ); x += orientedItem.Width; prevItem = packedItem; if (items.Count == 0) { RebuildItemList(); } } else if (newLayer.Items.Count == 0) { // zero items on layer // doesn't fit on layer even when empty, skipping for good continue; } else if (widthLeft > 0 && items.Count > 0) { // skip for now, move on to the next item skippedItems.Add(itemToPack); // abandon here if next item is the same, no point trying to keep going. Last time is not skipped, need that to trigger appropriate reset logic while (items.Count > 2 && orientatedItemFactory.IsSameDimensions(itemToPack, items.Top())) { this.skippedItems.Add(items.Extract()); } } else if (x > 0 && lengthLeft >= Math.Min(Math.Min(itemToPack.Width, itemToPack.Length), itemToPack.Depth)) { // No more fit in width wise, resetting for new row widthLeft += rowWidth; lengthLeft -= rowLength; y += rowLength; x = rowWidth = rowLength = 0; skippedItems.Add(itemToPack); RebuildItemList(); prevItem = null; continue; } else { // no items fit, so starting next vertical layer skippedItems.Add(itemToPack); RebuildItemList(); return; } } }