Пример #1
0
 /// <summary>
 /// Sets the end node of the edge
 /// </summary>
 /// <param name="p_node">New end node</param>
 public void setEnd(node p_node)
 {
     end = p_node;
 }
Пример #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="p_skus">List of SKUs</param>
        /// <param name="p_wh">Warehouse object</param>
        /// <param name="method">Allocation method: 0 turnover, 1 straight, 2 random</param>
        /// <returns>Returns -1 if there is insufficent warehouse space, 0 if there is sufficent warehouse space</returns>
        public int allocateSKUs(List <sku> p_skus, warehouse p_wh, int method)
        {
            int totalstoragelocations = p_wh.totalNumberOfLocations();

            if (p_skus.Count > totalstoragelocations)
            {
                return(-1);                                     //Return insufficient warehouse space
            }
            //Add warehouse locations to locations list in allocation class
            for (int i = 0; i < p_wh.regions.Count; i++)
            {
                for (int j = 0; j < p_wh.regions[i].pickingaisleedges.Count(); j++)
                {
                    for (int k = 0; k < p_wh.regions[i].pickingaisleedges[j].getOnEdgeNodes().Count(); k++)
                    {
                        locations.Add(p_wh.regions[i].pickingaisleedges[j].getOnEdgeNodes()[k]);
                    }
                }
            }
            //Use a different sku list to sort the skus based on their frequency
            //We don't want to change the order of skus in the original list because this might affect the randomized allocation process later
            for (int i = 0; i < p_skus.Count; i++)
            {
                sortedskus.Add(p_skus[i]);
            }

            if (method == 0)//Turnover based storage allocation
            {
                sortedskus.Sort((x, y) => y.pickprobability.CompareTo(x.pickprobability));
                //Set sku locations based on their frequency to the best locations based on overall ranking

                int k = 0;
                for (int i = 0; i < sortedskus.Count; i++)
                {
                    bool added = false;
                    if (p_wh.overallranking[k].node1.s1 != null)
                    {
                        if (p_wh.overallranking[k].node1.s1.addSKU(sortedskus[i]))
                        {
                            sortedskus[i].location = p_wh.overallranking[k].node1;
                            added = true;
                        }
                    }
                    if (!added && p_wh.overallranking[k].node1.s2 != null)
                    {
                        if (p_wh.overallranking[k].node1.s2.addSKU(sortedskus[i]))
                        {
                            sortedskus[i].location = p_wh.overallranking[k].node1;
                            added = true;
                        }
                    }
                    if (!added)
                    {
                        k++;
                        i--;
                    }
                }
            }
            else if (method == 1) //Straight allocation (first SKU goes to first location based on location ID)
            {
                int k = 0;
                for (int i = 0; i < sortedskus.Count; i++)
                {
                    bool added = false;
                    if (locations[k].s1 != null)
                    {
                        if (locations[k].s1.addSKU(sortedskus[i]))
                        {
                            sortedskus[i].location = locations[k];
                            added = true;
                        }
                    }
                    if (!added && locations[k].s2 != null)
                    {
                        if (locations[k].s2.addSKU(sortedskus[i]))
                        {
                            sortedskus[i].location = locations[k];
                            added = true;
                        }
                    }
                    if (!added)
                    {
                        k++;
                        i--;
                    }
                }
            }
            else //Randomized allocation, each SKU goes to a random location
            {
                int n = 2;//Number of SKUs per pick location
                while (sortedskus.Count > 0)
                {
                    node tmplocation = locations[rnd.Next(0, locations.Count - 1)];
                    for (int i = 0; i < n; i++)
                    {
                        if (sortedskus.Count > 0)
                        {
                            sku tmpsku = sortedskus[rnd.Next(0, sortedskus.Count - 1)];
                            tmpsku.location = tmplocation;
                            sortedskus.Remove(tmpsku);
                        }
                    }
                    locations.Remove(tmplocation);
                }
            }
            return(0);
        }
Пример #3
0
 /// <summary>
 /// Sets the start node of the edge
 /// </summary>
 /// <param name="p_node">New start node</param>
 public void setStart(node p_node)
 {
     start = p_node;
 }
