/// <summary> /// Copies edge object to another edge object /// </summary> /// <param name="p_edgeoriginal">Original edge</param> /// <param name="p_edgecopy">Copy edge</param> private void copyedge(edge p_edgeoriginal, edge p_edgecopy) { p_edgecopy.getStart().setX(p_edgeoriginal.getStart().getX()); p_edgecopy.getStart().setY(p_edgeoriginal.getStart().getY()); p_edgecopy.getEnd().setX(p_edgeoriginal.getEnd().getX()); p_edgecopy.getEnd().setY(p_edgeoriginal.getEnd().getY()); }
/// <summary> /// Used for picking aisle intersection points calculation /// </summary> /// <param name="p_edge">Intersecting edge</param> /// <returns>Returns -1000000 if there is no intersection between the line segments, returns the intersection point if there is intersection</returns> public node calculateIntersect(edge p_edge) { double nointersection = -1000000;//A magic coordinate number used for no intersection node tempcoordinate = new node(options.tempnode); double ua, ub; double x1 = this.getStart().getX(); double x2 = this.getEnd().getX(); double x3 = p_edge.getStart().getX(); double x4 = p_edge.getEnd().getX(); double y1 = this.getStart().getY(); double y2 = this.getEnd().getY(); double y3 = p_edge.getStart().getY(); double y4 = p_edge.getEnd().getY(); //Fixing the rounding error problem when picking aisles are 90 degrees to cross aisles (or regionedges) using epsilon x3 = x3 + (options.getEpsilon()) * (x3 - x4); x4 = x4 - (options.getEpsilon()) * (x3 - x4); y3 = y3 + (options.getEpsilon()) * (y3 - y4); y4 = y4 - (options.getEpsilon()) * (y3 - y4); double denom = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1)); if (denom == 0)//Lines are parallel { tempcoordinate.setX(nointersection); tempcoordinate.setY(nointersection); return(tempcoordinate); } double noma = ((x4 - x3) * (y1 - y3)) - ((y4 - y3) * (x1 - x3)); double nomb = ((x2 - x1) * (y1 - y3)) - ((y2 - y1) * (x1 - x3)); ua = noma / denom; ub = nomb / denom; if ((ua <= 1) && (ua >= 0) && (ub <= 1) && (ub >= 0))//Lines intersect within their line segments { tempcoordinate.setX(x1 + ua * (x2 - x1)); tempcoordinate.setY(y1 + ua * (y2 - y1)); return(tempcoordinate); } else//Lines intersect but beyond their line segments { tempcoordinate.setX(nointersection); tempcoordinate.setY(nointersection); return(tempcoordinate); } }
/// <summary> /// Used for interior cross aisle intersection point calculation /// This is little different than the previous one, we assume the lines are infinitely long lines /// We get rid of the ua <= 1 type of checks /// </summary> /// <param name="p_edge">Intersecting edge</param> /// <returns>Returns -1000000 if lines are parallel otherwise returns the intersection point</returns> public node calculateIntersectInfinite(edge p_edge) { int precision = 10; //Used for rounding error problem when intersection of 90 degree pick aisles double nointersection = -1000000; //A magic coordinate number used for no intersection node tempcoordinate = new node(options.tempnode); double ua, ub; double x1 = this.getStart().getX(); double x2 = this.getEnd().getX(); double x3 = p_edge.getStart().getX(); double x4 = p_edge.getEnd().getX(); double y1 = this.getStart().getY(); double y2 = this.getEnd().getY(); double y3 = p_edge.getStart().getY(); double y4 = p_edge.getEnd().getY(); //Fixing the rounding error problem when picking aisles are 90 degrees x1 = Math.Round(x1, precision); x2 = Math.Round(x2, precision); x3 = Math.Round(x3, precision); x4 = Math.Round(x4, precision); y1 = Math.Round(y1, precision); y2 = Math.Round(y2, precision); y3 = Math.Round(y3, precision); y4 = Math.Round(y4, precision); double denom = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1)); if (denom == 0) { tempcoordinate.setX(nointersection); tempcoordinate.setY(nointersection); return(tempcoordinate); } double noma = ((x4 - x3) * (y1 - y3)) - ((y4 - y3) * (x1 - x3)); double nomb = ((x2 - x1) * (y1 - y3)) - ((y2 - y1) * (x1 - x3)); ua = noma / denom; ub = nomb / denom; tempcoordinate.setX(x1 + ua * (x2 - x1)); tempcoordinate.setY(y1 + ua * (y2 - y1)); return(tempcoordinate); }
/// <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); } }