예제 #1
0
        /// <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(Tuple feasiblePoint, NestedItem newNestedItem, Bin <Tuple> temporaryBin, Item temporaryItem)
        {
            IList <NestedItem> downIntersectedNestedItems = PushItemDown(feasiblePoint, temporaryBin, temporaryItem, newNestedItem);
            IList <NestedItem> leftIntersectedNestedItems = 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))
            {
                ComputeHatchedArea(feasiblePoint, newNestedItem, downIntersectedNestedItems, leftIntersectedNestedItems);
                Console.WriteLine("(" + feasiblePoint.Pposition + ", " + feasiblePoint.Qposition + "), HR = " + feasiblePoint.HatchedArea +
                                  ", new coord(" + feasiblePoint.PfinalPosition + ", " + feasiblePoint.QfinalPosition + ")");
                return(feasiblePoint.HatchedArea);
            }
            else
            {
                return(-1);
            }
        }
예제 #2
0
 /// <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(NestedItem newNestedItem, float temporaryBinHeight, float temporaryBinWidth)
 {
     return(newNestedItem.TLqPosition <= temporaryBinHeight && newNestedItem.BRpPosition <= temporaryBinWidth);
 }
예제 #3
0
        /// <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 <NestedItem> PushItemLeft(Tuple feasiblePoint, Bin <Tuple> temporaryBin, Item temporaryItem, NestedItem newNestedItem)
        {
            //lista delle intersezioni tra item nuovo e item già in soluzione
            IList <NestedItem> intersectedItems = new List <NestedItem>();

            foreach (var nestedItem in temporaryBin.NestedItems)
            {
                //cerco interesezioni orizzontali tra nuovo item e item già in soluzione (HO TOLTO UGUALE DESTRA -> CHECK)
                if (((newNestedItem.BLqPosition >= nestedItem.BLqPosition && newNestedItem.BLqPosition < nestedItem.TLqPosition) ||
                     (newNestedItem.TLqPosition > nestedItem.BLqPosition && newNestedItem.TLqPosition <= nestedItem.TLqPosition)) &&
                    newNestedItem.BLpPosition >= 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 = intersectedItems.OrderBy(x => x.BRpPosition).Last().BRpPosition;
                    float delta    = feasiblePoint.Pposition - widthSum;
                    newNestedItem.BLpPosition -= delta;
                    newNestedItem.TLpPosition -= delta;
                    newNestedItem.BRpPosition -= delta;
                }
            }

            feasiblePoint.PfinalPosition = newNestedItem.BLpPosition;
            return(intersectedItems);
        }
예제 #4
0
        /// <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)
            {
                var nestedItem = new NestedItem(temporaryItem)
                {
                    BLpPosition = 0,
                    BLqPosition = 0,
                    BRpPosition = temporaryItem.Width,
                    BRqPosition = 0,
                    TLpPosition = 0,
                    TLqPosition = temporaryItem.Height
                };

                temporaryBin.NestedItems = new List <NestedItem>();
                temporaryBin.NestedItems.Add(nestedItem);

                HandleOperationsPostNestedItem(temporaryBin, temporaryItem, temporaryBin.Points.ElementAt(0), nestedItem);
                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)
                                            .FirstOrDefault();

                //se non riesco a trovare la tupla, vuol dire che le tuple sono finite
                if (minHatchedAreaTuple == null)
                {
                    return(false);
                }

                //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 nestedItem = 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
                    };

                    temporaryBin.NestedItems.Add(nestedItem);

                    HandleOperationsPostNestedItem(temporaryBin, temporaryItem, minHatchedAreaPoint, nestedItem);
                    return(true);
                }
                else if (minHatchedAreaPoints.Count > 1)
                {
                    Tuple minCoordinatePoint = ApplyRule(minHatchedAreaPoints);

                    var nestedItem = 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
                    };

                    temporaryBin.NestedItems.Add(nestedItem);

                    HandleOperationsPostNestedItem(temporaryBin, temporaryItem, minCoordinatePoint, nestedItem);
                    return(true);
                }
            }
            return(false);
        }
