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); } } }
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; }
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); }
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); }
public PathFinder(Polygons outlinePolygons, long avoidInset, IntRect?stayInsideBounds = null) { if (outlinePolygons.Count == 0) { return; } OutlinePolygons = FixWinding(outlinePolygons); OutlinePolygons = Clipper.CleanPolygons(OutlinePolygons, avoidInset / 60); InsetAmount = avoidInset; if (stayInsideBounds != null) { var boundary = stayInsideBounds.Value; OutlinePolygons.Add(new Polygon() { new IntPoint(boundary.minX, boundary.minY), new IntPoint(boundary.maxX, boundary.minY), new IntPoint(boundary.maxX, boundary.maxY), new IntPoint(boundary.minX, boundary.maxY), }); OutlinePolygons = FixWinding(OutlinePolygons); } BoundaryPolygons = OutlinePolygons.Offset(stayInsideBounds == null ? -avoidInset : -2 * avoidInset); BoundaryPolygons = FixWinding(BoundaryPolygons); OutlineEdgeQuadTrees = OutlinePolygons.GetEdgeQuadTrees(); OutlinePointQuadTrees = OutlinePolygons.GetPointQuadTrees(); BoundaryEdgeQuadTrees = BoundaryPolygons.GetEdgeQuadTrees(); BoundaryPointQuadTrees = BoundaryPolygons.GetPointQuadTrees(); foreach (var polygon in BoundaryPolygons) { Waypoints.AddPolygon(polygon); } // hook up path segments between the separate islands if (simpleHookup) // do a simple hookup { for (int indexA = 0; indexA < BoundaryPolygons.Count; indexA++) { var polyA = BoundaryPolygons[indexA]; if (polyA.GetWindingDirection() > 0) { Func <int, Polygon, bool> ConsiderPolygon = (polyIndex, poly) => { return(polyIndex != indexA && poly.GetWindingDirection() > 0); }; // find the closest two points between A and any other polygon IntPoint bestAPos = polyA.Center(); Func <int, IntPoint, bool> ConsiderPoint = (polyIndex, edgeEnd) => { if (OutlinePolygons.PointIsInside((bestAPos + edgeEnd) / 2, OutlineEdgeQuadTrees, OutlinePointQuadTrees)) { return(true); } return(false); }; var bestBPoly = BoundaryPolygons.FindClosestPoint(bestAPos, ConsiderPolygon, ConsiderPoint); if (bestBPoly.polyIndex == -1) { // find one that intersects bestBPoly = BoundaryPolygons.FindClosestPoint(bestAPos, ConsiderPolygon); } if (bestBPoly.polyIndex != -1) { bestAPos = polyA.FindClosestPoint(bestBPoly.Item3).Item2; var bestBResult = BoundaryPolygons[bestBPoly.Item1].FindClosestPoint(bestAPos, ConsiderPoint); IntPoint bestBPos = new IntPoint(); if (bestBResult.index != -1) { bestBPos = bestBResult.Item2; } else { // find one that intersects bestBPos = BoundaryPolygons[bestBPoly.Item1].FindClosestPoint(bestAPos).Item2; } bestAPos = polyA.FindClosestPoint(bestBPos).Item2; bestBPos = BoundaryPolygons[bestBPoly.Item1].FindClosestPoint(bestAPos).Item2; // hook the polygons up along this connection IntPointNode nodeA = Waypoints.FindNode(bestAPos); IntPointNode nodeB = Waypoints.FindNode(bestBPos); Waypoints.AddPathLink(nodeA, nodeB); } } } } else // hook up using thin lines code { // this is done with merge close edges and finding candidates // then joining the ends of the merged segments with the closest points Polygons thinLines; if (OutlinePolygons.FindThinLines(avoidInset * 2, 0, out thinLines)) { ThinLinePolygons = thinLines; for (int thinIndex = 0; thinIndex < thinLines.Count; thinIndex++) { var thinPolygon = thinLines[thinIndex]; if (thinPolygon.Count > 1) { Waypoints.AddPolygon(thinPolygon, false); } } Polygons allPolygons = new Polygons(thinLines); allPolygons.AddRange(BoundaryPolygons); for (int thinIndex = 0; thinIndex < thinLines.Count; thinIndex++) { var thinPolygon = thinLines[thinIndex]; if (thinPolygon.Count > 1) { // now hook up the start and end of this polygon to the existing way points var closestStart = allPolygons.FindClosestPoint(thinPolygon[0], (polyIndex, poly) => { return(polyIndex == thinIndex); }); var closestEnd = allPolygons.FindClosestPoint(thinPolygon[thinPolygon.Count - 1], (polyIndex, poly) => { return(polyIndex == thinIndex); }); // last point if (OutlinePolygons.PointIsInside((closestStart.Item3 + closestEnd.Item3) / 2, OutlineEdgeQuadTrees)) { IntPointNode nodeA = Waypoints.FindNode(closestStart.Item3); IntPointNode nodeB = Waypoints.FindNode(closestEnd.Item3); if (nodeA != null && nodeB != null) { Waypoints.AddPathLink(nodeA, nodeB); } } } } } } removePointList = new WayPointsToRemove(Waypoints); }
public Polygon2DArray(IEnumerable <Polygon2D> polygons) { Polygons.AddRange(polygons); }
private void CreateCube(List <Vector4> points, Matrix4x4 VP, Vector4 translate) { var newPoints = new List <Vector4>(); for (int i = 0; i < points.Count(); i++) { var tmp = points[i] + translate; //tmp = tmp.Multiply(VP); //if (tmp.W != 0) //{ // tmp /= tmp.W; //} newPoints.Add( new Vector4(tmp.X, tmp.Y, tmp.Z, tmp.W)); } Polygons.AddRange( new List <Polygon3> { new Polygon3( new List <Vector4> { newPoints[0], newPoints[1], newPoints[2] } ), new Polygon3( new List <Vector4> { newPoints[0], newPoints[2], newPoints[3] } ), new Polygon3( new List <Vector4> { newPoints[1], newPoints[5], newPoints[6] } ), new Polygon3( new List <Vector4> { newPoints[1], newPoints[2], newPoints[6] } ), new Polygon3( new List <Vector4> { newPoints[4], newPoints[5], newPoints[6] } ), new Polygon3( new List <Vector4> { newPoints[4], newPoints[6], newPoints[7] } ), new Polygon3( new List <Vector4> { newPoints[0], newPoints[4], newPoints[3] } ), new Polygon3( new List <Vector4> { newPoints[4], newPoints[3], newPoints[7] } ), new Polygon3( new List <Vector4> { newPoints[0], newPoints[4], newPoints[5] } ), new Polygon3( new List <Vector4> { newPoints[0], newPoints[1], newPoints[5] } ), new Polygon3( new List <Vector4> { newPoints[3], newPoints[2], newPoints[6] } ), new Polygon3( new List <Vector4> { newPoints[3], newPoints[7], newPoints[6] } ) }.AsEnumerable() ); }
/// <summary> /// Setter for setting polygons to a complex polygon. /// </summary> /// <param name="polygons">List of polygons.</param> public void SetPolygons(List <Polygon> polygons) { Polygons.Clear(); Polygons.AddRange(polygons); }