#region License Information
/* HeuristicLab
* Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Encodings.PermutationEncoding;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
using HeuristicLab.Problems.BinPacking3D.ExtremePointCreation;
using HeuristicLab.Problems.BinPacking3D.ExtremePointPruning;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HeuristicLab.Problems.BinPacking3D.Packer {
internal class BinPackerResidualSpaceBestFit : BinPacker {
#region Constructors for HEAL
[StorableConstructor]
protected BinPackerResidualSpaceBestFit(bool deserializing) : base(deserializing) { }
protected BinPackerResidualSpaceBestFit(BinPackerResidualSpaceBestFit original, Cloner cloner)
: base(original, cloner) {
}
public override IDeepCloneable Clone(Cloner cloner) {
return new BinPackerResidualSpaceBestFit(this, cloner);
}
#endregion
public BinPackerResidualSpaceBestFit() : base() { }
///
/// Packs the items into the bins by using a best fit residual space algorithm.
/// The order of the chosen items depends on the merit function.
/// Each residual space belongs to an extreme point.
///
/// Returns a collection of bin packing 3d objects. Each object represents a bin and the packed items
public override IList PackItems(Permutation sortedItems, PackingShape binShape, IList items, ExtremePointCreationMethod epCreationMethod, ExtremePointPruningMethod epPruningMethod, bool useStackingConstraints) {
IList packingList = new List();
IList remainingIds = new List(sortedItems);
IExtremePointCreator extremePointCreator = ExtremePointCreatorFactory.CreateExtremePointCreator(epCreationMethod, useStackingConstraints);
foreach (var remainingId in remainingIds) {
PackingItem item = items[remainingId];
var residualSpacePoints = GetResidualSpaceForAllPoints(packingList, item);
var sortedPoints = residualSpacePoints.OrderBy(x => x.Item3);
var packed = false;
foreach (var point in sortedPoints) {
if (point.Item1.IsPositionFeasible(item, point.Item2, useStackingConstraints)) {
var binPacking = point.Item1;
PackItem(binPacking, remainingId, item, point.Item2, extremePointCreator, useStackingConstraints);
packed = true;
break;
}
}
if (!packed) {
BinPacking3D binPacking = new BinPacking3D(binShape);
var position = FindPackingPositionForItem(binPacking, item, useStackingConstraints);
if (position != null) {
PackItem(binPacking, remainingId, item, position, extremePointCreator, useStackingConstraints);
} else {
throw new InvalidOperationException("Item " + remainingId + " cannot be packed into an empty bin.");
}
packingList.Add(binPacking);
}
}
ExtremePointPruningFactory.CreatePruning().PruneExtremePoints(epPruningMethod, packingList);
return packingList;
}
///
/// This method returns a list with all bins and their residual space where a given item can be placed.
/// It is nessecary to get all bins and their residaul space because this list will be sortet later.
///
///
///
///
public static IList> GetResidualSpaceForAllPoints(IList packingList, PackingItem item) {
var residualSpacePoints = new List>();
foreach (BinPacking3D bp in packingList) {
foreach (var extremPoints in bp.ExtremePoints) {
var ep = extremPoints.Key;
var residualSpaces = extremPoints.Value.Where(rs => rs.Width < item.Width || rs.Height < item.Height || rs.Depth < item.Depth);
if (residualSpaces.Count() <= 0) {
continue;
}
int merit = residualSpaces.Max(rs => CalculateResidualMerit(rs, item, ep));
residualSpacePoints.Add(Tuple.Create(bp, ep, merit));
}
}
return residualSpacePoints;
}
///
/// The merit function puts an item on the EP that minimizes the difference between its residual space an the item dimension
///
///
///
///
///
private static int CalculateResidualMerit(ResidualSpace rs, PackingItem item, PackingPosition ep) {
return ((rs.Width - item.Width) +
(rs.Height - item.Height) +
(rs.Depth - item.Depth));
}
}
}