public static List <GeneralPolygon2d> ComputeOffsetPolygon(GeneralPolygon2d poly, double fOffset, bool bMiter = false) { double nIntScale = GetIntScale(poly); CPolygonList clipper_polys = new CPolygonList(); clipper_polys.Add(ClipperUtil.ConvertToClipper(poly.Outer, nIntScale)); foreach (Polygon2d hole in poly.Holes) { clipper_polys.Add(ClipperUtil.ConvertToClipper(hole, nIntScale)); } CPolygonList dilate_solution = new CPolygonList(); try { ClipperOffset co = new ClipperOffset(); if (bMiter) { co.AddPaths(clipper_polys, JoinType.jtMiter, EndType.etClosedPolygon); } else { co.AddPaths(clipper_polys, JoinType.jtRound, EndType.etClosedPolygon); } co.Execute(ref dilate_solution, fOffset * nIntScale); } catch /*( Exception e )*/ { //System.Diagnostics.Debug.WriteLine("ClipperUtil.ComputeOffsetPolygon: Clipper threw exception: " + e.Message); return(new List <GeneralPolygon2d>()); } List <GeneralPolygon2d> polys = ClipperUtil.ConvertFromClipper(dilate_solution, nIntScale); return(polys); }
/// <summary> /// Compute offset polygon from all input polys (ie separate islands may merge) /// </summary> public static List <GeneralPolygon2d> ComputeOffsetPolygon(IEnumerable <GeneralPolygon2d> polys, double fOffset, bool bMiter = false, double minArea = -1) { double nIntScale = GetIntScale(polys); if (minArea < 0) { minArea = DiscardMinArea; } ClipperOffset co = new ClipperOffset(); PolyTree tree = new PolyTree(); try { foreach (GeneralPolygon2d poly in polys) { CPolygonList clipper_poly = ConvertToClipper(poly, nIntScale); if (bMiter) { co.AddPaths(clipper_poly, JoinType.jtMiter, EndType.etClosedPolygon); } else { co.AddPaths(clipper_poly, JoinType.jtRound, EndType.etClosedPolygon); } } co.Execute(ref tree, fOffset * nIntScale); List <GeneralPolygon2d> result = new List <GeneralPolygon2d>(); for (int ci = 0; ci < tree.ChildCount; ++ci) { Convert(tree.Childs[ci], result, nIntScale, minArea); } return(result); } catch /*(Exception e)*/ { //System.Diagnostics.Debug.WriteLine("ClipperUtil.ComputeOffsetPolygon: Clipper threw exception: " + e.Message); return(new List <GeneralPolygon2d>()); } }
public static List <GeneralPolygon2d> ComputeOffsetPolygon(Polygon2d poly, double fOffset, bool bSharp = false) { double nIntScale = GetIntScale(poly.Vertices); List <IntPoint> clipper_poly = ClipperUtil.ConvertToClipper(poly, nIntScale); CPolygonList clipper_polys = new CPolygonList() { clipper_poly }; CPolygonList dilate_solution = new CPolygonList(); try { ClipperOffset co = new ClipperOffset(); if (bSharp) { co.AddPaths(clipper_polys, JoinType.jtMiter, EndType.etClosedPolygon); } else { co.AddPaths(clipper_polys, JoinType.jtRound, EndType.etClosedPolygon); } co.Execute(ref dilate_solution, fOffset * nIntScale); } catch /*( Exception e )*/ { //System.Diagnostics.Debug.WriteLine("ClipperUtil.ComputeOffsetPolygon: Clipper threw exception: " + e.Message); return(new List <GeneralPolygon2d>()); } if (dilate_solution.Count == 0) { return(new List <GeneralPolygon2d>()); } List <GeneralPolygon2d> polys = ClipperUtil.ConvertFromClipper(dilate_solution, nIntScale); return(polys); }
/// <summary> /// remove portions of polyline that are inside set of solids /// </summary> public static List <PolyLine2d> ClipAgainstPolygon(IEnumerable <GeneralPolygon2d> solids, PolyLine2d polyline, bool bIntersect = false) { double nIntScale = Math.Max(GetIntScale(solids), GetIntScale(polyline.Vertices)); List <PolyLine2d> result = new List <PolyLine2d>(); Clipper clip = new Clipper(); PolyTree tree = new PolyTree(); try { foreach (GeneralPolygon2d poly in solids) { CPolygonList clipper_poly = ConvertToClipper(poly, nIntScale); clip.AddPaths(clipper_poly, PolyType.ptClip, true); } CPolyPath path = ConvertToClipper(polyline, nIntScale); clip.AddPath(path, PolyType.ptSubject, false); if (bIntersect) { clip.Execute(ClipType.ctIntersection, tree); } else { clip.Execute(ClipType.ctDifference, tree); } for (int ci = 0; ci < tree.ChildCount; ++ci) { if (tree.Childs[ci].IsOpen == false) { continue; } PolyLine2d clippedPath = ConvertFromClipperPath(tree.Childs[ci].Contour, nIntScale); // clipper just cuts up the polylines, we still have to figure out containment ourselves. // Currently just checking based on point around middle of polyline... // [TODO] can we get clipper to not return the inside ones? Vector2d qp = (clippedPath.VertexCount > 2) ? clippedPath[clippedPath.VertexCount / 2] : clippedPath.Segment(0).Center; bool inside = false; foreach (var poly in solids) { if (poly.Contains(qp)) { inside = true; break; } } if (inside == bIntersect) { result.Add(clippedPath); } } } catch /*(Exception e)*/ { // [TODO] what to do here? //System.Diagnostics.Debug.WriteLine("ClipperUtil.ClipAgainstPolygon: Clipper threw exception: " + e.Message); return(new List <PolyLine2d>()); } return(result); }
public static List <GeneralPolygon2d> PolygonBoolean( ICollection <GeneralPolygon2d> poly1, ICollection <GeneralPolygon2d> poly2, BooleanOp opType, double minArea = -1) { // handle cases where one list is empty if (poly1.Count == 0) { if (opType == BooleanOp.Difference || opType == BooleanOp.Intersection) { return(new List <GeneralPolygon2d>()); } else { return(DeepCopy.List(poly2)); } } else if (poly2.Count == 0) { if (opType == BooleanOp.Intersection) { return(new List <GeneralPolygon2d>()); } else { return(DeepCopy.List(poly1)); } } double nIntScale = Math.Max(GetIntScale(poly1), GetIntScale(poly2)); if (minArea < 0) { minArea = DiscardMinArea; } try { Clipper clipper = new Clipper(Clipper.ioStrictlySimple); foreach (GeneralPolygon2d sub in poly1) { CPolygonList cpoly = ConvertToClipper(sub, nIntScale); clipper.AddPaths(cpoly, PolyType.ptSubject, true); } foreach (GeneralPolygon2d clip in poly2) { CPolygonList cpoly = ConvertToClipper(clip, nIntScale); clipper.AddPaths(cpoly, PolyType.ptClip, true); } ClipType cType = ClipType.ctUnion; if (opType == BooleanOp.Difference) { cType = ClipType.ctDifference; } else if (opType == BooleanOp.Intersection) { cType = ClipType.ctIntersection; } else if (opType == BooleanOp.Xor) { cType = ClipType.ctXor; } PolyTree tree = new PolyTree(); bool bOK = clipper.Execute(cType, tree); if (bOK == false) { //System.Diagnostics.Debug.WriteLine("ClipperUtil.PolygonBoolean: Clipper failed"); return(new List <GeneralPolygon2d>()); } List <GeneralPolygon2d> result = new List <GeneralPolygon2d>(); for (int ci = 0; ci < tree.ChildCount; ++ci) { Convert(tree.Childs[ci], result, nIntScale, minArea); } return(result); } catch /*(Exception e)*/ { //System.Diagnostics.Debug.WriteLine("ClipperUtil.PolygonBoolean: Clipper threw exception: " + e.Message); return(new List <GeneralPolygon2d>()); } }
public static List <GeneralPolygon2d> ConvertFromClipper(CPolygonList clipper_polys, double nIntScale) { List <GeneralPolygon2d> result = new List <GeneralPolygon2d>(); try { // convert clipper polys to Polygon2d List <Polygon2d> polys = new List <Polygon2d>(); int N = clipper_polys.Count; for (int i = 0; i < N; ++i) { Polygon2d poly = ConvertFromClipper(clipper_polys[i], nIntScale); if (poly != null) { polys.Add(poly); } } // sort polygons into outer/holes // [TODO] clipper can figure this out for us...perhaps faster?? // find the 'outer' polygons. Here we are assuming // that outer polygons are CCW... bool[] done = new bool[N]; Array.Clear(done, 0, N); for (int i = 0; i < N; ++i) { if (polys[i].IsClockwise == false) { GeneralPolygon2d gp = new GeneralPolygon2d(); gp.Outer = polys[i]; result.Add(gp); done[i] = true; } } // compute bboxes AxisAlignedBox2d[] outerBounds = new AxisAlignedBox2d[result.Count]; for (int i = 0; i < result.Count; ++i) { outerBounds[i] = result[i].Outer.GetBounds(); } // remaining polygons are holes. Figure out which outer // they belong too. Only difficult if there is more than one option. for (int i = 0; i < N; ++i) { if (done[i]) { continue; } if (result.Count == 1) { result[0].AddHole(polys[i], false); done[i] = true; continue; } AxisAlignedBox2d box = polys[i].GetBounds(); for (int j = 0; j < result.Count; ++j) { if (outerBounds[j].Contains(box) == false) { continue; } if (result[j].Outer.Contains(polys[i])) { result[j].AddHole(polys[i], false); } done[i] = true; } // uh-oh...now what? perhaps should force a full N-pair test/sort if this happens? if (done[i] == false) { System.Diagnostics.Debug.WriteLine("ClipperUtil.ConvertFromClipper: could not find parent for polygon " + i.ToString()); } } } catch /*( Exception e )*/ { //System.Diagnostics.Debug.WriteLine("ClipperUtil.ConvertFromClipper: caught exception: " + e.Message); } return(result); }