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); }
public void SetNestingManager(INestingManager nestingManager) { if (nestingManager == null) { throw new ArgumentNullException(nameof(nestingManager)); } _nestingManager = nestingManager; }
private static ClassificationResult ClassifyGeneric( INestingManager manager, List <Part> parts, WorkingArea workingArea) { float areaX, areaY; if (!manager.IsRectangle(workingArea, out areaX, out areaY)) { throw new Exception("WorkingArea is not a rectangle!"); } float boxX, boxY; manager.GetRectangleBoxOfParts(parts, out boxX, out boxY); if (boxX > areaX || boxY > areaY) { throw new Exception("Part does not fit inside Working area!"); } //Calculate how many boxes could be fit in the area int horizontalBoxes = (int)(areaX / boxX); int verticalBoxes = (int)(areaY / boxY); //We build the final result using the partial results and the calculated positions of the boxes ClassificationResult result = new ClassificationResult(ClassifierInformation) { WorkingArea = workingArea.Clone() }; 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++) { Point subResultOrigin = new Point(i * boxX, j * boxY); result.ExtraPolygons.Add(manager.CalculateRectangle(boxX, boxY, subResultOrigin)); Part placedPart = parts[partIndex % parts.Count].Clone(); placedPart.Place(subResultOrigin); result.Parts.Add(placedPart); partIndex++; } } return(result); }
private static void PlaceGenericPart(INestingManager nestingManager, Point originOfTesselationPolygon, Part part, ClassificationResult result) { part.Place(Point.Origin); if (nestingManager.IsRightTriangle(part)) { Part flippedTriangle = nestingManager.CalculateFlippedRightTriangle(part); flippedTriangle.Place(Point.Origin); PlacePart(originOfTesselationPolygon, flippedTriangle, result); } PlacePart(originOfTesselationPolygon, part, result); }
private static List <WorkingArea> CalculateRemainderWorkingAreas( INestingManager nestingManager, float tesselationPolygonWidth, float tesselationPolygonHeight, int horizontalBoxes, int verticalBoxes, float workingAreaWidth, float workingAreaHeight) { List <WorkingArea> result = new List <WorkingArea>(); float width1 = tesselationPolygonWidth * horizontalBoxes; float height1 = workingAreaHeight - tesselationPolygonHeight * verticalBoxes; float width2 = workingAreaWidth - tesselationPolygonWidth * horizontalBoxes; float height2 = height1; float width3 = width2; float height3 = tesselationPolygonHeight * verticalBoxes; if (height1 > 0) { WorkingArea area = nestingManager.CalculateWorkingArea(width1, height1); area.Placement = new Point(0, tesselationPolygonHeight * verticalBoxes); result.Add(area); } if (height2 > 0 && width2 > 0) { WorkingArea area = nestingManager.CalculateWorkingArea(width2, height2); area.Placement = new Point(tesselationPolygonWidth * horizontalBoxes, tesselationPolygonHeight * verticalBoxes); result.Add(area); } if (width3 > 0) { WorkingArea area = nestingManager.CalculateWorkingArea(width3, height3); area.Placement = new Point(tesselationPolygonWidth * horizontalBoxes, 0); result.Add(area); } 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 void SetNestingManager(INestingManager nestingManager) { //This classifier does not use Nesting Manager }
public void SetNestingManager(INestingManager nestingManager) { this.manager = nestingManager; }
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); }