public bool Hit(Aabb other) { if (max.X < other.min.X) return false; if (min.X > other.max.X) return false; if (max.Y < other.min.Y) return false; if (min.Y > other.max.Y) return false; return true; }
public static void GenerateLinePaths(Polygons polygonToInfill, ref Polygons infillLinesToPrint, int lineSpacing, int infillExtendIntoPerimeter_um, double rotation, long rotationOffset = 0) { if (polygonToInfill.Count > 0) { Polygons outlines = polygonToInfill.Offset(infillExtendIntoPerimeter_um); if (outlines.Count > 0) { PointMatrix matrix = new PointMatrix(-(rotation + 90)); // we are rotating the part so we rotate by the negative so the lines go the way we expect outlines.ApplyMatrix(matrix); Aabb boundary = new Aabb(outlines); boundary.min.X = ((boundary.min.X / lineSpacing) - 1) * lineSpacing - rotationOffset; int xLineCount = (int)((boundary.max.X - boundary.min.X + (lineSpacing - 1)) / lineSpacing); Polygons unclipedPatern = new Polygons(); long firstX = boundary.min.X / lineSpacing * lineSpacing; for (int lineIndex = 0; lineIndex < xLineCount; lineIndex++) { Polygon line = new Polygon(); line.Add(new IntPoint(firstX + lineIndex * lineSpacing, boundary.min.Y)); line.Add(new IntPoint(firstX + lineIndex * lineSpacing, boundary.max.Y)); unclipedPatern.Add(line); } PolyTree ret = new PolyTree(); Clipper clipper = new Clipper(); clipper.AddPaths(unclipedPatern, PolyType.ptSubject, false); clipper.AddPaths(outlines, PolyType.ptClip, true); clipper.Execute(ClipType.ctIntersection, ret, PolyFillType.pftPositive, PolyFillType.pftEvenOdd); Polygons newSegments = Clipper.OpenPathsFromPolyTree(ret); PointMatrix inversematrix = new PointMatrix((rotation + 90)); newSegments.ApplyMatrix(inversematrix); infillLinesToPrint.AddRange(newSegments); } } }
public static void GenerateHexLinePaths(Polygons in_outline, ref Polygons result, int lineSpacing, int infillExtendIntoPerimeter_um, double rotationDegrees, int layerIndex) { int extraRotationAngle = 0; if (in_outline.Count > 0) { Polygons outlines = in_outline.Offset(infillExtendIntoPerimeter_um); if (outlines.Count > 0) { int perIncrementOffset = (int)(lineSpacing * Math.Sqrt(3) / 2 + .5); PointMatrix matrix = new PointMatrix(-(rotationDegrees + extraRotationAngle)); // we are rotating the part so we rotate by the negative so the lines go the way we expect outlines.ApplyMatrix(matrix); Aabb boundary = new Aabb(outlines); boundary.min.X = ((boundary.min.X / lineSpacing) - 1) * lineSpacing; boundary.min.Y = ((boundary.min.Y / perIncrementOffset) - 2) * perIncrementOffset; boundary.max.X += lineSpacing; boundary.max.Y += perIncrementOffset; Polygons unclipedPatern = new Polygons(); foreach (IntPoint startPoint in StartPositionIterator(boundary, lineSpacing, layerIndex)) { Polygon attachedLine = new Polygon(); foreach (IntPoint center in IncrementPositionIterator(startPoint, boundary, lineSpacing, layerIndex)) { // what we are adding are the little plusses that define the points // | top // | // /\ center // left/ \ right // IntPoint left = center + new IntPoint(-lineSpacing / 2, -perIncrementOffset / 3); IntPoint right = center + new IntPoint(lineSpacing / 2, -perIncrementOffset / 3); IntPoint top = center + new IntPoint(0, perIncrementOffset * 2 / 3); switch (layerIndex % 3) { case 0: // left to right attachedLine.Add(left); attachedLine.Add(center); attachedLine.Add(center); attachedLine.Add(right); unclipedPatern.Add(new Polygon() { top, center }); break; case 1: // left to top attachedLine.Add(left); attachedLine.Add(center); attachedLine.Add(center); attachedLine.Add(top); unclipedPatern.Add(new Polygon() { center, right }); break; case 2: // top to right attachedLine.Add(top); attachedLine.Add(center); attachedLine.Add(center); attachedLine.Add(right); unclipedPatern.Add(new Polygon() { left, center }); break; } } if (attachedLine.Count > 0) { unclipedPatern.Add(attachedLine); } } PolyTree ret = new PolyTree(); Clipper clipper = new Clipper(); clipper.AddPaths(unclipedPatern, PolyType.ptSubject, false); clipper.AddPaths(outlines, PolyType.ptClip, true); clipper.Execute(ClipType.ctIntersection, ret, PolyFillType.pftPositive, PolyFillType.pftEvenOdd); Polygons newSegments = Clipper.OpenPathsFromPolyTree(ret); PointMatrix inversematrix = new PointMatrix((rotationDegrees + extraRotationAngle)); newSegments.ApplyMatrix(inversematrix); result.AddRange(newSegments); } } }
private static IEnumerable<IntPoint> IncrementPositionIterator(IntPoint startPoint, Aabb boundary, int lineSpacing, int layerIndex) { IntPoint positionAdd = new IntPoint(lineSpacing, 0); int perIncrementOffset = (int)(lineSpacing * Math.Sqrt(3) / 2 + .5); switch (layerIndex % 3) { case 0: // left to right positionAdd = new IntPoint(lineSpacing, 0); break; case 1: // left to top positionAdd = new IntPoint(lineSpacing / 2, perIncrementOffset); break; case 2: // top to right positionAdd = new IntPoint(lineSpacing / 2, -perIncrementOffset); break; } IntPoint nextPoint = startPoint; do { yield return nextPoint; nextPoint += positionAdd; } while (nextPoint.X > boundary.min.X && nextPoint.X < boundary.max.X && nextPoint.Y > boundary.min.Y && nextPoint.Y < boundary.max.Y); }
public bool BridgeAngle(Polygons areaAboveToFill, out double bridgeAngle, string debugName = "") { SliceLayer layerToRestOn = this; bridgeAngle = -1; Aabb boundaryBox = new Aabb(areaAboveToFill); //To detect if we have a bridge, first calculate the intersection of the current layer with the previous layer. // This gives us the islands that the layer rests on. Polygons islandsToRestOn = new Polygons(); foreach (LayerIsland islandToRestOn in layerToRestOn.Islands) { if (!boundaryBox.Hit(islandToRestOn.BoundingBox)) { continue; } islandsToRestOn.AddRange(areaAboveToFill.CreateIntersection(islandToRestOn.IslandOutline)); } if (OUTPUT_DEBUG_DATA) { string outlineString = areaAboveToFill.WriteToString(); string islandOutlineString = ""; foreach (LayerIsland prevLayerIsland in layerToRestOn.Islands) { foreach (Polygon islandOutline in prevLayerIsland.IslandOutline) { islandOutlineString += islandOutline.WriteToString(); } islandOutlineString += "|"; } string islandsString = islandsToRestOn.WriteToString(); } Polygons islandConvexHuls = new Polygons(); foreach(Polygon poly in islandsToRestOn) { islandConvexHuls.Add(poly.CreateConvexHull()); } if (islandsToRestOn.Count > 5 || islandsToRestOn.Count < 1) { return false; } if (islandsToRestOn.Count == 1) { return GetSingleIslandAngle(areaAboveToFill, islandsToRestOn[0], out bridgeAngle, debugName); } // Find the 2 largest islands that we rest on. double biggestArea = 0; double nextBiggestArea = 0; int indexOfBiggest = -1; int indexOfNextBigest = -1; for (int islandIndex = 0; islandIndex < islandsToRestOn.Count; islandIndex++) { //Skip internal holes if (!islandsToRestOn[islandIndex].Orientation()) { continue; } double area = Math.Abs(islandConvexHuls[islandIndex].Area()); if (area > biggestArea) { if (biggestArea > nextBiggestArea) { nextBiggestArea = biggestArea; indexOfNextBigest = indexOfBiggest; } biggestArea = area; indexOfBiggest = islandIndex; } else if (area > nextBiggestArea) { nextBiggestArea = area; indexOfNextBigest = islandIndex; } } if (indexOfBiggest < 0 || indexOfNextBigest < 0) { return false; } Polygons big1 = new Polygons() { islandConvexHuls[indexOfBiggest] }; Polygons big2 = new Polygons() { islandConvexHuls[indexOfNextBigest] }; Polygons intersection = big1.CreateIntersection(big2); if(intersection.Count > 0) { return GetSingleIslandAngle(areaAboveToFill, islandsToRestOn[indexOfBiggest], out bridgeAngle, debugName); } IntPoint center1 = islandsToRestOn[indexOfBiggest].CenterOfMass(); IntPoint center2 = islandsToRestOn[indexOfNextBigest].CenterOfMass(); bridgeAngle = Math.Atan2(center2.Y - center1.Y, center2.X - center1.X) / Math.PI * 180; Range0To360(ref bridgeAngle); if (OUTPUT_DEBUG_DATA) { islandsToRestOn.SaveToGCode("{0} - angle {1:0.}.gcode".FormatWith(debugName, bridgeAngle)); } return true; }
private static IEnumerable <IntPoint> StartPositionIterator(Aabb boundary, int lineSpacing, int layerIndex) { int perIncrementOffset = (int)(lineSpacing * Math.Sqrt(3) / 2 + .5); int yLineCount = (int)((boundary.max.Y - boundary.min.Y + perIncrementOffset) / perIncrementOffset) + 1; switch (layerIndex % 3) { case 0: // left to right for (int yIndex = 0; yIndex < yLineCount; yIndex++) { long yPosition = boundary.min.Y + yIndex * perIncrementOffset; bool removeXOffset = ((yPosition / perIncrementOffset) % 2) == 0; long xOffsetForY = lineSpacing / 2; if (removeXOffset) // if we are at every other y { xOffsetForY = 0; } long firstX = boundary.min.X + xOffsetForY; yield return(new IntPoint(firstX, yPosition)); } break; case 1: // left to top { IntPoint nextPoint = new IntPoint(); for (int yIndex = yLineCount; yIndex >= 0; yIndex--) { long yPosition = boundary.min.Y + yIndex * perIncrementOffset; bool createLineSegment = ((yPosition / perIncrementOffset) % 2) == 0; if (createLineSegment) { nextPoint = new IntPoint(boundary.min.X, yPosition); yield return(nextPoint); } } IntPoint positionAdd = new IntPoint(lineSpacing, 0); nextPoint += positionAdd; while (nextPoint.X > boundary.min.X && nextPoint.X < boundary.max.X) { yield return(nextPoint); nextPoint += positionAdd; } } break; case 2: // top to right { IntPoint nextPoint = new IntPoint(); for (int yIndex = 0; yIndex < yLineCount; yIndex++) { long yPosition = boundary.min.Y + yIndex * perIncrementOffset; bool createLineSegment = ((yPosition / perIncrementOffset) % 2) == 0; if (createLineSegment) { nextPoint = new IntPoint(boundary.min.X, yPosition); yield return(nextPoint); } } IntPoint positionAdd = new IntPoint(lineSpacing, 0); nextPoint += positionAdd; while (nextPoint.X > boundary.min.X && nextPoint.X < boundary.max.X) { yield return(nextPoint); nextPoint += positionAdd; } } break; } }
private static IEnumerable <IntPoint> IncrementPositionIterator(IntPoint startPoint, Aabb boundary, int lineSpacing, int layerIndex) { IntPoint positionAdd = new IntPoint(lineSpacing, 0); int perIncrementOffset = (int)(lineSpacing * Math.Sqrt(3) / 2 + .5); switch (layerIndex % 3) { case 0: // left to right positionAdd = new IntPoint(lineSpacing, 0); break; case 1: // left to top positionAdd = new IntPoint(lineSpacing / 2, perIncrementOffset); break; case 2: // top to right positionAdd = new IntPoint(lineSpacing / 2, -perIncrementOffset); break; } IntPoint nextPoint = startPoint; do { yield return(nextPoint); nextPoint += positionAdd; } while (nextPoint.X > boundary.min.X && nextPoint.X < boundary.max.X && nextPoint.Y > boundary.min.Y && nextPoint.Y < boundary.max.Y); }
public bool BridgeAngle(Polygons areaGoingOnTop, long perimeterExpandDistance, out double bridgeAngle, Polygons bridgeAreas, string debugName = "") { SliceLayer layerToRestOn = this; bridgeAngle = -1; var boundaryBox = new Aabb(areaGoingOnTop); boundaryBox.Expand(perimeterExpandDistance); // To detect if we have a bridge, first calculate the intersection of the current layer with the previous layer. // This gives us the islands that the layer rests on. var islandsToRestOn = new Polygons(); foreach (LayerIsland islandToRestOn in layerToRestOn.Islands) { if (!boundaryBox.Hit(islandToRestOn.BoundingBox)) { continue; } islandsToRestOn.AddRange(areaGoingOnTop.CreateIntersection(islandToRestOn.IslandOutline)); } if (bridgeAreas != null) { bridgeAreas.AddRange(areaGoingOnTop.CreateDifference(layerToRestOn.AllOutlines)); } if (outputDebugData) { WriteDebugData(areaGoingOnTop, layerToRestOn, islandsToRestOn); } if (islandsToRestOn.Count > 5 || islandsToRestOn.Count < 1) { return(false); } if (islandsToRestOn.Count == 1) { return(GetSingleIslandAngle(areaGoingOnTop, islandsToRestOn[0], out bridgeAngle, debugName)); } // Find the 2 largest islands that we rest on. double biggestArea = 0; double nextBiggestArea = 0; int indexOfBiggest = -1; int indexOfNextBigest = -1; for (int islandIndex = 0; islandIndex < islandsToRestOn.Count; islandIndex++) { // Skip internal holes if (!islandsToRestOn[islandIndex].Orientation()) { continue; } double area = Math.Abs(islandsToRestOn[islandIndex].Area()); if (area > biggestArea) { if (biggestArea > nextBiggestArea) { nextBiggestArea = biggestArea; indexOfNextBigest = indexOfBiggest; } biggestArea = area; indexOfBiggest = islandIndex; } else if (area > nextBiggestArea) { nextBiggestArea = area; indexOfNextBigest = islandIndex; } } if (indexOfBiggest < 0 || indexOfNextBigest < 0) { return(false); } IntPoint center1 = islandsToRestOn[indexOfBiggest].CenterOfMass(); IntPoint center2 = islandsToRestOn[indexOfNextBigest].CenterOfMass(); bridgeAngle = Math.Atan2(center2.Y - center1.Y, center2.X - center1.X) / Math.PI * 180; Range0To360(ref bridgeAngle); if (outputDebugData) { islandsToRestOn.SaveToGCode("{0} - angle {1:0.}.gcode".FormatWith(debugName, bridgeAngle)); } return(true); }
public bool BridgeAngle(Polygons areaAboveToFill, out double bridgeAngle, string debugName = "") { SliceLayer layerToRestOn = this; bridgeAngle = -1; Aabb boundaryBox = new Aabb(areaAboveToFill); // To detect if we have a bridge, first calculate the intersection of the current layer with the previous layer. // This gives us the islands that the layer rests on. Polygons islandsToRestOn = new Polygons(); foreach (LayerIsland islandToRestOn in layerToRestOn.Islands) { if (!boundaryBox.Hit(islandToRestOn.BoundingBox)) { continue; } islandsToRestOn.AddRange(areaAboveToFill.CreateIntersection(islandToRestOn.IslandOutline)); } if (OUTPUT_DEBUG_DATA) { string outlineString = areaAboveToFill.WriteToString(); string islandOutlineString = ""; foreach (LayerIsland prevLayerIsland in layerToRestOn.Islands) { foreach (Polygon islandOutline in prevLayerIsland.IslandOutline) { islandOutlineString += islandOutline.WriteToString(); } islandOutlineString += "|"; } string islandsString = islandsToRestOn.WriteToString(); } if (islandsToRestOn.Count > 5 || islandsToRestOn.Count < 1) { return(false); } if (islandsToRestOn.Count == 1) { return(GetSingleIslandAngle(areaAboveToFill, islandsToRestOn[0], out bridgeAngle, debugName)); } // Find the 2 largest islands that we rest on. double biggestArea = 0; double nextBiggestArea = 0; int indexOfBiggest = -1; int indexOfNextBigest = -1; for (int islandIndex = 0; islandIndex < islandsToRestOn.Count; islandIndex++) { // Skip internal holes if (!islandsToRestOn[islandIndex].Orientation()) { continue; } double area = Math.Abs(islandsToRestOn[islandIndex].Area()); if (area > biggestArea) { if (biggestArea > nextBiggestArea) { nextBiggestArea = biggestArea; indexOfNextBigest = indexOfBiggest; } biggestArea = area; indexOfBiggest = islandIndex; } else if (area > nextBiggestArea) { nextBiggestArea = area; indexOfNextBigest = islandIndex; } } if (indexOfBiggest < 0 || indexOfNextBigest < 0) { return(false); } IntPoint center1 = islandsToRestOn[indexOfBiggest].CenterOfMass(); IntPoint center2 = islandsToRestOn[indexOfNextBigest].CenterOfMass(); bridgeAngle = Math.Atan2(center2.Y - center1.Y, center2.X - center1.X) / Math.PI * 180; Range0To360(ref bridgeAngle); if (OUTPUT_DEBUG_DATA) { islandsToRestOn.SaveToGCode("{0} - angle {1:0.}.gcode".FormatWith(debugName, bridgeAngle)); } return(true); }
private static Polygons RemoveIslandsFromPolygons(List<LayerIsland> islands, Aabb boundsToConsider, Polygons polygonsToSubtractFrom) { for (int islandIndex = 0; islandIndex < islands.Count; islandIndex++) { if (boundsToConsider.Hit(islands[islandIndex].BoundingBox)) { polygonsToSubtractFrom = polygonsToSubtractFrom.CreateDifference(islands[islandIndex].InsetToolPaths[islands[islandIndex].InsetToolPaths.Count - 1]); polygonsToSubtractFrom = Clipper.CleanPolygons(polygonsToSubtractFrom, cleanDistance_um); } } return polygonsToSubtractFrom; }
private static Polygons AddIslandsToPolygons(List<LayerIsland> islands, Aabb boundsToConsider, Polygons polysToAddTo) { Polygons polysToIntersect = new Polygons(); for (int islandIndex = 0; islandIndex < islands.Count; islandIndex++) { if (boundsToConsider.Hit(islands[islandIndex].BoundingBox)) { polysToIntersect = polysToIntersect.CreateUnion(islands[islandIndex].InsetToolPaths[islands[islandIndex].InsetToolPaths.Count - 1]); polysToIntersect = Clipper.CleanPolygons(polysToIntersect, cleanDistance_um); } } polysToAddTo = polysToAddTo.CreateIntersection(polysToIntersect); return polysToAddTo; }
private static Polygons RemoveIslandsFromPolygons(List <LayerIsland> islands, Aabb boundsToConsider, Polygons polygonsToSubtractFrom) { for (int islandIndex = 0; islandIndex < islands.Count; islandIndex++) { if (boundsToConsider.Hit(islands[islandIndex].BoundingBox)) { if (islands[islandIndex].InsetToolPaths.Count > 0) { polygonsToSubtractFrom = polygonsToSubtractFrom.CreateDifference(islands[islandIndex].InsetToolPaths[islands[islandIndex].InsetToolPaths.Count - 1]); polygonsToSubtractFrom = Clipper.CleanPolygons(polygonsToSubtractFrom, cleanDistance_um); } } } return(polygonsToSubtractFrom); }
public static bool BridgeAngle(Polygons outline, SliceLayer prevLayer, out double bridgeAngle, string debugName = "") { bridgeAngle = -1; Aabb boundaryBox = new Aabb(outline); //To detect if we have a bridge, first calculate the intersection of the current layer with the previous layer. // This gives us the islands that the layer rests on. Polygons islands = new Polygons(); foreach (SliceLayerPart prevLayerPart in prevLayer.parts) { if (!boundaryBox.Hit(prevLayerPart.BoundingBox)) { continue; } islands.AddRange(outline.CreateIntersection(prevLayerPart.TotalOutline)); } #if OUTPUT_DEBUG_DATA string outlineString = outline.WriteToString(); string partOutlineString = ""; foreach (SliceLayerPart prevLayerPart in prevLayer.parts) { foreach (Polygon prevPartOutline in prevLayerPart.outline) { partOutlineString += prevPartOutline.WriteToString(); } partOutlineString += "|"; } string islandsString = islands.WriteToString(); #endif if (islands.Count > 5 || islands.Count < 1) { return(false); } if (islands.Count == 1) { return(GetSingleIslandAngle(outline, islands[0], out bridgeAngle, debugName)); } // Find the 2 largest islands that we rest on. double biggestArea = 0; double nextBiggestArea = 0; int indexOfBiggest = -1; int indexOfNextBigest = -1; for (int islandIndex = 0; islandIndex < islands.Count; islandIndex++) { //Skip internal holes if (!islands[islandIndex].Orientation()) { continue; } double area = Math.Abs(islands[islandIndex].Area()); if (area > biggestArea) { if (biggestArea > nextBiggestArea) { nextBiggestArea = biggestArea; indexOfNextBigest = indexOfBiggest; } biggestArea = area; indexOfBiggest = islandIndex; } else if (area > nextBiggestArea) { nextBiggestArea = area; indexOfNextBigest = islandIndex; } } if (indexOfBiggest < 0 || indexOfNextBigest < 0) { return(false); } IntPoint center1 = islands[indexOfBiggest].CenterOfMass(); IntPoint center2 = islands[indexOfNextBigest].CenterOfMass(); bridgeAngle = Math.Atan2(center2.Y - center1.Y, center2.X - center1.X) / Math.PI * 180; Range0To360(ref bridgeAngle); #if OUTPUT_DEBUG_DATA islands.SaveToGCode("{0} - angle {1:0.}.gcode".FormatWith(debugName, bridgeAngle)); #endif return(true); }
private static Polygons IntersectWithSparsePolygons(List <LayerIsland> islands, Aabb boundsToConsider, Polygons polysToIntersect) { Polygons polysFromIslands = new Polygons(); for (int islandIndex = 0; islandIndex < islands.Count; islandIndex++) { if (boundsToConsider.Hit(islands[islandIndex].BoundingBox)) { if (islands[islandIndex].InsetToolPaths.Count > 0) { polysFromIslands = polysFromIslands.CreateUnion(islands[islandIndex].SparseInfillPaths); polysFromIslands = Clipper.CleanPolygons(polysFromIslands, cleanDistance_um); } } } polysToIntersect = polysToIntersect.CreateIntersection(polysFromIslands); return(polysToIntersect); }
private static IEnumerable<IntPoint> StartPositionIterator(Aabb boundary, int lineSpacing, int layerIndex) { int perIncrementOffset = (int)(lineSpacing * Math.Sqrt(3) / 2 + .5); int yLineCount = (int)((boundary.max.Y - boundary.min.Y + perIncrementOffset) / perIncrementOffset) + 1; switch (layerIndex % 3) { case 0: // left to right for (int yIndex = 0; yIndex < yLineCount; yIndex++) { long yPosition = boundary.min.Y + yIndex * perIncrementOffset; bool removeXOffset = ((yPosition / perIncrementOffset) % 2) == 0; long xOffsetForY = lineSpacing / 2; if (removeXOffset) // if we are at every other y { xOffsetForY = 0; } long firstX = boundary.min.X + xOffsetForY; yield return new IntPoint(firstX, yPosition); } break; case 1: // left to top { IntPoint nextPoint = new IntPoint(); for (int yIndex = yLineCount; yIndex >= 0; yIndex--) { long yPosition = boundary.min.Y + yIndex * perIncrementOffset; bool createLineSegment = ((yPosition / perIncrementOffset) % 2) == 0; if (createLineSegment) { nextPoint = new IntPoint(boundary.min.X, yPosition); yield return nextPoint; } } IntPoint positionAdd = new IntPoint(lineSpacing, 0); nextPoint += positionAdd; while (nextPoint.X > boundary.min.X && nextPoint.X < boundary.max.X) { yield return nextPoint; nextPoint += positionAdd; } } break; case 2: // top to right { IntPoint nextPoint = new IntPoint(); for (int yIndex = 0; yIndex < yLineCount; yIndex++) { long yPosition = boundary.min.Y + yIndex * perIncrementOffset; bool createLineSegment = ((yPosition / perIncrementOffset) % 2) == 0; if (createLineSegment) { nextPoint = new IntPoint(boundary.min.X, yPosition); yield return nextPoint; } } IntPoint positionAdd = new IntPoint(lineSpacing, 0); nextPoint += positionAdd; while (nextPoint.X > boundary.min.X && nextPoint.X < boundary.max.X) { yield return nextPoint; nextPoint += positionAdd; } } break; } }
public static void GenerateHexLinePaths(Polygons in_outline, Polygons result, int lineSpacing, long infillExtendIntoPerimeter_um, double rotationDegrees, int layerIndex) { int extraRotationAngle = 0; if (in_outline.Count > 0) { Polygons outlines = in_outline.Offset(infillExtendIntoPerimeter_um); if (outlines.Count > 0) { int perIncrementOffset = (int)(lineSpacing * Math.Sqrt(3) / 2 + .5); PointMatrix matrix = new PointMatrix(-(rotationDegrees + extraRotationAngle)); // we are rotating the part so we rotate by the negative so the lines go the way we expect outlines.ApplyMatrix(matrix); Aabb boundary = new Aabb(outlines); boundary.min.X = ((boundary.min.X / lineSpacing) - 1) * lineSpacing; boundary.min.Y = ((boundary.min.Y / perIncrementOffset) - 2) * perIncrementOffset; boundary.max.X += lineSpacing; boundary.max.Y += perIncrementOffset; Polygons unclippedPattern = new Polygons(); foreach (IntPoint startPoint in StartPositionIterator(boundary, lineSpacing, layerIndex)) { Polygon attachedLine = new Polygon(); foreach (IntPoint center in IncrementPositionIterator(startPoint, boundary, lineSpacing, layerIndex)) { // what we are adding are the little pluses that define the points // | top // | // /\ center // left/ \ right // IntPoint left = center + new IntPoint(-lineSpacing / 2, -perIncrementOffset / 3); IntPoint right = center + new IntPoint(lineSpacing / 2, -perIncrementOffset / 3); IntPoint top = center + new IntPoint(0, perIncrementOffset * 2 / 3); switch (layerIndex % 3) { case 0: // left to right attachedLine.Add(left); attachedLine.Add(center); attachedLine.Add(center); attachedLine.Add(right); unclippedPattern.Add(new Polygon() { top, center }); break; case 1: // left to top attachedLine.Add(left); attachedLine.Add(center); attachedLine.Add(center); attachedLine.Add(top); unclippedPattern.Add(new Polygon() { center, right }); break; case 2: // top to right attachedLine.Add(top); attachedLine.Add(center); attachedLine.Add(center); attachedLine.Add(right); unclippedPattern.Add(new Polygon() { left, center }); break; } } if (attachedLine.Count > 0) { unclippedPattern.Add(attachedLine); } } PolyTree ret = new PolyTree(); Clipper clipper = new Clipper(); clipper.AddPaths(unclippedPattern, PolyType.ptSubject, false); clipper.AddPaths(outlines, PolyType.ptClip, true); clipper.Execute(ClipType.ctIntersection, ret, PolyFillType.pftPositive, PolyFillType.pftEvenOdd); Polygons newSegments = Clipper.OpenPathsFromPolyTree(ret); PointMatrix inversematrix = new PointMatrix((rotationDegrees + extraRotationAngle)); newSegments.ApplyMatrix(inversematrix); result.AddRange(newSegments); } } }
public static bool BridgeAngle(Polygons outline, SliceLayer prevLayer, out double bridgeAngle, string debugName = "") { bridgeAngle = -1; Aabb boundaryBox = new Aabb(outline); //To detect if we have a bridge, first calculate the intersection of the current layer with the previous layer. // This gives us the islands that the layer rests on. Polygons islands = new Polygons(); foreach (SliceLayerPart prevLayerPart in prevLayer.parts) { if (!boundaryBox.Hit(prevLayerPart.BoundingBox)) { continue; } islands.AddRange(outline.CreateIntersection(prevLayerPart.TotalOutline)); } #if OUTPUT_DEBUG_DATA string outlineString = outline.WriteToString(); string partOutlineString = ""; foreach (SliceLayerPart prevLayerPart in prevLayer.parts) { foreach (Polygon prevPartOutline in prevLayerPart.outline) { partOutlineString += prevPartOutline.WriteToString(); } partOutlineString += "|"; } string islandsString = islands.WriteToString(); #endif if (islands.Count > 5 || islands.Count < 1) { return false; } if (islands.Count == 1) { return GetSingleIslandAngle(outline, islands[0], out bridgeAngle, debugName); } // Find the 2 largest islands that we rest on. double biggestArea = 0; double nextBiggestArea = 0; int indexOfBiggest = -1; int indexOfNextBigest = -1; for (int islandIndex = 0; islandIndex < islands.Count; islandIndex++) { //Skip internal holes if (!islands[islandIndex].Orientation()) { continue; } double area = Math.Abs(islands[islandIndex].Area()); if (area > biggestArea) { if (biggestArea > nextBiggestArea) { nextBiggestArea = biggestArea; indexOfNextBigest = indexOfBiggest; } biggestArea = area; indexOfBiggest = islandIndex; } else if (area > nextBiggestArea) { nextBiggestArea = area; indexOfNextBigest = islandIndex; } } if (indexOfBiggest < 0 || indexOfNextBigest < 0) { return false; } IntPoint center1 = islands[indexOfBiggest].CenterOfMass(); IntPoint center2 = islands[indexOfNextBigest].CenterOfMass(); bridgeAngle = Math.Atan2(center2.Y - center1.Y, center2.X - center1.X) / Math.PI * 180; Range0To360(ref bridgeAngle); #if OUTPUT_DEBUG_DATA islands.SaveToGCode("{0} - angle {1:0.}.gcode".FormatWith(debugName, bridgeAngle)); #endif return true; }