/// <summary> /// questo metodo calcola l'hatched area in basso e a sinistra dell'item. /// Infine, ritorna la somma delle due. /// Ritorna -1 se l'item, per come è posizionato, 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(Tuple feasiblePoint, NestedItem newNestedItem, Bin <Tuple> temporaryBin, Item temporaryItem) { float downtHatchedArea = PushItemDown(feasiblePoint, temporaryBin, temporaryItem, newNestedItem); float leftHatchedArea = PushItemLeft(feasiblePoint, temporaryBin, temporaryItem, newNestedItem); //controllo se l'oggettto, anche essendo stato spostato in basso a sintra, sborda if (IsBorderObserved(newNestedItem, temporaryBin.Height, temporaryBin.Width)) { return(downtHatchedArea + leftHatchedArea); } else { return(-1); } }
/// <summary> /// Questo metodo controlla se le dimensione dell'item eccedono quelle del bin /// </summary> /// <param name="newNestedItem"></param> /// <param name="temporaryBinHeight"></param> /// <param name="temporaryBinWidth"></param> /// <returns></returns> bool IsBorderObserved(NestedItem newNestedItem, float temporaryBinHeight, float temporaryBinWidth) { return(newNestedItem.TLqPosition <= temporaryBinHeight && newNestedItem.BRpPosition <= temporaryBinWidth); }
/// <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 bool IsBestPositionFound(Bin <Tuple> temporaryBin, Item temporaryItem) { SetFeasiblePoints(temporaryBin, temporaryItem); //se il bin non contiene punti if (temporaryBin.Points.Count == 0) { return(false); } 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.NestedItems = new List <NestedItem> { new NestedItem(temporaryItem) { BLpPosition = 0, BLqPosition = 0, BRpPosition = temporaryItem.Width, BRqPosition = 0, TLpPosition = 0, TLqPosition = temporaryItem.Height } }; HandleOperationsPostNestedItem(temporaryBin, temporaryItem, temporaryBin.Points.ElementAt(0)); return(true); } 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 NestedItem newNestedItem = new NestedItem(temporaryItem) { BLpPosition = feasiblePoint.Pposition, BLqPosition = feasiblePoint.Qposition, BRpPosition = feasiblePoint.Pposition + temporaryItem.Width, BRqPosition = feasiblePoint.Qposition, TLpPosition = feasiblePoint.Pposition, TLqPosition = feasiblePoint.Qposition + temporaryItem.Height }; feasiblePoint.HatchedArea = GetHatchedArea(feasiblePoint, newNestedItem, temporaryBin, temporaryItem); } } //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) .First(); //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); temporaryBin.NestedItems.Add(new NestedItem(temporaryItem) { BLpPosition = minHatchedAreaPoint.PfinalPosition, BLqPosition = minHatchedAreaPoint.QfinalPosition, BRpPosition = minHatchedAreaPoint.PfinalPosition + temporaryItem.Width, BRqPosition = minHatchedAreaPoint.QfinalPosition, TLpPosition = minHatchedAreaPoint.PfinalPosition, TLqPosition = minHatchedAreaPoint.QfinalPosition + temporaryItem.Height }); HandleOperationsPostNestedItem(temporaryBin, temporaryItem, minHatchedAreaPoint); return(true); } else if (minHatchedAreaPoints.Count > 1) { Tuple minCoordinatePoint = ApplyRule(minHatchedAreaPoints); temporaryBin.NestedItems.Add(new NestedItem(temporaryItem) { BLpPosition = minCoordinatePoint.PfinalPosition, BLqPosition = minCoordinatePoint.QfinalPosition, BRpPosition = minCoordinatePoint.PfinalPosition + temporaryItem.Width, BRqPosition = minCoordinatePoint.QfinalPosition, TLpPosition = minCoordinatePoint.PfinalPosition, TLqPosition = minCoordinatePoint.QfinalPosition + temporaryItem.Height }); HandleOperationsPostNestedItem(temporaryBin, temporaryItem, minCoordinatePoint); return(true); } } return(false); }
/// <summary> /// questo metodo spinge a sinistra un nuovo item e /// calcolo l'hatched area a sinistra del nuovo iten /// </summary> /// <param name="feasiblePoint"></param> /// <param name="temporaryBin"></param> /// <param name="temporaryItem"></param> /// <param name="newNestedItem"></param> /// <returns></returns> private float PushItemLeft(Tuple feasiblePoint, Bin <Tuple> temporaryBin, Item temporaryItem, NestedItem newNestedItem) { //variabile per l'hatched area che eventualmente rimane a sinistra del nuovo item float hatchedArea = 0; //lista delle intersezioni tra item nuovo e item già in soluzione IList <NestedItem> intersectedItems = new List <NestedItem>(); bool areIntersectedItemsPresent = false; foreach (var nestedItem in temporaryBin.NestedItems) { if (feasiblePoint.Qposition < nestedItem.TLqPosition && feasiblePoint.Qposition >= nestedItem.BRqPosition && feasiblePoint.Pposition >= nestedItem.BRpPosition) { intersectedItems.Add(nestedItem); } } //3 possibili risultati if (intersectedItems.Count == 0) //non ho intersezioni { newNestedItem.BLpPosition = 0; newNestedItem.TLpPosition = 0; newNestedItem.BRpPosition = temporaryItem.Width; } else { if (intersectedItems.Count == 1) //1 sola intersezione { float delta = feasiblePoint.Pposition - intersectedItems.ElementAt(0).Width; newNestedItem.BLpPosition -= delta; newNestedItem.TLpPosition -= delta; newNestedItem.BRpPosition -= delta; } else if (intersectedItems.Count > 1) //N intersezioni { float widthSum = 0; foreach (var intersectedItem in intersectedItems) { widthSum += intersectedItem.Width; } float delta = feasiblePoint.Pposition - widthSum; newNestedItem.BLpPosition -= delta; newNestedItem.TLpPosition -= delta; newNestedItem.BRpPosition -= delta; } areIntersectedItemsPresent = true; } feasiblePoint.PfinalPosition = newNestedItem.BLpPosition; if (areIntersectedItemsPresent) { //altezza della green area float greenAreaHeight = newNestedItem.Height; //ampiezza dellea green area float greenAreaWidth = newNestedItem.BLpPosition; //definiso la green area a sintra del nuovo item GreenZone greenZone = new GreenZone() { BRpPosition = feasiblePoint.PfinalPosition, BRqPosition = feasiblePoint.QfinalPosition, TRpPosition = feasiblePoint.PfinalPosition, TRqPosition = feasiblePoint.QfinalPosition + newNestedItem.Height, BLpPosition = 0, BLqPosition = feasiblePoint.QfinalPosition, TLpPosition = 0, TLqPosition = feasiblePoint.QfinalPosition + newNestedItem.Height, Area = greenAreaHeight * greenAreaWidth }; //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 = 0; foreach (var intersectedItem in intersectedItems) { //guardo se è più in alto l'item intersecato o il nuovo item if (newNestedItem.TLqPosition > intersectedItem.TLqPosition) { intersectedHeight = Math.Abs(intersectedItem.TLqPosition - greenZone.BLqPosition); } else if (newNestedItem.TLqPosition <= intersectedItem.TLqPosition) { intersectedHeight = newNestedItem.Height; } itemsInSolutionArea += (intersectedHeight * intersectedItem.Width); } hatchedArea = greenZone.Area - itemsInSolutionArea; } return(hatchedArea); }