Пример #4
0
 //If the edge is a region edge then you can add picking aisle start and end points to this edge
 //If the edge is a picking aisle edge then you can add pick locations to this edge
 /// <summary>
 /// If the edge is a region edge then you can add picking aisle start and end points to this edge
 /// If the edge is a picking aisle edge then you can add pick locations to this edge
 /// </summary>
 /// <param name="p_node">Node to be added</param>
 public void addOnEdgeNode(node p_node)
 {
     onedgenodes.Add(p_node);
 }
Пример #5
0
        /// <summary>
        /// Fulfills pick aisles with pick locations and storage locations, returns false if no storage location can be created (because aisle is too small)
        /// </summary>
        /// <param name="p_edge">Picking aisle</param>
        /// <param name="p_referencenode">Reference node 1 is used for aligning storage locations correctly between picking aisles</param>
        /// <param name="p_referencenode2">Reference node 2 is used for aligning storage locations correctly between picking aisles</param>
        /// <returns>Returns false if no storage locations are created in a pick aisle, otherwise returns true</returns>
        public bool fulfillLocations(edge p_edge, node p_referencenode1, node p_referencenode2)
        {
            double X;
            double Y;
            double Xl1, Xr1;
            double Xl2, Xr2;
            double Xl3, Xr3;
            double Xl4, Xr4;
            double Yl1, Yr1;
            double Yl2, Yr2;
            double Yl3, Yr3;
            double Yl4, Yr4;

            double Xs, Xe, Xr, Ys, Ye, Yr;

            if (p_edge.getStart().getY() > p_edge.getEnd().getY())
            {
                Xs = p_edge.getEnd().getX();
                Xe = p_edge.getStart().getX();
                Ys = p_edge.getEnd().getY();
                Ye = p_edge.getStart().getY();
            }
            else
            {
                Xs = p_edge.getStart().getX();
                Xe = p_edge.getEnd().getX();
                Ys = p_edge.getStart().getY();
                Ye = p_edge.getEnd().getY();
            }

            //Check which reference point is close to starting coordinate (Xs, Ys)
            if (p_referencenode1.getY() < p_referencenode2.getY())
            {
                Xr = p_referencenode1.getX();
                Yr = p_referencenode1.getY();
            }
            else
            {
                Xr = p_referencenode2.getX();
                Yr = p_referencenode2.getY();
            }

            double angle  = p_edge.calculateAngle();
            double angle1 = (visualmath.radianToDegree(angle) - 90);

            angle = visualmath.degreeToRadian(angle1);
            double halfpickingaislewidth = pickingaislewidth / 2;

            double lengthofaisle = Math.Sqrt(Math.Pow(Xs - Xe, 2) + Math.Pow(Ys - Ye, 2));

            int    numberoflocations = Convert.ToInt32(Math.Ceiling(lengthofaisle / locationwidth));
            double incx = (Xe - Xs) / (lengthofaisle / locationwidth);
            double incy = (Ye - Ys) / (lengthofaisle / locationwidth);

            //Find the starting point that is inside the picking aisle
            X = Xr;
            Y = Yr;
            if (Math.Abs(incy) > options.getEpsilon())//if the lines are not parallel then use this one
            {
                if (Yr < Ys)
                {
                    if (incy > 0)
                    {
                        while (Y < Ys)
                        {
                            X = X + incx;
                            Y = Y + incy;
                        }
                    }
                    else
                    {
                        while (Y < Ys)
                        {
                            X = X - incx;
                            Y = Y - incy;
                        }
                    }
                }
                else
                {
                    if (incy > 0)
                    {
                        while (Y > Ys)
                        {
                            X = X - incx;
                            Y = Y - incy;
                        }
                    }
                    else
                    {
                        while (Y > Ys)
                        {
                            X = X + incx;
                            Y = Y + incy;
                        }
                    }
                }
            }
            else//angle is zero so no y increment
            {
                if (Xr < Xs)
                {
                    if (incx > 0)
                    {
                        while (X < Xs)
                        {
                            X = X + incx;
                            Y = Y + incy;
                        }
                    }
                    else
                    {
                        while (X < Xs)
                        {
                            X = X - incx;
                            Y = Y - incy;
                        }
                    }
                }
                else
                {
                    if (incx > 0)
                    {
                        while (X > Xs)
                        {
                            X = X - incx;
                            Y = Y - incy;
                        }
                    }
                    else
                    {
                        while (X > Xs)
                        {
                            X = X + incx;
                            Y = Y + incy;
                        }
                    }
                }
            }

            X = X + incx * verticaladjuster;
            Y = Y + incy * verticaladjuster;

            for (int i = 0; i < numberoflocations; i++)
            {
                storagelocation s1 = null;
                storagelocation s2 = null;
                node            c  = new node(X, Y, options.locationnode);
                //Check each corner of the storage location is inside the region in a smart way
                //If all the corners are inside then create a storage location for left face
                Xl1 = X - incx / 2 - (halfpickingaislewidth + locationdepth) * Math.Cos(angle);
                Yl1 = Y - incy / 2 - (halfpickingaislewidth + locationdepth) * Math.Sin(angle);

                if (!isOnCrossAisle(Xl1, Yl1) && isInsideRegion(Xl1, Yl1))
                {
                    Xl3 = X + incx / 2 - (halfpickingaislewidth + locationdepth) * Math.Cos(angle);
                    Yl3 = Y + incy / 2 - (halfpickingaislewidth + locationdepth) * Math.Sin(angle);
                    if (!isOnCrossAisle(Xl3, Yl3) && isInsideRegion(Xl3, Yl3))
                    {
                        Xl2 = X - incx / 2 - (halfpickingaislewidth) * Math.Cos(angle);
                        Yl2 = Y - incy / 2 - (halfpickingaislewidth) * Math.Sin(angle);
                        if (!isOnCrossAisle(Xl2, Yl2) && isInsideRegion(Xl2, Yl2))
                        {
                            Xl4 = X + incx / 2 - (halfpickingaislewidth) * Math.Cos(angle);
                            Yl4 = Y + incy / 2 - (halfpickingaislewidth) * Math.Sin(angle);
                            if (!isOnCrossAisle(Xl4, Yl4) && isInsideRegion(Xl4, Yl4))
                            {
                                s1 = new storagelocation(c, Xl1, Yl1, Xl2, Yl2, Xl3, Yl3, Xl4, Yl4, 1);
                            }
                        }
                    }
                }

                Xr2 = X - incx / 2 + (halfpickingaislewidth + locationdepth) * Math.Cos(angle);
                Yr2 = Y - incy / 2 + (halfpickingaislewidth + locationdepth) * Math.Sin(angle);

                if (!isOnCrossAisle(Xr2, Yr2) && isInsideRegion(Xr2, Yr2))
                {
                    Xr4 = X + incx / 2 + (halfpickingaislewidth + locationdepth) * Math.Cos(angle);
                    Yr4 = Y + incy / 2 + (halfpickingaislewidth + locationdepth) * Math.Sin(angle);
                    if (!isOnCrossAisle(Xr4, Yr4) && isInsideRegion(Xr4, Yr4))
                    {
                        Xr1 = X - incx / 2 + (halfpickingaislewidth) * Math.Cos(angle);
                        Yr1 = Y - incy / 2 + (halfpickingaislewidth) * Math.Sin(angle);
                        if (!isOnCrossAisle(Xr1, Yr1) && isInsideRegion(Xr1, Yr1))
                        {
                            Xr3 = X + incx / 2 + (halfpickingaislewidth) * Math.Cos(angle);
                            Yr3 = Y + incy / 2 + (halfpickingaislewidth) * Math.Sin(angle);
                            if (!isOnCrossAisle(Xr3, Yr3) && isInsideRegion(Xr3, Yr3))
                            {
                                s2 = new storagelocation(c, Xr1, Yr1, Xr2, Yr2, Xr3, Yr3, Xr4, Yr4, 1);
                            }
                        }
                    }
                }

                if (s1 != null)
                {
                    c.s1 = s1;
                }
                if (s2 != null)
                {
                    c.s2 = s2;
                }
                //Do not create a pick location if there is no storage location
                if (s1 != null || s2 != null)
                {
                    c.setPickingAisleEdge(p_edge);
                    p_edge.addOnEdgeNode(c);
                }
                X = X + incx;
                Y = Y + incy;
            }
            //Return false if there are no pick locations created (because aisle is too short), else return true
            if (p_edge.getOnEdgeNodes().Count == 0)
            {
                return(false);
            }
            else
            {
                return(true);
            }
        }
