/// <summary> /// metodo per controllare se nestare un nuovo item in un certo punto /// comporta delle sovrapposizioni tra nuovo item e item già in soluzione /// </summary> /// <param name="newPricedItem"></param> /// <param name="temporaryBin"></param> /// <returns></returns> bool IsOverlappingOk(PricedItem newPricedItem, Bin <Tuple> temporaryBin) { foreach (var pricedItem in temporaryBin.PricedItems) { //se c'è overlap if (pricedItem.BLpPosition < newPricedItem.BRpPosition && pricedItem.BRpPosition > newPricedItem.BLpPosition && pricedItem.BLqPosition < newPricedItem.TLqPosition && pricedItem.TLqPosition > newPricedItem.BLqPosition) { return(false); } } return(true); }
/// <summary> /// metodo che spinge il più in basso possibile /// il nuovo item da nestare /// </summary> /// <param name="feasiblePoint"></param> /// <param name="temporaryBin"></param> /// <param name="temporaryItem"></param> /// <param name="newNestedItem"></param> /// <returns></returns> private IList <PricedItem> PushItemDown(Bin <Tuple> temporaryBin, PricedItem newPricedItem, Tuple feasiblePoint) { //lista delle intersezioni tra item nuovo e item già in soluzione IList <PricedItem> intersectedPricedItems = new List <PricedItem>(); foreach (var pricedItem in temporaryBin.PricedItems) { //cerco intersezioni verticali tra nuovo item e item già in soluzione (HO TOLTO UGUALE DESTRA -> CHECK) if (((newPricedItem.BLpPosition >= pricedItem.BLpPosition && newPricedItem.BLpPosition < pricedItem.BRpPosition) || (newPricedItem.BRpPosition > pricedItem.BLpPosition && newPricedItem.BRpPosition <= pricedItem.BRpPosition) || (newPricedItem.BLpPosition <= pricedItem.TLpPosition && newPricedItem.BRpPosition >= pricedItem.TRpPosition) || //le p di OI cadono dentro le p di NI o le p di OI sono uguali alle p di NI (newPricedItem.BLpPosition > pricedItem.TLpPosition && newPricedItem.BRpPosition < pricedItem.TRpPosition) //le p di NI cadono dentro le p di OI ) && newPricedItem.BLqPosition >= pricedItem.TLqPosition) { intersectedPricedItems.Add(pricedItem); } } //3 possibili risultati if (intersectedPricedItems.Count == 0) //non ho intersezioni { newPricedItem.BLqPosition = 0; newPricedItem.TLqPosition = newPricedItem.Height; newPricedItem.BRqPosition = 0; newPricedItem.TRqPosition = newPricedItem.Height; } else { if (intersectedPricedItems.Count == 1) //1 sola intersezione { float delta = feasiblePoint.Qposition - intersectedPricedItems.ElementAt(0).Height; newPricedItem.BLqPosition -= delta; newPricedItem.TLqPosition -= delta; newPricedItem.BRqPosition -= delta; newPricedItem.TRqPosition -= delta; } else if (intersectedPricedItems.Count > 1) //N intersezioni { float heightSum = intersectedPricedItems.OrderBy(x => x.TLqPosition).Last().TLqPosition; float delta = feasiblePoint.Qposition - heightSum; newPricedItem.BLqPosition -= delta; newPricedItem.TLqPosition -= delta; newPricedItem.BRqPosition -= delta; newPricedItem.TRqPosition -= delta; } } feasiblePoint.QfinalPosition = newPricedItem.BLqPosition; return(intersectedPricedItems); }
/// <summary> /// il metodo che spinge il più a sinistra possibile /// il nuovo item da nestare /// </summary> /// <param name="feasiblePoint"></param> /// <param name="temporaryBin"></param> /// <param name="temporaryItem"></param> /// <param name="newNestedItem"></param> /// <returns></returns> private IList <PricedItem> PushItemLeft(Bin <Tuple> temporaryBin, PricedItem newPricedItem, Tuple feasiblePoint) { //lista delle intersezioni tra item nuovo e item già in soluzione IList <PricedItem> intersectedPricedItems = new List <PricedItem>(); foreach (var pricedItem in temporaryBin.PricedItems) { //cerco interesezioni orizzontali tra nuovo item e item già in soluzione (HO TOLTO UGUALE DESTRA -> CHECK) if (((newPricedItem.BLqPosition >= pricedItem.BLqPosition && newPricedItem.BLqPosition < pricedItem.TLqPosition) || (newPricedItem.TLqPosition > pricedItem.BLqPosition && newPricedItem.TLqPosition <= pricedItem.TLqPosition) || (newPricedItem.BLqPosition <= pricedItem.BRqPosition && newPricedItem.TLqPosition >= pricedItem.TRqPosition) || //le coord q di OI cadono entrambe dentro a NI o sono uguali (newPricedItem.BLqPosition > pricedItem.BRqPosition && newPricedItem.TLqPosition < pricedItem.TRqPosition) //le coord q di NI cadono entrambe dentro OI ) && newPricedItem.BLpPosition >= pricedItem.BRpPosition) { intersectedPricedItems.Add(pricedItem); } } //3 possibili risultati if (intersectedPricedItems.Count == 0) //non ho intersezioni { newPricedItem.BLpPosition = 0; newPricedItem.TLpPosition = 0; newPricedItem.BRpPosition = newPricedItem.Width; newPricedItem.TRpPosition = newPricedItem.Width; } else { if (intersectedPricedItems.Count == 1) //1 sola intersezione { float delta = feasiblePoint.Pposition - intersectedPricedItems.ElementAt(0).Width; newPricedItem.BLpPosition -= delta; newPricedItem.TLpPosition -= delta; newPricedItem.BRpPosition -= delta; newPricedItem.TRpPosition -= delta; } else if (intersectedPricedItems.Count > 1) //N intersezioni { float widthSum = intersectedPricedItems.OrderBy(x => x.BRpPosition).Last().BRpPosition; float delta = feasiblePoint.Pposition - widthSum; newPricedItem.BLpPosition -= delta; newPricedItem.TLpPosition -= delta; newPricedItem.BRpPosition -= delta; newPricedItem.TRpPosition -= delta; } } feasiblePoint.PfinalPosition = newPricedItem.BLpPosition; return(intersectedPricedItems); }
/// <summary> /// metodo che calcola l'hatched area totale relativa /// al posizionamento di un nuovo item e la ritorna. /// il metodo ritorna -1 se l'item, per come è posizionato (cioè dopo averlo spinto /// in basso a sinistra), eccede le dimensioni del bin /// </summary> /// <param name="feasiblePoint"></param> /// <param name="newNestedItem"></param> /// <param name="temporaryBin"></param> /// <param name="temporaryItem"></param> /// <returns></returns> private float GetHatchedArea(Bin <Tuple> temporaryBin, PricedItem newPricedItem, Tuple feasiblePoint) { PushItemDown(temporaryBin, newPricedItem, feasiblePoint); IList <PricedItem> leftIntersectedPricedItems = PushItemLeft(temporaryBin, newPricedItem, feasiblePoint); //conto il numero di intersezioni che ho da sotto, perché potrebbero cambiare (da quelle inzialemnte trovate con //la prima invocazione di PushItemDown) dopo aver spinto l'item tutto a sinistra IList <PricedItem> downIntersectedPricedItems = CheckDownInsersectionNumber(temporaryBin, newPricedItem, feasiblePoint); //controllo se l'oggetto, anche essendo stato spostato in basso a sintra, sborderebbe e //se la posizione in cui deve essere nestato il nuovo item comporterebbe delle sovrapposizioni con item già in soluzione if (IsBorderObserved(newPricedItem, temporaryBin.Height, temporaryBin.Width) && IsOverlappingOk(newPricedItem, temporaryBin)) { ComputeHatchedArea(feasiblePoint, newPricedItem, downIntersectedPricedItems, leftIntersectedPricedItems); //Console.WriteLine("(" + feasiblePoint.Pposition + ", " + feasiblePoint.Qposition + "), HR = " + feasiblePoint.HatchedArea + //", new coord(" + feasiblePoint.PfinalPosition + ", " + feasiblePoint.QfinalPosition + ")"); return(feasiblePoint.HatchedArea); } else { return(-1); } }
/// <summary> /// metodo che computa l'euristica di hsolve /// </summary> public IList <Sequence> ComputeHeuristic() { IUtilities utilities = new Utilities(); //================ STEP 1 - INITIALIZATION ================ //inizializzo il prezzo v associato ad ogni item j IList <PricedItem> pricedItems = new List <PricedItem>(); int counter = 0; foreach (var dimension in Configuration.Dimensions) { var pricedItem = new PricedItem() { Height = dimension.Height, Width = dimension.Width, Id = counter, Price = dimension.Height * dimension.Width, }; pricedItems.Add(pricedItem); counter += 1; } IList <Bin <Tuple> > bins = new List <Bin <Tuple> >(); counter = 0; //inserisco ogni item prezzato e i nuovi punti disponibili //in un bin diverso foreach (var pricedItem in pricedItems) { var bin = new Bin <Tuple>() { Id = counter, Height = Configuration.BinHeight, Width = Configuration.BinWidth, PricedItems = new List <PricedItem>() { pricedItems.ElementAt(counter) }, Points = new List <Tuple>() { new Tuple() { Pposition = 0, Qposition = pricedItem.Height, IsUsed = false }, new Tuple() { Pposition = pricedItem.Width, Qposition = 0, IsUsed = false } } }; bins.Add(bin); counter += 1; } int itemNumber = counter + 1; counter = 0; //inizializzo il costo della soluzione con il numero degli elementi int zStar = itemNumber; //inizializzo il numero di iterazioni int iter = 0; //calcolo il lower bound ed il relativo intervallo float lowerBound = utilities.ComputeLowerBound(pricedItems, Configuration.BinWidth, Configuration.BinHeight); float lowerBoundMin = lowerBound - Configuration.LowerBoundDelta; float lowerBoundMax = lowerBound + Configuration.LowerBoundDelta; int maxIter = Configuration.MaxIter; //================ STEP 2 - ERASE THE CURRENT SOLUTION ================ l3: /*Sequence sequence = new Sequence() * { * Bins = new List<Bin<Tuple>>() * };*/ //creo una lista temporanea J' di item IList <PricedItem> temporaryPricedItems = new List <PricedItem>(); //assegno la lista di item J a J' temporaryPricedItems = pricedItems; //setto il bin che considero al momento int i = 0; //creo tanti bin temporanei quanti sono gli item IList <Bin <Tuple> > temporaryBins = new List <Bin <Tuple> >(); foreach (var pricedItem in pricedItems) { var temporaryBin = new Bin <Tuple>() { Id = counter, Height = Configuration.BinHeight, Width = Configuration.BinWidth, PricedItems = null, Points = new List <Tuple>() { new Tuple() { Pposition = 0, Qposition = 0, IsUsed = false } } }; temporaryBins.Add(temporaryBin); counter += 1; } //1) ogni volta che inizio una nuova iterazione iter devo riordinare gli item per price decrescente //dato che i price sono stati aggiornati; //2) riattribuisco gli id agli item, così l'item col prezzo maggiore è quello che ha l'id 0 e così via var sortedTemporaryPricedItems = new List <PricedItem>(); counter = 0; foreach (var temporaryPricedItem in temporaryPricedItems.OrderByDescending(x => x.Price)) { sortedTemporaryPricedItems.Add(temporaryPricedItem); temporaryPricedItem.Id = counter; counter += 1; } //================ STEP 3 - FILLING UP BIN i ================ l1: //cerco la posizione migliore per ogni item j' foreach (var sortedTemporaryPricedItem in sortedTemporaryPricedItems) { if (!sortedTemporaryPricedItem.IsRemoved) { utilities.IsBestPositionFound(temporaryBins.ElementAt(i), sortedTemporaryPricedItem); //salvo un bin nuovo ogni volta che viene aggiunto un elemento /*var tempItem = temporaryBins[i]; * Bin<Tuple> b; * * if (tempItem.PricedItems != null) * { * * b = new Bin<Tuple> * { * Id = tempItem.Id, * Height = tempItem.Height, * Width = tempItem.Width, * Points = new List<Tuple>(tempItem.Points), * PricedItems = new List<PricedItem>(tempItem.PricedItems) * }; * } * else * { * b = new Bin<Tuple> * { * Id = tempItem.Id, * Height = tempItem.Height, * Width = tempItem.Width, * Points = new List<Tuple>(tempItem.Points), * PricedItems = new List<PricedItem>() * }; * } * * sequence.Bins.Add(b);*/ } } //================ STEP 4 - CHECK IF ALL ITEMS HAVE BEEN ALLOCATED ================ int z = i; bool isSortedTemporaryPricedItemsEmpty = true; //controllo se tutta la lista è stata svuotata foreach (var sortedTemporaryPricedItem in sortedTemporaryPricedItems) { if (sortedTemporaryPricedItem.IsRemoved == false) { isSortedTemporaryPricedItemsEmpty = false; break; } } if (isSortedTemporaryPricedItemsEmpty) { //Sequences.Add(sequence); goto l0; } if (!isSortedTemporaryPricedItemsEmpty && (i < (zStar))) { i += 1; goto l1; } goto l2; //================ STEP 5 - UPDATE THE BEST SOLUTION ================ l0 : zStar = z; bins = temporaryBins; Sequence sequence1 = new Sequence() { Bins = new List <Bin <Tuple> >() }; sequence1.Bins = bins; Sequences.Add(sequence1); //================ STEP 6 - CHECK OPTIMALITY ================ //guardo se il costo della soluzione è compreso nell'intervallo del lower bound if (zStar > lowerBoundMin && zStar < lowerBoundMax) { goto end; } //================ STEP 7 - UPDATE THE ITEM PRICES ================ l2 : if (iter == maxIter) { goto end; } else { utilities.UpdatePrice(z, pricedItems, bins); iter += 1; //rimetto tutti gli item come isRemoved = false perché cominicio una nuova iterazione foreach (var pricedItem in pricedItems) { pricedItem.IsRemoved = false; } goto l3; } end: Sequence sequence2 = new Sequence() { Bins = new List <Bin <Tuple> >() }; sequence2.Bins = bins; Sequences.Add(sequence2); Sequence firstSequence = Sequences.FirstOrDefault(); Sequence lastSequence = Sequences.LastOrDefault(); Sequences.Clear(); Sequences.Add(firstSequence); Sequences.Add(lastSequence); return(Sequences); }
/// <summary> /// metodo che controlla se, a fronte del posizione del nuovo item da nestare, /// le dimensioni di tale item sforano rispetto alle dimensioni del bin /// </summary> /// <param name="newNestedItem"></param> /// <param name="temporaryBinHeight"></param> /// <param name="temporaryBinWidth"></param> /// <returns></returns> bool IsBorderObserved(PricedItem newPricedItem, float temporaryBinHeight, float temporaryBinWidth) { return(newPricedItem.TLqPosition <= temporaryBinHeight && newPricedItem.BRpPosition <= temporaryBinWidth); }
private IList <PricedItem> CheckDownInsersectionNumber(Bin <Tuple> temporaryBin, PricedItem newPricedItem, Tuple feasiblePoint) { //lista delle intersezioni tra item nuovo e item già in soluzione IList <PricedItem> intersectedPricedItems = new List <PricedItem>(); foreach (var pricedItem in temporaryBin.PricedItems) { //cerco intersezioni verticali tra nuovo item e item già in soluzione (HO TOLTO UGUALE DESTRA -> CHECK) if (((newPricedItem.BLpPosition >= pricedItem.BLpPosition && newPricedItem.BLpPosition < pricedItem.BRpPosition) || (newPricedItem.BRpPosition > pricedItem.BLpPosition && newPricedItem.BRpPosition <= pricedItem.BRpPosition) || (newPricedItem.BLpPosition <= pricedItem.TLpPosition && newPricedItem.BRpPosition >= pricedItem.TRpPosition) || //le p di OI cadono dentro le p di NI o le p di OI sono uguali alle p di NI (newPricedItem.BLpPosition > pricedItem.TLpPosition && newPricedItem.BRpPosition < pricedItem.TRpPosition) //le p di NI cadono dentro le p di OI ) && newPricedItem.BLqPosition >= pricedItem.TLqPosition) { intersectedPricedItems.Add(pricedItem); } } return(intersectedPricedItems); }
/// <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, PricedItem temporaryPricedItem) { //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 (temporaryPricedItem.Height > temporaryBin.Height || temporaryPricedItem.Width > temporaryBin.Width) { temporaryPricedItem.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) { temporaryBin.PricedItems = new List <PricedItem>() { new PricedItem() { Height = temporaryPricedItem.Height, Width = temporaryPricedItem.Width, Id = temporaryPricedItem.Id, Price = temporaryPricedItem.Price, TLqPosition = temporaryPricedItem.Height, BRpPosition = temporaryPricedItem.Width, TRpPosition = temporaryPricedItem.Width, TRqPosition = temporaryPricedItem.Height } }; HandleOperationsPostNestedItem(temporaryBin, temporaryPricedItem, temporaryBin.Points.ElementAt(0)); return(temporaryBin); } else if (temporaryBin.Points.Count > 1)//se il bin contiene n punti { foreach (var feasiblePoint in temporaryBin.Points) { if (!feasiblePoint.IsUsed) { //assegno le coordinate di partenza al nuovo item da nestare, poi inzio a muoverlo PricedItem newPricedItem = new PricedItem() { Height = temporaryPricedItem.Height, Width = temporaryPricedItem.Width, Id = temporaryPricedItem.Id, Price = temporaryPricedItem.Price, BLpPosition = feasiblePoint.Pposition, BLqPosition = feasiblePoint.Qposition, BRpPosition = feasiblePoint.Pposition + temporaryPricedItem.Width, BRqPosition = feasiblePoint.Qposition, TLpPosition = feasiblePoint.Pposition, TLqPosition = feasiblePoint.Qposition + temporaryPricedItem.Height, TRpPosition = feasiblePoint.Pposition + temporaryPricedItem.Width, TRqPosition = feasiblePoint.Qposition + temporaryPricedItem.Height }; 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 (var point in temporaryBin.Points) { if (point.HatchedArea == minHatchedAreaTuple.HatchedArea && !point.IsUsed) { minHatchedAreaPoints.Add(point); } } if (minHatchedAreaPoints.Count == 1) { var minHatchedAreaPoint = minHatchedAreaPoints.ElementAt(0); var pricedItem = new PricedItem() { Height = temporaryPricedItem.Height, Width = temporaryPricedItem.Width, Id = temporaryPricedItem.Id, Price = temporaryPricedItem.Price, BLpPosition = minHatchedAreaPoint.PfinalPosition, BLqPosition = minHatchedAreaPoint.QfinalPosition, BRpPosition = minHatchedAreaPoint.PfinalPosition + temporaryPricedItem.Width, BRqPosition = minHatchedAreaPoint.QfinalPosition, TLpPosition = minHatchedAreaPoint.PfinalPosition, TLqPosition = minHatchedAreaPoint.QfinalPosition + temporaryPricedItem.Height, TRpPosition = minHatchedAreaPoint.PfinalPosition + temporaryPricedItem.Width, TRqPosition = minHatchedAreaPoint.QfinalPosition + temporaryPricedItem.Height }; temporaryBin.PricedItems.Add(pricedItem); HandleOperationsPostNestedItem(temporaryBin, temporaryPricedItem, minHatchedAreaPoint); return(temporaryBin); } else if (minHatchedAreaPoints.Count > 1) { Tuple minCoordinatePoint = ApplyRule(minHatchedAreaPoints); var pricedItem = new PricedItem() { Height = temporaryPricedItem.Height, Width = temporaryPricedItem.Width, Id = temporaryPricedItem.Id, Price = temporaryPricedItem.Price, BLpPosition = minCoordinatePoint.PfinalPosition, BLqPosition = minCoordinatePoint.QfinalPosition, BRpPosition = minCoordinatePoint.PfinalPosition + temporaryPricedItem.Width, BRqPosition = minCoordinatePoint.QfinalPosition, TLpPosition = minCoordinatePoint.PfinalPosition, TLqPosition = minCoordinatePoint.QfinalPosition + temporaryPricedItem.Height, TRpPosition = minCoordinatePoint.PfinalPosition + temporaryPricedItem.Width, TRqPosition = minCoordinatePoint.QfinalPosition + temporaryPricedItem.Height }; temporaryBin.PricedItems.Add(pricedItem); HandleOperationsPostNestedItem(temporaryBin, temporaryPricedItem, minCoordinatePoint); return(temporaryBin); } } return(temporaryBin); }
/// <summary> /// metodo che calcola l'hatched area prima sotto /// e poi a sinistra del nuovo item /// </summary> /// <param name="downIntersectedNestedItems"></param> /// <param name="leftIntersectedNestedItems"></param> /// <returns></returns> /// private void ComputeHatchedArea(Tuple feasiblePoint, PricedItem newPricedItem, IList <PricedItem> downIntersectedNestedItems, IList <PricedItem> leftIntersectedNestedItems) { float totalHatchedArea = 0; //variabile per l'hatched area che eventualmente rimane sotto e a sinitra float partialHatchedArea; if (downIntersectedNestedItems.Count > 0) { //definiso la green area sotto il nuovo item AdjacentItem adjacentItem = new AdjacentItem() { BRpPosition = feasiblePoint.PfinalPosition + newPricedItem.Width, BRqPosition = 0, TRpPosition = feasiblePoint.PfinalPosition + newPricedItem.Width, TRqPosition = feasiblePoint.QfinalPosition, BLpPosition = feasiblePoint.PfinalPosition, BLqPosition = 0, TLpPosition = feasiblePoint.PfinalPosition, TLqPosition = feasiblePoint.QfinalPosition, Height = newPricedItem.BRqPosition, Width = newPricedItem.Width, Area = newPricedItem.BRqPosition * newPricedItem.Width }; //per ogni item già in posizione, che è stato intersecato, //calcolo quanta parte di area di esso rientra nella green area e //infine sommo tale area all'area totale degli item intersecati float itemsInSolutionArea = 0; float intersectedWidth; foreach (var intersectedItem in downIntersectedNestedItems) { //if else per scegliere la width dell'item in soluzione //di cui devo calcolare l'area //per fare valore assoluto Math.Abs( ... ); if (newPricedItem.BLpPosition < intersectedItem.BLpPosition && //new item + a sx di interesect item newPricedItem.BRpPosition < intersectedItem.BRpPosition) { intersectedWidth = newPricedItem.BRpPosition - intersectedItem.BLpPosition; } else if (intersectedItem.BLpPosition < newPricedItem.BLpPosition && //new item è + a dx di intersected item intersectedItem.BRpPosition < newPricedItem.BRpPosition) { intersectedWidth = intersectedItem.BRpPosition - newPricedItem.BLpPosition; } else if ((newPricedItem.BLpPosition == intersectedItem.BLpPosition && //new item inizia come insertected item ma termina prima newPricedItem.BRpPosition < intersectedItem.BRpPosition) || (intersectedItem.BLpPosition < newPricedItem.BLpPosition && // new item inizia dopo di insertected item ma terminano uguali intersectedItem.BRpPosition == newPricedItem.BRpPosition) || (intersectedItem.BLpPosition < newPricedItem.BLpPosition && //le coordinate p del new item cadono dentro quelle p dell'intersected item intersectedItem.BRpPosition > newPricedItem.BRpPosition)) { intersectedWidth = adjacentItem.Width; } else { intersectedWidth = intersectedItem.Width; } itemsInSolutionArea += (intersectedItem.Height * intersectedWidth); } partialHatchedArea = adjacentItem.Area - itemsInSolutionArea; totalHatchedArea += partialHatchedArea; } if (leftIntersectedNestedItems.Count > 0) { //definiso la green area a sintra del nuovo item AdjacentItem adjacentItem = new AdjacentItem() { BRpPosition = feasiblePoint.PfinalPosition, BRqPosition = feasiblePoint.QfinalPosition, TRpPosition = feasiblePoint.PfinalPosition, TRqPosition = feasiblePoint.QfinalPosition + newPricedItem.Height, BLpPosition = 0, BLqPosition = feasiblePoint.QfinalPosition, TLpPosition = 0, TLqPosition = feasiblePoint.QfinalPosition + newPricedItem.Height, Height = newPricedItem.Height, Width = newPricedItem.BLpPosition, Area = newPricedItem.Height * newPricedItem.BLpPosition }; //per ogni item già in posizione, che è stato intersecato, //calcolo quanta parte di area di esso rientra nella green area e //infine sommo tale area all'area totale degli item intersecati float itemsInSolutionArea = 0; float intersectedHeight; foreach (var intersectedItem in leftIntersectedNestedItems) { //if else per scegliere la height dell'item in soluzione //di cui devo calcolare l'area //per fare valore assoluto Math.Abs( ... ); if (intersectedItem.BLqPosition < newPricedItem.BLqPosition && //new item + in alto di intersected item intersectedItem.TLqPosition < newPricedItem.TLqPosition) { intersectedHeight = intersectedItem.TLqPosition - newPricedItem.BLqPosition; } else if (newPricedItem.BLqPosition < intersectedItem.BLqPosition && //new item + in basso di interesect item newPricedItem.TLqPosition < intersectedItem.TLqPosition) { intersectedHeight = newPricedItem.TLqPosition - intersectedItem.BLqPosition; } else if ((newPricedItem.BLqPosition == intersectedItem.BLqPosition && //new item inizia come insertected item ma termina prima newPricedItem.TLqPosition < intersectedItem.TLqPosition) || (intersectedItem.BLqPosition < newPricedItem.BLqPosition && // new item inizia dopo di insertected item ma terminano uguali intersectedItem.TLqPosition == newPricedItem.TLqPosition) || (intersectedItem.BLqPosition < newPricedItem.BLqPosition && //le coordinate q del new item cadono dentro quelle dell'intersected item intersectedItem.TLqPosition > newPricedItem.TLqPosition)) { intersectedHeight = adjacentItem.Height; } else { intersectedHeight = intersectedItem.Height; } itemsInSolutionArea += (intersectedHeight * intersectedItem.Width); } partialHatchedArea = adjacentItem.Area - itemsInSolutionArea; totalHatchedArea += partialHatchedArea; } feasiblePoint.HatchedArea = totalHatchedArea; }
/// <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, PricedItem sortedTemporaryPricedItem, Tuple point) { //setto il punto ad usato, per recuparare il punto dalla lista uso l'id var matchingPoint = temporaryBin.Points.Where(x => x.Pposition == point.Pposition && x.Qposition == point.Qposition) .First(); matchingPoint.IsUsed = true; //controllo se non è più possibile usare dei punti foreach (var p in temporaryBin.Points) { //cerco punti "coperti" dal nuovo item nestato if ((p.Pposition >= sortedTemporaryPricedItem.BLpPosition && p.Pposition < sortedTemporaryPricedItem.BRpPosition && p.Qposition >= sortedTemporaryPricedItem.BLqPosition && p.Qposition < sortedTemporaryPricedItem.TLqPosition) || (p.PfinalPosition == matchingPoint.PfinalPosition && //cerco punti che, dopo push down and left portavano alle stesse coordinate finali p.QfinalPosition == matchingPoint.QfinalPosition && sortedTemporaryPricedItem.BRpPosition >= p.Pposition && sortedTemporaryPricedItem.TLqPosition >= p.Qposition)) { p.IsUsed = true; } } //controllo se il primo nuovo punto (TL) da aggiungere è già presente nella lista temporaryBin.Points Tuple pointFound = temporaryBin.Points.Where(x => x.Pposition == point.PfinalPosition && x.Qposition == point.QfinalPosition + sortedTemporaryPricedItem.Height && x.IsUsed == false).FirstOrDefault(); //definisco il primo nuovo punto var firstPoint = new Tuple() { Pposition = point.PfinalPosition, Qposition = point.QfinalPosition + sortedTemporaryPricedItem.Height, 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 (var ni in temporaryBin.PricedItems) { 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); } else { pointFound = null; } isPointLyingOnItemSide = false; //controllo se il secondo nuovo punto (BR) da aggiungere è già presente nella lista temporaryBin.Points pointFound = temporaryBin.Points.Where(x => x.Pposition == point.PfinalPosition + sortedTemporaryPricedItem.Width && x.Qposition == point.QfinalPosition).FirstOrDefault(); //definisco il secondo nuovo punto var secondPoint = new Tuple() { Pposition = point.PfinalPosition + sortedTemporaryPricedItem.Width, Qposition = point.QfinalPosition, 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 (var ni in temporaryBin.PricedItems) { 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); } //setto item a nestato sortedTemporaryPricedItem.IsRemoved = true; }