public static void Verify(BinPackParameter parameter, string algorithmName, IList <IList <Cuboid> > result) { // o--------o // /| /| // / | / | // h o--------o | // e | o-----|--o h //y i | / | / t // g |/ |/ p z // h o--------o e // t | width d // | x // (0, 0, 0) foreach (var cuboids in result) { for (int a = 0; a < cuboids.Count; ++a) { // check if cuboid out of bin var cuboid = cuboids[a]; if (cuboid.X < 0 || cuboid.Y < 0 || cuboid.Z < 0) { throw new ArithmeticException( $"verify cuboid failed: negative position, algorithm: {algorithmName}, cuboid: {cuboid}"); } if (cuboid.X + cuboid.Width > parameter.BinWidth || cuboid.Y + cuboid.Height > parameter.BinHeight || cuboid.Z + cuboid.Depth > parameter.BinDepth) { throw new ArithmeticException( $"verify cuboid failed: out of bin, algorithm: {algorithmName}, cuboid: {cuboid}"); } // check if this cuboid intersects others for (int b = a + 1; b < cuboids.Count; ++b) { var otherCuboid = cuboids[b]; if (cuboid.X < otherCuboid.X + otherCuboid.Width && otherCuboid.X < cuboid.X + cuboid.Width && cuboid.Y < otherCuboid.Y + otherCuboid.Height && otherCuboid.Y < cuboid.Y + cuboid.Height && cuboid.Z < otherCuboid.Z + otherCuboid.Depth && otherCuboid.Z < cuboid.Z + cuboid.Depth) { throw new ArithmeticException( $"verify cuboid failed: cuboid intersects others, algorithm: {algorithmName}, cuboid a: {cuboid}, cuboid b: {otherCuboid}"); } } } // check is cuboids overweight if (cuboids.Sum(c => c.Weight) > parameter.BinWeight) { throw new ArithmeticException( $"verify cuboid failed: cuboids overweight, algorithm: {algorithmName}"); } } }
public static decimal GetVolumeRate(BinPackParameter parameter, IList <IList <Cuboid> > result) { var volumeRates = result.Select(x => GetVolumeRate(parameter, x)).ToList(); if (volumeRates.Count > 1) { // ignore last bin volumeRates.RemoveAt(volumeRates.Count - 1); } return(volumeRates.Average()); }
public BinPackResult Pack(BinPackParameter parameter) { // [ [ cuboid in bin a, cuboid in bin a, ... ], [ cuboid in bin b, ... ] ] IList <IList <Cuboid> > bestResult = null; var allResults = new List <IList <IList <Cuboid> > >(); string bestAlgorithmName = null; foreach (var factory in _factories) { foreach (var cuboids in GetCuboidsPermutations(parameter.Cuboids)) { // reset cuboids state var unpackedCuboids = cuboids.Select(c => c.CloneWithoutPlaceInformation()).ToList(); var result = new List <IList <Cuboid> >(); var algorithmName = ""; while (unpackedCuboids.Count > 0) { // pack single bin var algorithm = factory(parameter); algorithmName = algorithm.ToString(); algorithm.Insert(unpackedCuboids); // find out which cuboids are placed var packedCuboids = unpackedCuboids.Where(c => c.IsPlaced).ToList(); if (packedCuboids.Count == 0) { break; } result.Add(packedCuboids); // pack remain cuboids unpackedCuboids = unpackedCuboids.Where(c => !c.IsPlaced).ToList(); } // verify this result if (_verifyOption == BinPackerVerifyOption.All) { Verify(parameter, algorithmName, result); } // add to all results allResults.Add(result); // update best result if all cuboids is placed and uses less bins if (unpackedCuboids.Count == 0 && (bestResult == null || result.Count < bestResult.Count)) { bestResult = result; bestAlgorithmName = algorithmName; } } } if (bestResult == null) { throw new InvalidOperationException( "no algorithm can pack these cuboids\n" + $"binWidth: {parameter.BinWidth}, binHeight: {parameter.BinHeight}, " + $"binDepth: {parameter.BinDepth}, binWeight: {parameter.BinWeight}\n" + $"cuboids: {string.Join("\n", parameter.Cuboids.Select(x => x.ToString()))}"); } // verify the best result if (_verifyOption == BinPackerVerifyOption.BestOnly) { Verify(parameter, bestAlgorithmName, bestResult); } return(new BinPackResult(bestResult, allResults, bestAlgorithmName)); }
public BinPackResult Pack(BinPackParameter parameter) { // [ [ cuboid in bin a, cuboid in bin a, ... ], [ cuboid in bin b, ... ] ] var bestResult = new List <IList <Cuboid> >(); IList <Cuboid> pendingCuboids = parameter.Cuboids.ToList(); while (pendingCuboids.Count > 0) { // pack a single bin // find the best volume rate from the combination of algorithms and permutations IList <Cuboid> singleBestResult = null; IList <Cuboid> singleBestRemain = null; decimal singleBestVolumeRate = 0; string singleBestAlgorihm = null; foreach (var factory in _factories) { foreach (var cuboids in GetCuboidsPermutations(pendingCuboids, parameter.ShuffleCount)) { var targetCuboids = cuboids.Select(c => c.CloneWithoutPlaceInformation()).ToList(); var algorithm = factory(parameter); var algorithmName = algorithm.ToString(); algorithm.Insert(targetCuboids); var packedCuboids = targetCuboids.Where(c => c.IsPlaced).ToList(); if (packedCuboids.Count == 0) { break; } // verify this result if (_verifyOption == BinPackerVerifyOption.All) { Verify(parameter, algorithmName, packedCuboids); } // compare with the best result var volumeRate = GetVolumeRate(parameter, packedCuboids); if (singleBestResult == null || volumeRate > singleBestVolumeRate) { // update the best result singleBestResult = packedCuboids; singleBestRemain = targetCuboids.Where(c => !c.IsPlaced).ToList(); singleBestVolumeRate = volumeRate; singleBestAlgorihm = algorithmName; } } } if (singleBestResult == null) { throw new InvalidOperationException( "no algorithm can pack these cuboids\n" + $"binWidth: {parameter.BinWidth}, binHeight: {parameter.BinHeight}, " + $"binDepth: {parameter.BinDepth}, binWeight: {parameter.BinWeight}\n" + $"cuboids: {string.Join("\n", parameter.Cuboids.Select(x => x.ToString()))}"); } // verify the best result if (_verifyOption == BinPackerVerifyOption.BestOnly) { Verify(parameter, singleBestAlgorihm, singleBestResult); } // update the best result of multiple bins bestResult.Add(singleBestResult); pendingCuboids = singleBestRemain; } return(new BinPackResult(bestResult)); }
public static decimal GetVolumeRate(BinPackParameter parameter, IList <Cuboid> result) { return(result.Sum(x => x.Width * x.Height * x.Depth) / (parameter.BinWidth * parameter.BinHeight * parameter.BinDepth)); }