public void Execute(ref List <List <IntPoint> > solution, double delta) { solution.Clear(); FixOrientations(); DoOffset(delta); Clipper clipper = new Clipper(0); clipper.AddPaths(m_destPolys, PolyType.ptSubject, true); if (delta > 0.0) { clipper.Execute(ClipType.ctUnion, solution, PolyFillType.pftPositive, PolyFillType.pftPositive); } else { IntRect bounds = ClipperBase.GetBounds(m_destPolys); List <IntPoint> list = new List <IntPoint>(4); list.Add(new IntPoint(bounds.left - 10, bounds.bottom + 10)); list.Add(new IntPoint(bounds.right + 10, bounds.bottom + 10)); list.Add(new IntPoint(bounds.right + 10, bounds.top - 10)); list.Add(new IntPoint(bounds.left - 10, bounds.top - 10)); clipper.AddPath(list, PolyType.ptSubject, true); clipper.ReverseSolution = true; clipper.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative); if (solution.Count > 0) { solution.RemoveAt(0); } } }
public static Polygons GetCorrectedWinding(this Polygons polygonsToFix) { polygonsToFix = Clipper.CleanPolygons(polygonsToFix); Polygon boundsPolygon = new Polygon(); IntRect bounds = Clipper.GetBounds(polygonsToFix); bounds.minX -= 10; bounds.minY -= 10; bounds.maxY += 10; bounds.maxX += 10; boundsPolygon.Add(new IntPoint(bounds.minX, bounds.minY)); boundsPolygon.Add(new IntPoint(bounds.maxX, bounds.minY)); boundsPolygon.Add(new IntPoint(bounds.maxX, bounds.maxY)); boundsPolygon.Add(new IntPoint(bounds.minX, bounds.maxY)); Clipper clipper = new Clipper(); clipper.AddPaths(polygonsToFix, PolyType.ptSubject, true); clipper.AddPath(boundsPolygon, PolyType.ptClip, true); PolyTree intersectionResult = new PolyTree(); clipper.Execute(ClipType.ctIntersection, intersectionResult); Polygons outputPolygons = Clipper.ClosedPathsFromPolyTree(intersectionResult); return(outputPolygons); }
public static Ngons MinkowskiSumSegment(Ngon pattern, IntPoint p1, IntPoint p2, bool flip_pattern) { Clipper clipper = new Clipper(); Ngon p1_c = pattern.Clone(p1.X, p1.Y, flip_pattern); if (p1 == p2) { return new Ngons() { p1_c } } ; Ngon p2_c = pattern.Clone(p2.X, p2.Y, flip_pattern); Ngons full = new Ngons(); clipper.AddPath(p1_c, PolyType.ptSubject, true); clipper.AddPath(p2_c, PolyType.ptSubject, true); clipper.AddPaths(Clipper.MinkowskiSum(pattern.Clone(0, 0, flip_pattern), new Ngon() { p1, p2 }, false), PolyType.ptSubject, true); clipper.Execute(ClipType.ctUnion, full, PolyFillType.pftNonZero); return(full); }
/// <summary> /// Checks if polygons are intersecting /// </summary> /// <param name="p1">Subject polygon</param> /// <param name="p2">Clip polygon(s)</param> /// <returns>true if intersects</returns> public static bool IsIntersects(Paths p1, params Paths[] p2) { Clipper c = new Clipper(); Paths solution = new Paths(); c.AddPaths(p1, PolyType.ptSubject, true); for (int i = 0; i < p2.Length; i++) { c.AddPaths(p2[i], PolyType.ptClip, true); } c.Execute(ClipType.ctIntersection, solution, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); return(solution.Count != 0); }
private Polygons FixWinding(Polygons polygonsToPathAround) { polygonsToPathAround = Clipper.CleanPolygons(polygonsToPathAround); Polygon boundsPolygon = new Polygon(); IntRect bounds = Clipper.GetBounds(polygonsToPathAround); bounds.left -= 10; bounds.bottom += 10; bounds.right += 10; bounds.top -= 10; boundsPolygon.Add(new IntPoint(bounds.left, bounds.top)); boundsPolygon.Add(new IntPoint(bounds.right, bounds.top)); boundsPolygon.Add(new IntPoint(bounds.right, bounds.bottom)); boundsPolygon.Add(new IntPoint(bounds.left, bounds.bottom)); Clipper clipper = new Clipper(); clipper.AddPaths(polygonsToPathAround, PolyType.ptSubject, true); clipper.AddPath(boundsPolygon, PolyType.ptClip, true); PolyTree intersectionResult = new PolyTree(); clipper.Execute(ClipType.ctIntersection, intersectionResult); Polygons outputPolygons = Clipper.ClosedPathsFromPolyTree(intersectionResult); Clipper.ReversePaths(outputPolygons); return(outputPolygons); }
/// <summary> /// Add the 2D projection of the given arc /// to the current element outline union /// </summary> static public bool AddToUnion( Polygons union, VertexLookup vl, Clipper c, Arc arc) { IList <XYZ> pts = arc.Tessellate(); int n = pts.Count; Polygons faces = new Polygons(1); Polygon face2d = new Polygon(n); IntPoint a = vl.GetOrAdd(pts[0]); face2d.Add(a); for (int i = 1; i < n; ++i) { IntPoint b = vl.GetOrAdd(pts[i]); if (b != a) { face2d.Add(b); a = b; } } faces.Add(face2d); return(c.AddPaths(faces, PolyType.ptSubject, true)); }
/// <summary> /// Constructs the geometric difference between this Polygon and the supplied Polygons. /// </summary> /// <param name="difPolys">The list of intersecting Polygons.</param> /// <returns> /// Returns a list of Polygons representing the subtraction of the supplied Polygons from this Polygon. /// Returns null if the area of this Polygon is entirely subtracted. /// Returns a list containing a representation of the perimeter of this Polygon if the two Polygons do not intersect. /// </returns> public IList <Polygon> Difference(IList <Polygon> difPolys) { var thisPath = this.ToClipperPath(); var polyPaths = new List <List <IntPoint> >(); foreach (Polygon polygon in difPolys) { polyPaths.Add(polygon.ToClipperPath()); } Clipper clipper = new Clipper(); clipper.AddPath(thisPath, PolyType.ptSubject, true); clipper.AddPaths(polyPaths, PolyType.ptClip, true); var solution = new List <List <IntPoint> >(); clipper.Execute(ClipType.ctDifference, solution); if (solution.Count == 0) { return(null); } var polygons = new List <Polygon>(); foreach (List <IntPoint> path in solution) { polygons.Add(PolygonExtensions.ToPolygon(path.Distinct().ToList())); } return(polygons); }
/// <summary> /// Updates the key definition to occupy a region of itself plus the specified other keys. /// </summary> /// <param name="keys">The keys to union with.</param> /// <returns>A new key definition with the updated region.</returns> private KeyboardKeyDefinition UnionWith(IList <KeyboardKeyDefinition> keys) { var newBoundaries = this.Boundaries.Select(b => new TPoint(b.X, b.Y)).ToList(); if (keys.Any()) { var cl = new Clipper(); cl.AddPath(this.GetPath(), PolyType.ptSubject, true); cl.AddPaths(keys.Select(x => x.GetPath()).ToList(), PolyType.ptClip, true); var union = new List <List <IntPoint> >(); cl.Execute(ClipType.ctUnion, union); if (union.Count > 1) { throw new ArgumentException("Cannot union two non-overlapping keys."); } newBoundaries = union.Single().ConvertAll <TPoint>(x => x); } return(new KeyboardKeyDefinition( this.Id, newBoundaries, this.KeyCodes, this.Text, this.ShiftText, this.ChangeOnCaps)); }
public static List<List<IntPoint>> ClipPolygons(List<Polygon> polygons) { var subj = new List<List<IntPoint>>(polygons.Count); var clip = new List<List<IntPoint>>(polygons.Count); foreach (var polygon in polygons) { subj.Add(polygon.ToClipperPath()); clip.Add(polygon.ToClipperPath()); } var solution = new List<List<IntPoint>>(); var c = new Clipper(); c.AddPaths(subj, PolyType.PtSubject, true); c.AddPaths(clip, PolyType.PtClip, true); c.Execute(ClipType.CtUnion, solution, PolyFillType.PftPositive, PolyFillType.PftEvenOdd); return solution; }
public void GenerateMarchingSquaresAndLines(Action <double, string> progressReporter, ImageBuffer image, IThresholdFunction thresholdFunction) { if (image != null) { // Regenerate outline var marchingSquaresData = new MarchingSquaresByte( image, thresholdFunction.ZeroColor, thresholdFunction.Threshold, 0); progressReporter?.Invoke(0, "Creating Outline"); marchingSquaresData.CreateLineSegments(); progressReporter?.Invoke(.1, null); int pixelsToIntPointsScale = 1000; var lineLoops = marchingSquaresData.CreateLineLoops(pixelsToIntPointsScale); progressReporter?.Invoke(.15, null); var min = new IntPoint(-10, -10); var max = new IntPoint(10 + image.Width * pixelsToIntPointsScale, 10 + image.Height * pixelsToIntPointsScale); var boundingPoly = new Polygon(); boundingPoly.Add(min); boundingPoly.Add(new IntPoint(min.X, max.Y)); boundingPoly.Add(max); boundingPoly.Add(new IntPoint(max.X, min.Y)); // now clip the polygons to get the inside and outside polys var clipper = new Clipper(); clipper.AddPaths(lineLoops, PolyType.ptSubject, true); clipper.AddPath(boundingPoly, PolyType.ptClip, true); var polygonShape = new Polygons(); progressReporter?.Invoke(.3, null); clipper.Execute(ClipType.ctIntersection, polygonShape); progressReporter?.Invoke(.55, null); polygonShape = Clipper.CleanPolygons(polygonShape, 100); progressReporter?.Invoke(.75, null); VertexStorage rawVectorShape = polygonShape.PolygonToPathStorage(); var aabb = this.VisibleMeshes().FirstOrDefault().GetAxisAlignedBoundingBox(); var xScale = aabb.XSize / image.Width; var affine = Affine.NewScaling(1.0 / pixelsToIntPointsScale * xScale); affine *= Affine.NewTranslation(-aabb.XSize / 2, -aabb.YSize / 2); rawVectorShape.transform(affine); this.VertexSource = rawVectorShape; progressReporter?.Invoke(1, null); } }
public static List<List<IntPoint>> ClipPolygons(List<Polygon> polygons) { var subj = new List<List<IntPoint>>(polygons.Count); var clip = new List<List<IntPoint>>(polygons.Count); foreach (var polygon in polygons) { subj.Add(polygon.ToClipperPath()); clip.Add(polygon.ToClipperPath()); } var solution = new List<List<IntPoint>>(); var c = new Clipper(); c.AddPaths(subj, PolyType.ptSubject, true); c.AddPaths(clip, PolyType.ptClip, true); c.Execute(ClipType.ctUnion, solution, PolyFillType.pftPositive, PolyFillType.pftEvenOdd); return solution; }
private void Clip(NavigationPolygon floor, NavigationPolygons staticObjects) { Clipper clipper = new Clipper(); if (!clipper.AddPath(floor, PolyType.ptSubject, true)) { throw new Exception("Can't add Paths (Subject)."); } if (staticObjects.Count > 0 && !clipper.AddPaths(staticObjects, PolyType.ptClip, true)) { throw new Exception("Can't add Paths (Clip)."); } // we do it twice (it's easier than deep copy the polygons), since this is loading screen time... We don't mind performance too much here if (!clipper.Execute(ClipType.ctDifference, floorWithStaticObjects, PolyFillType.pftNonZero)) { throw new Exception("Can't clip floorWithStaticObjects."); } if (!clipper.Execute(ClipType.ctDifference, FloorWithDynamicObjects, PolyFillType.pftNonZero)) { throw new Exception("Can't clip floorWithStaticObjects."); } clipper.Reset(); }
//------------------------------------------------------------------------------ public void Execute(ref Paths sol, double delta) { sol.Clear(); if (nodes.Count == 0) { return; } GetLowestPolygonIdx(); bool negate = (lowestIdx >= 0 && Area(nodes[lowestIdx].path) < 0); //if polygon orientations are reversed, then 'negate' ... if (negate) { this.delta = -delta; } else { this.delta = delta; } DoOffset(this.delta); //now clean up 'corners' ... Clipper clpr = new Clipper(); clpr.AddPaths(solution, PathType.Subject); if (negate) { clpr.Execute(ClipType.Union, sol, FillRule.Negative); } else { clpr.Execute(ClipType.Union, sol, FillRule.Positive); } }
/// <summary> /// Constructs the geometric difference between this Polygon and the supplied Polygons. /// </summary> /// <param name="difPolys">The list of intersecting Polygons.</param> /// <param name="tolerance">An optional tolerance value.</param> /// <returns> /// Returns a list of Polygons representing the subtraction of the supplied Polygons from this Polygon. /// Returns null if the area of this Polygon is entirely subtracted. /// Returns a list containing a representation of the perimeter of this Polygon if the two Polygons do not intersect. /// </returns> public IList <Polygon> Difference(IList <Polygon> difPolys, double tolerance = Vector3.EPSILON) { var thisPath = this.ToClipperPath(tolerance); var polyPaths = new List <List <IntPoint> >(); foreach (Polygon polygon in difPolys) { polyPaths.Add(polygon.ToClipperPath(tolerance)); } Clipper clipper = new Clipper(); clipper.AddPath(thisPath, PolyType.ptSubject, true); clipper.AddPaths(polyPaths, PolyType.ptClip, true); var solution = new List <List <IntPoint> >(); clipper.Execute(ClipType.ctDifference, solution); if (solution.Count == 0) { return(null); } var polygons = new List <Polygon>(); foreach (List <IntPoint> path in solution) { try { polygons.Add(PolygonExtensions.ToPolygon(path.Distinct().ToList(), tolerance)); } catch { // swallow invalid polygons } } return(polygons); }
public static Polygons GetCorrectedWinding(this Polygons polygonsToFix) { polygonsToFix = Clipper.CleanPolygons(polygonsToFix); var boundsPolygon = new Polygon(); IntRect bounds = Clipper.GetBounds(polygonsToFix); bounds.left -= 10; bounds.top -= 10; bounds.bottom += 10; bounds.right += 10; boundsPolygon.Add(new IntPoint(bounds.left, bounds.top)); boundsPolygon.Add(new IntPoint(bounds.right, bounds.top)); boundsPolygon.Add(new IntPoint(bounds.right, bounds.bottom)); boundsPolygon.Add(new IntPoint(bounds.left, bounds.bottom)); var clipper = new Clipper(); clipper.AddPaths(polygonsToFix, PolyType.ptSubject, true); clipper.AddPath(boundsPolygon, PolyType.ptClip, true); var intersectionResult = new PolyTree(); clipper.Execute(ClipType.ctIntersection, intersectionResult); Polygons outputPolygons = Clipper.ClosedPathsFromPolyTree(intersectionResult); return(outputPolygons); }
private Polygons FixWinding(Polygons polygonsToPathAround) { polygonsToPathAround = Clipper.CleanPolygons(polygonsToPathAround); Polygon boundsPolygon = new Polygon(); IntRect bounds = Clipper.GetBounds(polygonsToPathAround); bounds.minX -= 10; bounds.maxY += 10; bounds.maxX += 10; bounds.minY -= 10; boundsPolygon.Add(new IntPoint(bounds.minX, bounds.minY)); boundsPolygon.Add(new IntPoint(bounds.maxX, bounds.minY)); boundsPolygon.Add(new IntPoint(bounds.maxX, bounds.maxY)); boundsPolygon.Add(new IntPoint(bounds.minX, bounds.maxY)); Clipper clipper = new Clipper(); clipper.AddPaths(polygonsToPathAround, PolyType.ptSubject, true); clipper.AddPath(boundsPolygon, PolyType.ptClip, true); PolyTree intersectionResult = new PolyTree(); clipper.Execute(ClipType.ctIntersection, intersectionResult); Polygons outputPolygons = Clipper.ClosedPathsFromPolyTree(intersectionResult); return(outputPolygons); }
public void RemoveHoles(float maxPerimiter) { Paths keep = new Paths(); PolyNode node = polyTree.GetFirst(); while (node != null) { if (node.IsHole && node.ChildCount == 0) { var line = LineStripFromPolygon(node.Contour); float length = line.Length(LineStrip.Type.Closed); if (length < maxPerimiter) { // Remove it } else { keep.Add(node.Contour); } } else { keep.Add(node.Contour); } node = node.GetNext(); } Clipper c = new Clipper(); c.Clear(); c.AddPaths(keep, PolyType.ptSubject, true); polyTree = new PolyTree(); c.Execute(ClipType.ctUnion, polyTree); }
private Polygons CreateTravelPath(Polygons polygonsToPathAround, Polygons travelPolysLine) { Clipper clipper = new Clipper(); clipper.AddPaths(travelPolysLine, PolyType.ptSubject, false); clipper.AddPaths(polygonsToPathAround, PolyType.ptClip, true); PolyTree clippedLine = new PolyTree(); //List<List<IntPoint>> intersectedPolys = new List<List<IntPoint>>(); //clipper.Execute(ClipType.ctDifference, intersectedPolys); clipper.Execute(ClipType.ctDifference, clippedLine); return(Clipper.OpenPathsFromPolyTree(clippedLine)); }
/// <summary> /// Checks if polygons are intersecting /// </summary> /// <param name="p1">Subject polygon</param> /// <param name="p2">Clip polygon(s)</param> /// <returns>true if intersects</returns> public static bool IsIntersects(Paths p1, params Paths[] p2) { var c = new Clipper(); var solution = new Paths(); c.AddPaths(p1, PolyType.ptSubject, true); foreach (Paths t in p2) { c.AddPaths(t, PolyType.ptClip, true); } c.Execute(ClipType.ctIntersection, solution, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); return(solution.Count != 0); }
/// <summary> /// Apply a boolean operation (Union, Difference, Intersection, or XOr) to two lists of Polygons. /// </summary> /// <param name="subjectPolygons">Polygons to clip</param> /// <param name="clippingPolygons">Polygons with which to clip</param> /// <param name="booleanMode">The operation to apply: Union, Difference, Intersection, or XOr</param> /// <param name="voidTreatment">Optional setting for how to process the polygons in each set: either treat polygons inside others as voids, or treat them all as solid (thereby ignoring internal polygons).</param> /// <param name="tolerance">Optional override of the tolerance for determining if two polygons are identical.</param> private static IList <Polygon> BooleanTwoSets(IList <Polygon> subjectPolygons, IList <Polygon> clippingPolygons, BooleanMode booleanMode, VoidTreatment voidTreatment = VoidTreatment.PreserveInternalVoids, double tolerance = Vector3.EPSILON) { var subjectPaths = subjectPolygons.Select(s => s.ToClipperPath(tolerance)).ToList(); var clipPaths = clippingPolygons.Select(s => s.ToClipperPath(tolerance)).ToList(); Clipper clipper = new Clipper(); clipper.AddPaths(subjectPaths, PolyType.ptSubject, true); clipper.AddPaths(clipPaths, PolyType.ptClip, true); var solution = new List <List <IntPoint> >(); var executionMode = ClipType.ctDifference; var polyFillType = PolyFillType.pftEvenOdd; if (voidTreatment == VoidTreatment.IgnoreInternalVoids) { polyFillType = PolyFillType.pftNonZero; } switch (booleanMode) { case BooleanMode.Difference: executionMode = ClipType.ctDifference; break; case BooleanMode.Union: executionMode = ClipType.ctUnion; break; case BooleanMode.Intersection: executionMode = ClipType.ctIntersection; break; case BooleanMode.XOr: executionMode = ClipType.ctXor; break; } clipper.Execute(executionMode, solution, polyFillType); if (solution.Count == 0) { return(null); } var polygons = new List <Polygon>(); foreach (List <IntPoint> path in solution) { polygons.Add(PolygonExtensions.ToPolygon(path, tolerance)); } return(polygons); }
public bool CheckForOverLaps(Polygon otherPolygon) { var subj = new List <List <IntPoint> >(); var clip = new List <List <IntPoint> >(); subj.Add(ToClipperPath()); clip.Add(otherPolygon.ToClipperPath()); var solution = new List <List <IntPoint> >(); var c = new Clipper(); c.AddPaths(subj, PolyType.ptSubject, true); c.AddPaths(clip, PolyType.ptClip, true); c.Execute(ClipType.ctIntersection, solution, PolyFillType.pftNonZero, PolyFillType.pftNonZero); return(solution.Count != 0); }
private static Polygon ClipPolygon(Polygon subject, Polygon clip, ClipType operation) { Paths clprResult = new Paths(); // Convert to library structure Paths clprSubject = PolygonToClprPaths(subject); Paths clprClip = PolygonToClprPaths(clip); // Execute clip action lock (ClipperEngine) { ClipperEngine.Clear(); ClipperEngine.AddPaths(clprSubject, PolyType.ptSubject, true); ClipperEngine.AddPaths(clprClip, PolyType.ptClip, true); ClipperEngine.Execute(operation, clprResult); } // Convert back to common polygon return(ClprPathsToPolygon(clprResult)); }
static public IPolygon Clip(this IPolygon clippee, Envelope clipper) { var clippeePolygons = clippee.ToClipperPolygons(); var clipperPolygons = clipper.ToPolygon().ToClipperPolygons(); var c = new Clipper(); c.AddPaths(clippeePolygons, PolyType.ptSubject, true); c.AddPaths(clipperPolygons, PolyType.ptClip, true); ClipperPolygons result = new ClipperPolygons(); if (c.Execute(ClipType.ctIntersection, result) == true) { return result.ToPolygon(); } return clippee; }
/// <summary> /// Constructs the geometric intersections between two supplied Lists of Polygons. /// </summary> /// <param name="polygons">List of subject Polygons for the difference calculation.</param> /// <param name="inters">List of clipping Polygons for the difference calculation.</param> /// <returns> /// A List of Polygons representing the subtraction of the clipping Polygons from the subject Polygons. /// </returns> public static List <Polygon> Intersections(List <Polygon> polygons, List <Polygon> inters, double tolerance = 0.01) { var resultPolygons = new List <Polygon>(); if (polygons == null || polygons.Count == 0 || inters == null || inters.Count == 0) { return(resultPolygons); } var polyPaths = new List <List <IntPoint> >(); var intrPaths = new List <List <IntPoint> >(); foreach (Polygon polygon in polygons) { polyPaths.Add(polygon.PolygonToClipper()); } foreach (Polygon polygon in inters) { intrPaths.Add(polygon.PolygonToClipper()); } Clipper clipper = new Clipper(); clipper.AddPaths(polyPaths, PolyType.ptSubject, true); clipper.AddPaths(intrPaths, PolyType.ptClip, true); var solution = new List <List <IntPoint> >(); clipper.Execute(ClipType.ctIntersection, solution, PolyFillType.pftNonZero); if (solution.Count == 0) { return(resultPolygons); } foreach (var solved in solution) { var polygon = solved.ToList().PolygonFromClipper(); if (polygon == null) { continue; } if (polygon.IsClockWise()) { polygon = polygon.Reversed(); } resultPolygons.Add(polygon); } return(resultPolygons.Where(p => p.Area() >= tolerance).OrderByDescending(p => p.Area()).ToList()); }
/// <summary> /// process the difference between this and other /// </summary> /// <param name="other"></param> /// <param name="type">http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Types/ClipType.htm</param> /// <returns></returns> public List <Vector2> Clip(Polygon other, PolygonOps op) { var type = (ClipType)op; var subj = new Paths(1); subj.Add(ToClipper(this.points)); var clip = new Paths(1); clip.Add(ToClipper(other.Points)); Paths solution = new Paths(); Clipper clp = new Clipper(); clp.AddPaths(subj, PolyType.ptSubject, true); clp.AddPaths(clip, PolyType.ptClip, true); clp.Execute(type, solution, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); return(solution.Count > 0 ? FromClipper(solution[0]) : null); }
public static NFP[] intersection(NFP polygon, NFP polygon1, double offset, JoinType jType = JoinType.jtMiter, double clipperScale = 10000000, double curveTolerance = 0.72, double miterLimit = 4) { var p = ToClipperCoordinates(new[] { polygon }, clipperScale).ToList(); var p1 = ToClipperCoordinates(new[] { polygon1 }, clipperScale).ToList(); Clipper clipper = new Clipper(); clipper.AddPaths(p.Select(z => z.ToList()).ToList(), PolyType.ptClip, true); clipper.AddPaths(p1.Select(z => z.ToList()).ToList(), PolyType.ptSubject, true); List <List <IntPoint> > finalNfp = new List <List <IntPoint> >(); if (clipper.Execute(ClipType.ctIntersection, finalNfp, PolyFillType.pftNonZero, PolyFillType.pftNonZero) && finalNfp != null && finalNfp.Count > 0) { return(finalNfp.Select(z => toNestCoordinates(z.ToArray(), clipperScale)).ToArray()); } return(null); }
public void createBasePolyTreeFromDescription() { // combine all paths polytree = new PolyTree(); Clipper c = new Clipper(Clipper.ioPreserveCollinear); // sort paths for subj and holes c.AddPaths(paths, PolyType.ptSubject, true); if (clips.Count > 0) { //Debug.Log ("Have clip"); c.AddPaths(paths, PolyType.ptClip, true); } c.Execute(ClipType.ctDifference, polytree, PolyFillType.pftNonZero, PolyFillType.pftNonZero); }
public static List <XPolygon> Clip(ClipType clipType, List <XPolygon> subjects, List <XPolygon> clips, double scaleBy = 1000) { List <XPolygon> results = new List <XPolygon>(); Paths subjPaths = ToPaths(subjects, scaleBy); Paths clipPaths = ToPaths(clips, scaleBy); Clipper clipper = new Clipper(); clipper.AddPaths(clipPaths, PolyType.ptSubject, closed: true); clipper.AddPaths(subjPaths, PolyType.ptClip, closed: true); PolyTree result = new PolyTree(); clipper.Execute(clipType, result, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); PathOrientation orientation = Clipper.Orientation(subjPaths.First()) == true ? PathOrientation.Anticlockwise : PathOrientation.Clockwise; return(FromPolyTree(result, orientation, scaleBy)); }
// perform union on a list of polygons public static Paths ClipperUnion(this List <Polygon> polygons) { var subj = new Paths(polygons.Count); var clip = new Paths(polygons.Count); foreach (var polygon in polygons) { subj.Add(polygon.ToClipperPath()); clip.Add(polygon.ToClipperPath()); } var solution = new Paths(); var c = new Clipper(); c.AddPaths(subj, PolyType.ptSubject, true); c.AddPaths(clip, PolyType.ptClip, true); c.Execute(ClipType.ctUnion, solution, PolyFillType.pftPositive, PolyFillType.pftPositive); return(solution); }
public static Polygons ProcessEvenOdd(this Polygons polygons) { var ret = new Polygons(); var clipper = new Clipper(); clipper.AddPaths(polygons, PolyType.ptSubject, true); clipper.Execute(ClipType.ctUnion, ret); return(ret); }
private static List <List <IntPoint> > ClipPolygons(IReadOnlyCollection <Polygon> polygons) { var subj = new List <List <IntPoint> >(polygons.Count); var clip = new List <List <IntPoint> >(polygons.Count); foreach (var polygon in polygons) { subj.Add(polygon.ToClipperPath()); clip.Add(polygon.ToClipperPath()); } var solution = new List <List <IntPoint> >(); var c = new Clipper(); c.AddPaths(subj, PolyType.PtSubject, true); c.AddPaths(clip, PolyType.PtClip, true); c.Execute(ClipType.CtUnion, solution, PolyFillType.PftPositive, PolyFillType.PftEvenOdd); return(solution); }
public static void GenerateLinePaths(Polygons in_outline, ref Polygons result, int lineSpacing, int infillExtendIntoPerimeter_um, double rotation, long rotationOffset = 0) { if (in_outline.Count > 0) { Polygons outlines = in_outline.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); result.AddRange(newSegments); } } }
//------------------------------------------------------------------------------ public List<List<Point>> Execute(double deltap, double eps = double.Epsilon) { var solution = new List<List<Point>>(); FixPerimeters(); DoOffset(deltap, eps); //now clean up 'corners' ... var clpr = new Clipper(); clpr.AddPaths(destPolys, PolyType.Subject); if (deltap > 0) { clpr.Execute(ClipType.Union, solution, PolyFillType.Positive, PolyFillType.Positive); } else { var r = destPolys.GetBounds(); var outer = new List<Point>(4) { new Point(r.Left - 10, r.Bottom + 10), new Point(r.Right + 10, r.Bottom + 10), new Point(r.Right + 10, r.Top - 10), new Point(r.Left - 10, r.Top - 10) }; clpr.AddPath(outer, PolyType.Subject); clpr.ReverseSolution = true; clpr.Execute(ClipType.Union, solution, PolyFillType.Negative, PolyFillType.Negative); if (solution.Count > 0) solution.RemoveAt(0); } return solution; }
/// <summary> /// Subtract 2 polygon coordinates by top - bottom. /// </summary> /// <returns>The subtracted coordinates.</returns> /// <param name="top">Top polygon coordinates.</param> /// <param name="bottom">Bottom polygon coordinates.</param> public static IEnumerable<Coordinate> Subtract(IEnumerable<Coordinate> top, IEnumerable<Coordinate> bottom) { // Using Clipper library to do polygon operation. var clipper = new Clipper(); var topPolies = new List<List<IntPoint>>(); topPolies.Add(new List<IntPoint>()); foreach(var c in top) { topPolies[0].Add( new IntPoint(Utils.ToLong(c.X), Utils.ToLong(c.Y))); } clipper.AddPaths(topPolies, PolyType.ptSubject, true); var bottomPolies = new List<List<IntPoint>>(); bottomPolies.Add(new List<IntPoint>()); foreach(var c in bottom) { bottomPolies[0].Add( new IntPoint(Utils.ToLong(c.X), Utils.ToLong(c.Y))); } clipper.AddPaths(bottomPolies, PolyType.ptClip, true); var solution = new List<List<IntPoint>>(); clipper.Execute(ClipType.ctXor, solution, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); var coords = new List<Coordinate>(); foreach (var areas in solution) { foreach(var p in areas) { var c = new Coordinate() { X = Utils.ToDouble(p.X), Y = Utils.ToDouble(p.Y) }; coords.Add(c); } } return coords; }
/// <summary> /// Gets the union coordinates of specified district key. /// </summary> /// <returns>The coordinates.</returns> /// <param name="districtKeys">Array of district key.</param> public static IEnumerable<Coordinate> GetUnionCoordinates(String[] districtKeys) { // Using Clipper library to do polygon operation. var clipper = new Clipper(); foreach (var dk in districtKeys) { var polies = new List<List<IntPoint>>(); var areas = GetCoordinates(dk); foreach(var a in areas) { polies.Add(new List<IntPoint>()); foreach (var c in a) polies[0].Add(new IntPoint(Utils.ToLong(c.X), Utils.ToLong(c.Y))); } clipper.AddPaths(polies, PolyType.ptSubject, true); } var solution = new List<List<IntPoint>>(); clipper.Execute(ClipType.ctUnion, solution, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); var coords = new List<Coordinate>(); foreach (var areas in solution) { foreach(var p in areas) { var c = new Coordinate() { X = Utils.ToDouble(p.X), Y = Utils.ToDouble(p.Y) }; coords.Add(c); } } return coords; }
public static Polygons ProcessEvenOdd(this Polygons polygons) { Polygons ret = new Polygons(); Clipper clipper = new Clipper(); clipper.AddPaths(polygons, PolyType.ptSubject, true); clipper.Execute(ClipType.ctUnion, ret); return ret; }
public static Polygons CreateUnion(this Polygons polygons, Polygons other) { Polygons ret = new Polygons(); Clipper clipper = new Clipper(); clipper.AddPaths(polygons, PolyType.ptSubject, true); clipper.AddPaths(other, PolyType.ptSubject, true); clipper.Execute(ClipType.ctUnion, ret, PolyFillType.pftNonZero, PolyFillType.pftNonZero); return ret; }
public static List<Polygons> CreateLayerOutlines(this Polygons polygons, LayerOpperation opperation) { List<Polygons> ret = new List<Polygons>(); Clipper clipper = new Clipper(); PolyTree resultPolyTree = new PolyTree(); clipper.AddPaths(polygons, PolyType.ptSubject, true); if (opperation == LayerOpperation.UnionAll) { clipper.Execute(ClipType.ctUnion, resultPolyTree, PolyFillType.pftNonZero, PolyFillType.pftNonZero); } else { clipper.Execute(ClipType.ctUnion, resultPolyTree); } polygons._processPolyTreeNode(resultPolyTree, ret); return ret; }
public static Polygons CreateIntersection(this Polygons polygons, Polygons other) { Polygons ret = new Polygons(); Clipper clipper = new Clipper(); clipper.AddPaths(polygons, PolyType.ptSubject, true); clipper.AddPaths(other, PolyType.ptClip, true); clipper.Execute(ClipType.ctIntersection, ret); return ret; }
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 static Polygons CreateLineIntersections(this Polygons polygons, Polygons other) { Clipper clipper = new Clipper(); clipper.AddPaths(other, PolyType.ptSubject, false); clipper.AddPaths(polygons, PolyType.ptClip, true); PolyTree clippedLines = new PolyTree(); clipper.Execute(ClipType.ctIntersection, clippedLines); return Clipper.OpenPathsFromPolyTree(clippedLines); }
public static List<Polygons> ProcessIntoSeparatIslands(this Polygons polygons) { List<Polygons> ret = new List<Polygons>(); Clipper clipper = new Clipper(); PolyTree resultPolyTree = new PolyTree(); clipper.AddPaths(polygons, PolyType.ptSubject, true); clipper.Execute(ClipType.ctUnion, resultPolyTree); polygons.ProcessPolyTreeNodeIntoSeparatIslands(resultPolyTree, ret); return ret; }
public static Polygons GetCorrectedWinding(this Polygons polygonsToFix) { polygonsToFix = Clipper.CleanPolygons(polygonsToFix); Polygon boundsPolygon = new Polygon(); IntRect bounds = Clipper.GetBounds(polygonsToFix); bounds.left -= 10; bounds.bottom += 10; bounds.right += 10; bounds.top -= 10; boundsPolygon.Add(new IntPoint(bounds.left, bounds.top)); boundsPolygon.Add(new IntPoint(bounds.right, bounds.top)); boundsPolygon.Add(new IntPoint(bounds.right, bounds.bottom)); boundsPolygon.Add(new IntPoint(bounds.left, bounds.bottom)); Clipper clipper = new Clipper(); clipper.AddPaths(polygonsToFix, PolyType.ptSubject, true); clipper.AddPath(boundsPolygon, PolyType.ptClip, true); PolyTree intersectionResult = new PolyTree(); clipper.Execute(ClipType.ctIntersection, intersectionResult); Polygons outputPolygons = Clipper.ClosedPathsFromPolyTree(intersectionResult); return outputPolygons; }
public static Polygons CreateLineDifference(this Polygons linePolygons, Polygons removePolygons) { Clipper clipper = new Clipper(); clipper.AddPaths(linePolygons, PolyType.ptSubject, false); clipper.AddPaths(removePolygons, PolyType.ptClip, true); PolyTree clippedLines = new PolyTree(); clipper.Execute(ClipType.ctDifference, clippedLines); return Clipper.OpenPathsFromPolyTree(clippedLines); }