/// <summary> /// metodo per stabilire se è possibile /// trovare una posizione in cui nestare /// un nuovo item /// </summary> /// <param name="temporaryBin"></param> /// <param name="temporaryItem"></param> /// <returns></returns> public Bin <Tuple> IsBestPositionFound(Bin <Tuple> temporaryBin, Item temporaryItem, string itemAllocationMethod) { //se l'item non è nestabile (ovvero le sue dimensioni eccedano quelle del bin) //setto comunque l'item come removed, altrimenti la lista di item non sarà mai empty e hsolve non va avanti /*if(temporaryItem.Height > temporaryBin.Height || temporaryItem.Width > temporaryBin.Width) * { * temporaryItem.IsRemoved = true; * return temporaryBin; * }*/ //item nestabile, procedo SetFeasiblePoints(temporaryBin); //se il bin non contiene punti if (temporaryBin.Points.Count == 0) { return(temporaryBin); } else if (temporaryBin.Points.Count == 1 && //se il bin contiene 1 solo punto e quel punto è (0,0) temporaryBin.Points.ElementAt(0).Pposition == 0 && temporaryBin.Points.ElementAt(0).Qposition == 0) { Item pricedItem = new Item() { Height = temporaryItem.Height, Width = temporaryItem.Width, Id = temporaryItem.Id, Price = temporaryItem.Price, TLqPosition = temporaryItem.Height, BRpPosition = temporaryItem.Width, TRpPosition = temporaryItem.Width, TRqPosition = temporaryItem.Height }; if (IsBorderObserved(pricedItem, temporaryBin.Height, temporaryBin.Width)) { temporaryBin.NestedItems = new List <Item> { pricedItem }; HandleOperationsPostNestedItem(temporaryBin, temporaryItem, temporaryBin.Points.ElementAt(0), pricedItem); } else { pricedItem = new Item() { Height = temporaryItem.Width, Width = temporaryItem.Height, Id = temporaryItem.Id, Price = temporaryItem.Price, TLqPosition = temporaryItem.Width, BRpPosition = temporaryItem.Height, TRpPosition = temporaryItem.Height, TRqPosition = temporaryItem.Width }; if (IsBorderObserved(pricedItem, temporaryBin.Height, temporaryBin.Width)) { temporaryBin.NestedItems = new List <Item> { pricedItem }; HandleOperationsPostNestedItem(temporaryBin, temporaryItem, temporaryBin.Points.ElementAt(0), pricedItem); } } //Console.WriteLine("item " + pricedItem.Id + "(" + pricedItem.Height + ", " + pricedItem.Width + ") nested in " // + temporaryBin.Points.ElementAt(0).PfinalPosition + ", " + // temporaryBin.Points.ElementAt(0).QfinalPosition + ", " + temporaryBin.Points.ElementAt(0).Rposition + " BIN " + temporaryBin.Id); return(temporaryBin); } else if (temporaryBin.Points.Count > 1)//se il bin contiene n punti { foreach (Tuple feasiblePoint in temporaryBin.Points) { if (!feasiblePoint.IsUsed) { Item newPricedItem = null; if (feasiblePoint.Rposition == 0) { //assegno le coordinate di partenza al nuovo item da nestare, poi inzio a muoverlo newPricedItem = new Item() { Height = temporaryItem.Height, Width = temporaryItem.Width, Id = temporaryItem.Id, Price = temporaryItem.Price, BLpPosition = feasiblePoint.Pposition, BLqPosition = feasiblePoint.Qposition, BRpPosition = feasiblePoint.Pposition + temporaryItem.Width, BRqPosition = feasiblePoint.Qposition, TLpPosition = feasiblePoint.Pposition, TLqPosition = feasiblePoint.Qposition + temporaryItem.Height, TRpPosition = feasiblePoint.Pposition + temporaryItem.Width, TRqPosition = feasiblePoint.Qposition + temporaryItem.Height }; } else if (feasiblePoint.Rposition == 1) { newPricedItem = new Item() { Height = temporaryItem.Width, Width = temporaryItem.Height, Id = temporaryItem.Id, Price = temporaryItem.Price, BLpPosition = feasiblePoint.Pposition, BLqPosition = feasiblePoint.Qposition, BRpPosition = feasiblePoint.Pposition + temporaryItem.Height, BRqPosition = feasiblePoint.Qposition, TLpPosition = feasiblePoint.Pposition, TLqPosition = feasiblePoint.Qposition + temporaryItem.Width, TRpPosition = feasiblePoint.Pposition + temporaryItem.Height, TRqPosition = feasiblePoint.Qposition + temporaryItem.Width }; } feasiblePoint.HatchedArea = GetHatchedArea(temporaryBin, newPricedItem, feasiblePoint); } } //trovo la tupla con lo scarto minore tra quelle ancora disponibili //(Where(x => x.HatchedArea >= 0) filtra solo le tuple con hatched area = 0) Tuple minHatchedAreaTuple = temporaryBin.Points.Where(x => x.IsUsed == false && x.HatchedArea >= 0) .OrderBy(x => x.HatchedArea) .FirstOrDefault(); //se non riesco a trovare la tupla, vuol dire che le tuple sono finite if (minHatchedAreaTuple == null) { return(temporaryBin); } //controllo se ho più tuple che hanno lo stesso scarto (il minore) IList <Tuple> minHatchedAreaPoints = new List <Tuple>(); foreach (Tuple point in temporaryBin.Points) { if (point.HatchedArea == minHatchedAreaTuple.HatchedArea && !point.IsUsed) { minHatchedAreaPoints.Add(point); } } if (minHatchedAreaPoints.Count == 1) { Tuple minHatchedAreaPoint = minHatchedAreaPoints.ElementAt(0); Item pricedItem = null; if (minHatchedAreaPoint.Rposition == 0) { pricedItem = new Item() { Height = temporaryItem.Height, Width = temporaryItem.Width, Id = temporaryItem.Id, Price = temporaryItem.Price, BLpPosition = minHatchedAreaPoint.PfinalPosition, BLqPosition = minHatchedAreaPoint.QfinalPosition, BRpPosition = minHatchedAreaPoint.PfinalPosition + temporaryItem.Width, BRqPosition = minHatchedAreaPoint.QfinalPosition, TLpPosition = minHatchedAreaPoint.PfinalPosition, TLqPosition = minHatchedAreaPoint.QfinalPosition + temporaryItem.Height, TRpPosition = minHatchedAreaPoint.PfinalPosition + temporaryItem.Width, TRqPosition = minHatchedAreaPoint.QfinalPosition + temporaryItem.Height }; } else if (minHatchedAreaPoint.Rposition == 1) { pricedItem = new Item() { Height = temporaryItem.Width, Width = temporaryItem.Height, Id = temporaryItem.Id, Price = temporaryItem.Price, BLpPosition = minHatchedAreaPoint.PfinalPosition, BLqPosition = minHatchedAreaPoint.QfinalPosition, BRpPosition = minHatchedAreaPoint.PfinalPosition + temporaryItem.Height, BRqPosition = minHatchedAreaPoint.QfinalPosition, TLpPosition = minHatchedAreaPoint.PfinalPosition, TLqPosition = minHatchedAreaPoint.QfinalPosition + temporaryItem.Width, TRpPosition = minHatchedAreaPoint.PfinalPosition + temporaryItem.Height, TRqPosition = minHatchedAreaPoint.QfinalPosition + temporaryItem.Width }; } //Console.WriteLine("item " + pricedItem.Id + "(" + pricedItem.Height + ", " + pricedItem.Width + ") nested in " // + minHatchedAreaPoint.PfinalPosition + ", " + //minHatchedAreaPoint.QfinalPosition + ", " + minHatchedAreaPoint.Rposition + " BIN " + temporaryBin.Id); temporaryBin.NestedItems.Add(pricedItem); HandleOperationsPostNestedItem(temporaryBin, temporaryItem, minHatchedAreaPoint, pricedItem); return(temporaryBin); } else if (minHatchedAreaPoints.Count > 1) { Tuple minCoordinatePoint = ApplyRule(minHatchedAreaPoints, itemAllocationMethod); Item pricedItem = null; if (minCoordinatePoint.Rposition == 0) { pricedItem = new Item() { Height = temporaryItem.Height, Width = temporaryItem.Width, Id = temporaryItem.Id, Price = temporaryItem.Price, BLpPosition = minCoordinatePoint.PfinalPosition, BLqPosition = minCoordinatePoint.QfinalPosition, BRpPosition = minCoordinatePoint.PfinalPosition + temporaryItem.Width, BRqPosition = minCoordinatePoint.QfinalPosition, TLpPosition = minCoordinatePoint.PfinalPosition, TLqPosition = minCoordinatePoint.QfinalPosition + temporaryItem.Height, TRpPosition = minCoordinatePoint.PfinalPosition + temporaryItem.Width, TRqPosition = minCoordinatePoint.QfinalPosition + temporaryItem.Height }; } else if (minCoordinatePoint.Rposition == 1) { pricedItem = new Item() { Height = temporaryItem.Width, Width = temporaryItem.Height, Id = temporaryItem.Id, Price = temporaryItem.Price, BLpPosition = minCoordinatePoint.PfinalPosition, BLqPosition = minCoordinatePoint.QfinalPosition, BRpPosition = minCoordinatePoint.PfinalPosition + temporaryItem.Height, BRqPosition = minCoordinatePoint.QfinalPosition, TLpPosition = minCoordinatePoint.PfinalPosition, TLqPosition = minCoordinatePoint.QfinalPosition + temporaryItem.Width, TRpPosition = minCoordinatePoint.PfinalPosition + temporaryItem.Height, TRqPosition = minCoordinatePoint.QfinalPosition + temporaryItem.Width }; } //Console.WriteLine("item " + pricedItem.Id + "(" + pricedItem.Height + ", " + pricedItem.Width + ") nested in " // + minCoordinatePoint.PfinalPosition + ", " + //minCoordinatePoint.QfinalPosition + ", " + minCoordinatePoint.Rposition + " BIN " + temporaryBin.Id); temporaryBin.NestedItems.Add(pricedItem); HandleOperationsPostNestedItem(temporaryBin, temporaryItem, minCoordinatePoint, pricedItem); return(temporaryBin); } } return(temporaryBin); }
public void Initialize(Configuration configuration, string pricingRule, IPricingUtilities PricingUtilities) { Sequences = new List <Sequence> { new Sequence(), new Sequence() }; //inizializzo il prezzo v associato ad ogni item j Items = new List <Item>(); Bins = new List <Bin>(); Counter = 0; foreach (Dimension dimension in configuration.Dimensions) { Item item = new Item() { Height = dimension.Height, Width = dimension.Width, Id = Counter, Price = PricingUtilities.ComputePricingRule(pricingRule, dimension.Height, dimension.Width) }; Items.Add(item); //inserisco ogni item prezzato e i nuovi punti disponibili //in un bin diverso Bin bin = new Bin() { Id = Counter, Height = configuration.BinHeight, Width = configuration.BinWidth, NestedItems = new List <Item>() { item }, Points = new List <Position>() { new Position() { Pposition = 0, Qposition = item.Height, Rposition = 0, IsUsed = false }, new Position() { Pposition = 0, Qposition = item.Height, Rposition = 1, IsUsed = false }, new Position() { Pposition = item.Width, Qposition = 0, Rposition = 0, IsUsed = false }, new Position() { Pposition = item.Width, Qposition = 0, Rposition = 1, IsUsed = false } } }; Bins.Add(bin); Counter += 1; } //inizializzo il costo della soluzione con il numero degli elementi Zstar = Counter; //inizializzo il numero di iterazioni Iter = 0; //calcolo il lower bound ed il relativo intervallo //double lowerBound; MaxIter = configuration.MaxIter; }
/// <summary> /// metodo per gestire le operazioni post item nestato /// </summary> /// <param name="temporaryBin"></param> /// <param name="temporaryItem"></param> /// <param name="point"></param> private void HandleOperationsPostNestedItem(Bin <Tuple> temporaryBin, Item sortedTemporaryItem, Tuple point, Item pricedItem) { //recupero il punto dalla lista usando l'id. tale punto lo setterò poi ad usato var matchingPoints = temporaryBin.Points.Where(x => x.Pposition == point.PfinalPosition && x.Qposition == point.QfinalPosition && x.PfinalPosition == point.PfinalPosition && x.QfinalPosition == point.QfinalPosition); //.FirstOrDefault(); //gestisco il fatto che ci possano essere più punti che portano alle stesse coordinate finali if (matchingPoints != null) { foreach (Tuple matchingPoint in matchingPoints) { matchingPoint.IsUsed = true; } } else { matchingPoints = temporaryBin.Points.Where(x => x.PfinalPosition == point.PfinalPosition && x.QfinalPosition == point.QfinalPosition); //.FirstOrDefault(); foreach (Tuple matchingPoint in matchingPoints) { matchingPoint.IsUsed = true; } } //=============================================== //controllo se non è più possibile usare dei punti foreach (Tuple p in temporaryBin.Points) { foreach (Tuple matchingPoint in matchingPoints) { //cerco punti "coperti" dal nuovo item nestato if ((p.Pposition >= pricedItem.BLpPosition && p.Pposition < pricedItem.BRpPosition && p.Qposition >= pricedItem.BLqPosition && p.Qposition < pricedItem.TLqPosition) || (p.PfinalPosition == matchingPoint.PfinalPosition && //cerco punti che, dopo push down and left portavano alle stesse coordinate finali p.QfinalPosition == matchingPoint.QfinalPosition && pricedItem.BRpPosition >= p.Pposition && pricedItem.TLqPosition >= p.Qposition)) { p.IsUsed = true; } } } //controllo se il primo nuovo punto (TL) da aggiungere è già presente nella lista temporaryBin.Points e non è statao usato Tuple pointFound = temporaryBin.Points.Where(x => x.Pposition == point.PfinalPosition && x.Qposition == point.QfinalPosition + pricedItem.Height && x.IsUsed == false).FirstOrDefault(); //definisco il primo nuovo punto Tuple firstPoint = new Tuple() { Pposition = point.PfinalPosition, Qposition = point.QfinalPosition + pricedItem.Height, Rposition = 0, IsUsed = false }; //controllo se il primo nuovo punto è idoneo ad essere aggiunto perché //potrebbe essere erroneaemente creato sul lato di un item già in soluzione bool isPointLyingOnItemSide = false; foreach (Item ni in temporaryBin.NestedItems) { if (firstPoint.Qposition == ni.BLqPosition && firstPoint.Pposition > ni.BLpPosition && firstPoint.Pposition < ni.BRpPosition) { isPointLyingOnItemSide = true; break; } } //aggiungo il primo nuovo punto if (pointFound == null && !isPointLyingOnItemSide) { temporaryBin.Points.Add(firstPoint); firstPoint = new Tuple() { Pposition = point.PfinalPosition, Qposition = point.QfinalPosition + pricedItem.Height, Rposition = 1, IsUsed = false }; temporaryBin.Points.Add(firstPoint); } else { pointFound = null; } isPointLyingOnItemSide = false; //controllo se il secondo nuovo punto (BR) da aggiungere è già presente nella lista temporaryBin.Points e non è statao usato pointFound = temporaryBin.Points.Where(x => x.Pposition == point.PfinalPosition + pricedItem.Width && x.Qposition == point.QfinalPosition && x.IsUsed == false).FirstOrDefault(); //definisco il secondo nuovo punto Tuple secondPoint = new Tuple() { Pposition = point.PfinalPosition + pricedItem.Width, Qposition = point.QfinalPosition, Rposition = 0, IsUsed = false }; //controllo se il secondo nuovo punto è idoneo ad essere aggiunto perché //potrebbe essere erroneaemente creato sul lato di un item già esistente foreach (Item ni in temporaryBin.NestedItems) { if (secondPoint.Pposition == ni.BLpPosition && secondPoint.Qposition > ni.BLqPosition && secondPoint.Qposition < ni.TLqPosition) { isPointLyingOnItemSide = true; break; } } //aggiungo il secondo nuovo punto if (pointFound == null && !isPointLyingOnItemSide) { temporaryBin.Points.Add(secondPoint); secondPoint = new Tuple() { Pposition = point.PfinalPosition + pricedItem.Width, Qposition = point.QfinalPosition, Rposition = 1, IsUsed = false }; temporaryBin.Points.Add(secondPoint); } //setto item a nestato sortedTemporaryItem.IsRemoved = true; }