private static ClassificationResult GetDirectedResult(INestingManager nestingManager, Part part, WorkingArea workingArea, List <Part> originalParts) { float areaX, areaY; if (!nestingManager.IsRectangle(workingArea, out areaX, out areaY)) { throw new Exception("WorkingArea is not a rectangle!"); } //Step 1: Calculate the tesselation polygon float boxX, boxY; nestingManager.GetRectangleBoxOfPart(part, out boxX, out boxY); int horizontalBoxes = (int)(areaX / boxX); int verticalBoxes = (int)(areaY / boxY); ClassificationResult result = new ClassificationResult(ClassifierInformation); //Step 4: Calculate the remainder polygons List <WorkingArea> remainderPolygons = CalculateRemainderWorkingAreas( nestingManager, boxX, boxY, horizontalBoxes, verticalBoxes, areaX, areaY); //Step 5: Generate the reimainder polygons' problems foreach (WorkingArea remainderPolygon in remainderPolygons) { ClassificationResult subResult = GetMainResult(nestingManager, originalParts, remainderPolygon); if (!nestingManager.IsRectangle(remainderPolygon, out areaX, out areaY)) { throw new Exception("WorkingArea is not a rectangle!"); } result.ExtraPolygons.Add(nestingManager.CalculateRectangle(areaX, areaY, remainderPolygon.Placement)); result.AddSubResult(subResult, remainderPolygon.Placement); } for (int i = 0; i < horizontalBoxes; i++) { for (int j = 0; j < verticalBoxes; j++) { Point placementPart = new Point(i * boxX, j * boxY); PlaceGenericPart(nestingManager, placementPart, part, result); result.ExtraPolygons.Add(nestingManager.CalculateRectangle(boxX, boxY, placementPart)); } } return(result); }
private static void ClassifySinglePart(INestingManager nestingManager, Part part, WorkingArea workingArea, List <ClassificationResult> results) { Point point = Point.Origin; part.Place(Point.Origin); float areaWidth, areaHeight; if (!nestingManager.IsRectangle(workingArea, out areaWidth, out areaHeight)) { throw new InvalidOperationException("Area is not a rectangle"); } foreach (KeyValuePair <Point, Point> edge in part.ConvexHullEdges()) { Part mirror = part.CalculateMirror(edge.Key, edge.Value); Part clone = part.Clone(); mirror.Place(point); clone.Place(point); Part hull = new Part(); foreach (var side in new Part[] { mirror, clone }) { if (side.InnerParts.Any()) { hull.InnerParts.AddRange(side.InnerParts.Select(x => x.Clone())); } else { hull.InnerParts.Add(side); } } hull.FitToOrigin(); float hullWidth, hullHeight; nestingManager.GetRectangleBoxOfPart(hull, out hullWidth, out hullHeight); //Is the hull too big for the area? if (!(hullWidth <= areaWidth) || !(hullHeight <= areaHeight)) { continue; } ClassificationResult result = new ClassificationResult(ClassifierInformation) { Parts = hull.InnerParts, WorkingArea = workingArea }; //The result was already found? if (results.Contains(result)) { //Ignore result continue; } //If it fits, we store the part and continue operating over it. results.Add(result); ClassifySinglePart(nestingManager, hull, workingArea, results); } }
public static ClassificationResult GetMainResult( INestingManager nestingManager, List <Part> originalParts, WorkingArea workingArea) { float areaX, areaY; if (!nestingManager.IsRectangle(workingArea, out areaX, out areaY)) { throw new Exception("WorkingArea is not a rectangle!"); } //Step 1: Remove parts that do not fit the working area float boxX; float boxY; List <Part> parts = new List <Part>(); foreach (Part part in originalParts) { nestingManager.GetRectangleBoxOfPart(part, out boxX, out boxY); if (areaX >= boxX && areaY >= boxY) { //Part does not fit the working area parts.Add(part); } } //Step 2: Break if no parts fit the working area if (!parts.Any()) { //Empty result return(new ClassificationResult(ClassifierInformation) { WorkingArea = workingArea }); } //Step 2.5: Sort parts by Area size in descending order, so we favor the placement of bigger pieces //in case there are not enough polygons to place all the parts, because the smaller parts could be fit in the remainders parts = parts.OrderByDescending(x => x.GetTotalArea()).ToList(); //Step 3: Calculate the tesselation polygon nestingManager.GetRectangleBoxOfParts(parts, out boxX, out boxY); int horizontalBoxes = (int)(areaX / boxX); int verticalBoxes = (int)(areaY / boxY); WorkingArea tesselationPolygon = new WorkingArea() { Vertexes = new List <Point>() { new Point(0, 0), new Point(boxX, 0), new Point(boxX, boxY), new Point(0, boxY) } }; ClassificationResult result = new ClassificationResult(ClassifierInformation); //Step 4: Calculate the remainder polygons List <WorkingArea> remainderPolygons = CalculateRemainderWorkingAreas( nestingManager, boxX, boxY, horizontalBoxes, verticalBoxes, areaX, areaY); //Step 5: Generate the reimainder polygons' problems foreach (WorkingArea remainderPolygon in remainderPolygons) { ClassificationResult subResult = GetMainResult(nestingManager, parts, remainderPolygon); if (!nestingManager.IsRectangle(remainderPolygon, out areaX, out areaY)) { throw new Exception("WorkingArea is not a rectangle!"); } result.ExtraPolygons.Add(nestingManager.CalculateRectangle(areaX, areaY, remainderPolygon.Placement)); result.AddSubResult(subResult, remainderPolygon.Placement); } //Step6: Generate tesselation poligons' subproblem List <ClassificationResult> subresults = new List <ClassificationResult>(); foreach (Part part in parts) { ClassificationResult res = GetDirectedResult(nestingManager, part, tesselationPolygon, parts); if (res != null) { subresults.Add(res); } } result.WorkingArea = workingArea.Clone(); int numberOfParts = parts.Count; int partIndex = 0; //Place parts until we run out of space for (int i = 0; i < horizontalBoxes; i++) { for (int j = 0; j < verticalBoxes; j++) { ClassificationResult subResult = subresults[partIndex % numberOfParts]; Point subResultOrigin = new Point(i * boxX, j * boxY); result.AddSubResult(subResult, subResultOrigin); partIndex++; } } return(result); }