public static List <Polyline> Boolean(ClipType clipType, IEnumerable <Polyline> polyA, IEnumerable <Polyline> polyB, Plane pln, double tolerance, bool evenOddFilling) { Clipper clipper = new Clipper(0); PolyFillType polyfilltype = PolyFillType.pftEvenOdd; if (!evenOddFilling) { polyfilltype = PolyFillType.pftNonZero; } List <List <IntPoint> > PathsA = new List <List <IntPoint> >(); List <List <IntPoint> > PathsB = new List <List <IntPoint> >(); foreach (Polyline plA in polyA) { clipper.AddPath(plA.ToPath2D(pln, tolerance), PolyType.ptSubject, plA.IsClosed); } foreach (Polyline plB in polyB) { clipper.AddPath(plB.ToPath2D(pln, tolerance), PolyType.ptClip, true); } PolyTree OutputTree = new PolyTree(); clipper.Execute(clipType, OutputTree, polyfilltype, polyfilltype); List <Polyline> Output = new List <Polyline> (); foreach (PolyNode pn in OutputTree.Iterate()) { if (pn.Contour.Count > 1) { Output.Add(pn.Contour.ToPolyline(pln, tolerance, !pn.IsOpen)); } } return(Output); }
public static List <Polyline> Boolean(ClipType clipType, IEnumerable <Polyline> polyA, IEnumerable <Polyline> polyB, Plane pln, double tolerance, bool evenOddFilling) { NGonsCore.Clipper642.Clipper clipper = new NGonsCore.Clipper642.Clipper(); PolyFillType polyfilltype = PolyFillType.pftEvenOdd; if (!evenOddFilling) { polyfilltype = PolyFillType.pftNonZero; } foreach (Polyline plA in polyA) { clipper.AddPath(plA.ToPath2D(pln, tolerance), PolyType.ptSubject, plA.IsClosed); } foreach (Polyline plB in polyB) { clipper.AddPath(plB.ToPath2D(pln, tolerance), PolyType.ptClip, true); } PolyTree polytree = new PolyTree(); clipper.Execute(clipType, polytree, polyfilltype, polyfilltype); List <Polyline> output = new List <Polyline>(); // ReSharper disable once LoopCanBeConvertedToQuery foreach (PolyNode pn in polytree.Iterate()) { if (pn.Contour.Count > 1) { output.Add(pn.Contour.ToPolyline(pln, tolerance, !pn.IsOpen)); } } return(output); }
/// <summary> /// Offsets the specified polylines. /// </summary> /// <param name="polylines">A list of polylines</param> /// <param name="openFilletType">Optional: line endtype (Butt, Square, Round)</param> /// <param name="closedFilltetType">Optional: join type: Round, Miter (uses miter parameter) or Square</param> /// <param name="plane">Plane to project the polylines to</param> /// <param name="tolerance">Tolerance: Cutoff point. Eg. point {1.245; 9.244351; 19.3214} with precision {0.1} will be cut /// off to {1.2; 9.2; 19.3}.</param> /// <param name="distance">Distances to offset set of shapes.</param> /// <param name="miter">Miter deterimines how long narrow spikes can become before they are cut off: A miter setting of 2 /// means not longer than 2 times the offset distance. A miter of 25 will give big spikes.</param> /// <param name="arcTolerance">The arc tolerance.</param> /// <param name="outContour">The out contour.</param> /// <param name="outHoles">The out holes.</param> public static void Offset(IEnumerable <Polyline> polylines, List <OpenFilletType> openFilletType, List <ClosedFilletType> closedFilltetType, Plane plane, double tolerance, IEnumerable <double> distance, double miter, double arcTolerance, out List <List <Polyline> > outContour, out List <List <Polyline> > outHoles) { outContour = new List <List <Polyline> >(); outHoles = new List <List <Polyline> >(); /* * iEndType: How to handle open ended polygons. * Open Closed * etOpenSquare etClosedLine (fill inside & outside) * etOpenRound etClosedPolygon (fill outside only) * etOpenButt * * See: http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Types/EndType.htm */ /* * jtJoinType * How to fill angles of closed polygons * jtRound: Round * jtMiter: Square with variable distance * jtSquare: Square with fixed distance (jtMiter = 1) */ ClipperOffset cOffset = new ClipperOffset(miter, arcTolerance); int i = 0; foreach (Polyline pl in polylines) { EndType et = EndType.etOpenButt; JoinType jt = JoinType.jtSquare; if (pl.IsClosed) { et = EndType.etClosedLine; } else if (openFilletType.Count != 0) { OpenFilletType oft = IndexOrLast(openFilletType, i); switch (oft) { case OpenFilletType.Butt: et = EndType.etOpenButt; break; case OpenFilletType.Round: et = EndType.etOpenRound; break; case OpenFilletType.Square: et = EndType.etOpenSquare; break; } } else { et = EndType.etOpenButt; } if (closedFilltetType.Count != 0) { ClosedFilletType cft = IndexOrLast(closedFilltetType, i); switch (cft) { case ClosedFilletType.Miter: jt = JoinType.jtMiter; break; case ClosedFilletType.Round: jt = JoinType.jtRound; break; case ClosedFilletType.Square: jt = JoinType.jtSquare; break; } } else { jt = JoinType.jtSquare; } cOffset.AddPath(pl.ToPath2D(plane, tolerance), jt, et); i++; } foreach (double offsetDistance in distance) { PolyTree tree = new PolyTree(); cOffset.Execute(ref tree, offsetDistance / tolerance); List <Polyline> holes = new List <Polyline>(); List <Polyline> contours = new List <Polyline>(); foreach (PolyNode path in tree.Iterate()) { if (path.Contour.Count == 0) { continue; } Polyline polyline = path.Contour.ToPolyline(plane, tolerance, !path.IsOpen); if (path.IsHole) { holes.Add(polyline); } else { contours.Add(polyline); } } outContour.Add(contours); outHoles.Add(holes); } }
public override void Calculate() { ResultPaths = new List <Polyline>(); if (Stock == null || Stock.Count < 1 || DriveGeometry == null || DriveGeometry.Count < 1) { throw new Exception("Stock or drive geometry not set!"); } BoundingBox bb = Stock[0].GetBoundingBox(Workplane); foreach (Mesh m in Stock) { bb = BoundingBox.Union(bb, m.GetBoundingBox(Workplane)); } if (bb.IsDegenerate(0.1) > 0) { throw new Exception("Bounding Box is degenerate.");// return; } Point3d top = bb.Center; top.Z = bb.Corner(false, false, false).Z; Point3d bottom = bb.Center; bottom.Z = bb.Corner(true, true, true).Z; double TotalDepth = top.DistanceTo(bottom); int N = (int)(Math.Ceiling(Math.Min(MaxDepth, TotalDepth) / Tool.StepDown)); Plane CuttingPlane = new Plane(Workplane); Point3d top_xform = new Point3d(top); top_xform.Transform(Transform.PlaneToPlane(Plane.WorldXY, Workplane)); CuttingPlane.Origin = top_xform; Tuple <CPaths, CPaths, CPaths> Polygons; Polygons = GeneratePolygons(CuttingPlane); CPaths Shadow = new CPaths(Polygons.Item1); double Area = PathsArea(Shadow); for (int i = 0; i <= N; ++i) { // for each layer CuttingPlane.Origin = CuttingPlane.Origin - Workplane.ZAxis * Tool.StepDown; Polygons = GeneratePolygons(CuttingPlane, Shadow); if (Polygons == null) { throw new Exception("Failed to generate polygons!"); } double AreaNew = PathsArea(Polygons.Item1); if (AreaNew > Area) { Shadow = new CPaths(Polygons.Item1); Area = AreaNew; } ClipperOffset offset = new ClipperOffset(0.25, 0.25); offset.AddPaths(Polygons.Item3, JoinType.jtMiter, EndType.etClosedPolygon); PolyTree tree = new PolyTree(); offset.Execute(ref tree, -(Tool.Diameter / 2 + RestHorizontal) / Tolerance); CPaths WorkingPaths = new CPaths(); List <Polyline> Output = new List <Polyline>(); foreach (PolyNode pn in tree.Iterate()) { if (pn.Contour.Count > 0) { Output.Add(pn.Contour.ToPolyline(CuttingPlane, Tolerance, true)); WorkingPaths.Add(pn.Contour); } } int counter = 0; do { offset.Clear(); offset.AddPaths(WorkingPaths, JoinType.jtMiter, EndType.etClosedPolygon); offset.Execute(ref tree, -Tool.StepOver / Tolerance); WorkingPaths = new List <List <IntPoint> >(); foreach (PolyNode pn in tree.Iterate()) { if (pn.Contour.Count > 0) { Output.Add(pn.Contour.ToPolyline(CuttingPlane, Tolerance, true)); WorkingPaths.Add(pn.Contour); } } counter++; }while (tree.Total > 0 && counter < LOOP_LIMIT); ResultPaths.AddRange(Output); } ShadowPolylines = new List <Polyline>(); foreach (CPath p in Shadow) { ShadowPolylines.Add(p.ToPolyline(CuttingPlane, Tolerance, true)); } }