예제 #5
0
        /// <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, NestedItem newNestedItem, IList <NestedItem> downIntersectedNestedItems, IList <NestedItem> 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
                GreenZone greenZone = new GreenZone()
                {
                    BRpPosition = feasiblePoint.PfinalPosition + newNestedItem.Width,
                    BRqPosition = 0,
                    TRpPosition = feasiblePoint.PfinalPosition + newNestedItem.Width,
                    TRqPosition = feasiblePoint.QfinalPosition,
                    BLpPosition = feasiblePoint.PfinalPosition,
                    BLqPosition = 0,
                    TLpPosition = feasiblePoint.PfinalPosition,
                    TLqPosition = feasiblePoint.QfinalPosition,
                    Height      = newNestedItem.BRqPosition,
                    Width       = newNestedItem.Width,
                    Area        = newNestedItem.BRqPosition * newNestedItem.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 (newNestedItem.BLpPosition < intersectedItem.BLpPosition && //new item + a sx di interesect item
                        newNestedItem.BRpPosition < intersectedItem.BRpPosition)
                    {
                        intersectedWidth = newNestedItem.BRpPosition - intersectedItem.BLpPosition;
                    }
                    else if (intersectedItem.BLpPosition < newNestedItem.BLpPosition && //new item è + a  dx di intersected item
                             intersectedItem.BRpPosition < newNestedItem.BRpPosition)
                    {
                        intersectedWidth = intersectedItem.BRpPosition - newNestedItem.BLpPosition;
                    }
                    else if ((newNestedItem.BLpPosition == intersectedItem.BLpPosition && //new item inizia come insertected item ma termina prima
                              newNestedItem.BRpPosition < intersectedItem.BRpPosition) ||
                             (intersectedItem.BLpPosition < newNestedItem.BLpPosition &&  // new item inizia dopo di insertected item ma terminano uguali
                              intersectedItem.BRpPosition == newNestedItem.BRpPosition) ||
                             (intersectedItem.BLpPosition < newNestedItem.BLpPosition &&  //le coordinate p del new item cadono dentro quelle p dell'intersected item
                              intersectedItem.BRpPosition > newNestedItem.BRpPosition))
                    {
                        intersectedWidth = greenZone.Width;
                    }
                    else
                    {
                        intersectedWidth = intersectedItem.Width;
                    }

                    itemsInSolutionArea += (intersectedItem.Height * intersectedWidth);
                }

                partialHatchedArea = greenZone.Area - itemsInSolutionArea;
                totalHatchedArea  += partialHatchedArea;
            }

            if (leftIntersectedNestedItems.Count > 0)
            {
                //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,
                    Height      = newNestedItem.Height,
                    Width       = newNestedItem.BLpPosition,
                    Area        = newNestedItem.Height * newNestedItem.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 < newNestedItem.BLqPosition && //new item + in alto di intersected item
                        intersectedItem.TLqPosition < newNestedItem.TLqPosition)
                    {
                        intersectedHeight = intersectedItem.TLqPosition - newNestedItem.BLqPosition;
                    }
                    else if (newNestedItem.BLqPosition < intersectedItem.BLqPosition &&  //new item + in basso di interesect item
                             newNestedItem.TLqPosition < intersectedItem.TLqPosition)
                    {
                        intersectedHeight = newNestedItem.TLqPosition - intersectedItem.BLqPosition;
                    }
                    else if ((newNestedItem.BLqPosition == intersectedItem.BLqPosition && //new item inizia come insertected item ma termina prima
                              newNestedItem.TLqPosition < intersectedItem.TLqPosition) ||
                             (intersectedItem.BLqPosition < newNestedItem.BLqPosition &&  // new item inizia dopo di insertected item ma terminano uguali
                              intersectedItem.TLqPosition == newNestedItem.TLqPosition) ||
                             (intersectedItem.BLqPosition < newNestedItem.BLqPosition &&  //le coordinate q del new item cadono dentro quelle dell'intersected item
                              intersectedItem.TLqPosition > newNestedItem.TLqPosition))
                    {
                        intersectedHeight = greenZone.Height;
                    }
                    else
                    {
                        intersectedHeight = intersectedItem.Height;
                    }

                    itemsInSolutionArea += (intersectedHeight * intersectedItem.Width);
                }

                partialHatchedArea = greenZone.Area - itemsInSolutionArea;
                totalHatchedArea  += partialHatchedArea;
            }

            feasiblePoint.HatchedArea = totalHatchedArea;
        }
예제 #6
0
        /// <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 temporaryItem, Tuple point, NestedItem nestedItem)
        {
            //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 in quanto sono stati "coperti" dal nuovo item nestato
            foreach (var p in temporaryBin.Points)
            {
                if (p.Pposition >= nestedItem.BLpPosition && p.Pposition < nestedItem.BRpPosition &&
                    p.Qposition >= nestedItem.BLqPosition && p.Qposition < nestedItem.TLqPosition)
                {
                    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 + temporaryItem.Height &&
                                                         x.IsUsed == false).FirstOrDefault();

            //definisco il primo nuovo punto
            var firstPoint = new Tuple()
            {
                Pposition = point.PfinalPosition,
                Qposition = point.QfinalPosition + temporaryItem.Height,
                IsUsed    = false
            };

            //controllo se il primo nuovo punto è idoneo ad essere aggiunto perché
            //potrebbe essere erroneaemente creato sul lato di un item già esistente
            bool isPointLyingOnItemSide = false;

            foreach (var 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);
            }
            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 + temporaryItem.Width &&
                                                   x.Qposition == point.QfinalPosition).FirstOrDefault();

            //definisco il secondo nuovo punto
            var secondPoint = new Tuple()
            {
                Pposition = point.PfinalPosition + temporaryItem.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.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);
            }

            //setto item a nestato
            temporaryItem.IsRemoved = true;
        }