Пример #6
0
        /// <summary>
        /// Fill region with picking aisles, this method currently only works with one interior node (because of picking aisles that are split into two by another region)
        /// </summary>
        public void fill()
        {
            findRegionNodes();
            //base coordinate used for rotations in regionfill
            node basecoordinate = new node(0, 0, options.tempnode);
            //temporary region edges
            List <edge> tempregionedges = new List <edge>();

            //rotate all edges of the region by given angle
            for (int i = 0; i < regionedges.Count; i++)
            {
                edge tempedge = new edge();
                copyedge(regionedges[i], tempedge);
                tempregionedges.Add(tempedge);
                tempregionedges[i].setStart(visualmath.rotate(basecoordinate, tempregionedges[i].getStart(), angle));
                tempregionedges[i].setEnd(visualmath.rotate(basecoordinate, tempregionedges[i].getEnd(), angle));
            }

            //Used for rectangular creation
            double minx = options.getBig();
            double miny = options.getBig();
            double maxx = options.getSmall();
            double maxy = options.getSmall();

            //Find the minx, miny, maxx and maxy for a box that is extreme boundaries of the region
            for (int i = 0; i < regionedges.Count; i++)
            {
                if (tempregionedges[i].getStart().getX() > maxx)
                {
                    maxx = tempregionedges[i].getStart().getX();
                }
                if (tempregionedges[i].getStart().getY() > maxy)
                {
                    maxy = tempregionedges[i].getStart().getY();
                }
                if (tempregionedges[i].getEnd().getX() > maxx)
                {
                    maxx = tempregionedges[i].getEnd().getX();
                }
                if (tempregionedges[i].getEnd().getY() > maxy)
                {
                    maxy = tempregionedges[i].getEnd().getY();
                }

                if (tempregionedges[i].getStart().getX() < minx)
                {
                    minx = tempregionedges[i].getStart().getX();
                }
                if (tempregionedges[i].getStart().getY() < miny)
                {
                    miny = tempregionedges[i].getStart().getY();
                }
                if (tempregionedges[i].getEnd().getX() < minx)
                {
                    minx = tempregionedges[i].getEnd().getX();
                }
                if (tempregionedges[i].getEnd().getY() < miny)
                {
                    miny = tempregionedges[i].getEnd().getY();
                }
            }

            //Temporary edges used to add picking aisles to the region
            //infeasible ones are eliminated and not added as picking aisles
            List <edge> tempedges = new List <edge>();

            //calculate the gap between picking aisles
            double gap = (pickingaislewidth + 2 * locationdepth);
            int    k   = 0;

            //Add edges starting from minimum y point and increasing by gap up to maximum y point of the rotated region
            while (miny + k * gap + horizontaladjuster * gap <= maxy)
            {
                edge e1 = new edge(new node(minx, miny + k * gap + horizontaladjuster * gap, options.tempnode), new node(maxx, miny + k * gap + horizontaladjuster * gap, options.tempnode), options.tempedge);
                tempedges.Add(e1);
                k++;
            }

            //Rotate temp edges back
            for (int i = 0; i < tempedges.Count; i++)
            {
                tempedges[i].setStart(visualmath.rotate(basecoordinate, tempedges[i].getStart(), -angle));
                tempedges[i].setEnd(visualmath.rotate(basecoordinate, tempedges[i].getEnd(), -angle));
            }

            //Find edges that are intersecting two of the edges and add them as picking aisles of that region
            for (int i = 0; i < tempedges.Count; i++)
            {
                List <node> tmppoints      = new List <node>();
                List <int>  intersectedges = new List <int>();
                for (int j = 0; j < regionedges.Count; j++)
                {
                    node p = new node(0, 0, options.pickingaislenode);
                    p = regionedges[j].calculateIntersect(tempedges[i]);
                    //Check if that edge intersect with tempedge
                    if (p.getX() != -1000000)//-1000000 is a magic number for no intersection
                    {
                        tmppoints.Add(p);
                        tmppoints[tmppoints.Count - 1].setCrossAisleEdge(regionedges[j]);
                    }
                }
                //if there are exactly two intersections then add these two points as picking aisles to that region
                if (tmppoints.Count == 2)
                {
                    if (angle == 90)
                    {
                        tmppoints.Sort((x, y) => y.getY().CompareTo(x.getY()));
                    }
                    else
                    {
                        tmppoints.Sort((x, y) => y.getX().CompareTo(x.getX()));
                    }
                    tmppoints[0].type = options.pickingaislenode;
                    tmppoints[1].type = options.pickingaislenode;
                    //If there are storage locations on this picking aisle then add this picking aisle to the region
                    if (addPickingAisleEdge(tmppoints[0], tmppoints[1], tempedges[i].getStart(), tempedges[i].getEnd()))
                    {
                        tmppoints[0].getCrossAisleEdge().addOnEdgeNode(tmppoints[0]);
                        tmppoints[1].getCrossAisleEdge().addOnEdgeNode(tmppoints[1]);
                    }
                }
                //if there are exactly four intersections then add first two points as first picking aisle and second two points as second picking aisle
                if (tmppoints.Count == 4)
                {
                    if (angle == 90)
                    {
                        tmppoints.Sort((x, y) => y.getY().CompareTo(x.getY()));
                    }
                    else
                    {
                        tmppoints.Sort((x, y) => y.getX().CompareTo(x.getX()));
                    }
                    //First picking aisle
                    tmppoints[0].type = options.pickingaislenode;
                    tmppoints[1].type = options.pickingaislenode;
                    //If there are storage locations on this picking aisle then add this picking aisle to the region
                    if (addPickingAisleEdge(tmppoints[0], tmppoints[1], tempedges[i].getStart(), tempedges[i].getEnd()))
                    {
                        tmppoints[0].getCrossAisleEdge().addOnEdgeNode(tmppoints[0]);
                        tmppoints[1].getCrossAisleEdge().addOnEdgeNode(tmppoints[1]);
                    }
                    //Second picking aisle
                    tmppoints[2].type = options.pickingaislenode;
                    tmppoints[3].type = options.pickingaislenode;
                    //If there are storage locations on this picking aisle then add this picking aisle to the region
                    if (addPickingAisleEdge(tmppoints[2], tmppoints[3], tempedges[i].getStart(), tempedges[i].getEnd()))
                    {
                        tmppoints[2].getCrossAisleEdge().addOnEdgeNode(tmppoints[2]);
                        tmppoints[3].getCrossAisleEdge().addOnEdgeNode(tmppoints[3]);
                    }
                }
            }
        }
Пример #7
0
        /// <summary>
        /// Add picking aisle to the region
        /// </summary>
        /// <param name="p_start">Beginning of pick aisle</param>
        /// <param name="p_end">Ending of pick aisle</param>
        /// <param name="p_referencenode1">First reference node</param>
        /// <param name="p_referencenode2">Second reference node</param>
        /// <returns>Returns true if at least one picking aisle is created, otherwise returns false</returns>
        public bool addPickingAisleEdge(node p_start, node p_end, node p_referencenode1, node p_referencenode2)
        {
            //Connect two picking aisle nodes, same picking aisle
            edge tempedge = p_start.connect(p_end, options.pickingaisleedge);

            //Set width of the picking aisle
            tempedge.setWidth(pickingaislewidth);
            //Set region of the picking aisle
            tempedge.setRegion(this);
            //if there is at least one storage location then create a picking aisle
            if (fulfillLocations(tempedge, p_referencenode1, p_referencenode2))
            {
                //Add this edge to region picking aisle edges
                pickingaisleedges.Add(tempedge);
                return(true);
            }
            return(false);
        }