public static IPolygon Offset(this IPolygon p, double offset) { if (p.IsEmpty) { return(Polygon.Empty); } var boundingBox = p.BoundingBox().Offset(Math.Max(offset, 0)); double scale = Math.Max(boundingBox.Width, boundingBox.Height); var fixedPointRange = new Box2(boundingBox.MinCorner, new Vector2(scale, scale)); var fixedP = ConvertToFixedPoint(p, fixedPointRange); try { var offsetter = new ClipperOffset(); offsetter.AddPaths(fixedP, JoinType.jtMiter, EndType.etClosedPolygon); var fixedAnswer = new ClipperPolygon(); offsetter.Execute(ref fixedAnswer, offset * _fixedPointRange / scale); return(ConvertToFloatingPoint(fixedAnswer, fixedPointRange)); } catch (Exception e) { Console.WriteLine("EXCEPTION: {0}", e); return(p); } }
private static IPolygon BinaryOperation(IPolygon p, IPolygon q, ClipType operationType) { if (p.IsEmpty && q.IsEmpty) { return(Polygon.Empty); } var boundingBox = Box2.Hull(p.BoundingBox(), q.BoundingBox()); var fixedP = ConvertToFixedPoint(p, boundingBox); var fixedQ = ConvertToFixedPoint(q, boundingBox); try { var clipper = new Clipper(); clipper.AddPaths(fixedP, PolyType.ptSubject, closed: true); clipper.AddPaths(fixedQ, PolyType.ptClip, closed: true); var fixedAnswer = new ClipperPolygon(); clipper.Execute(operationType, fixedAnswer); return(ConvertToFloatingPoint(fixedAnswer, boundingBox)); } catch (Exception e) { Console.WriteLine("EXCEPTION: {0}", e); return(Polygon.Empty); } }
// intersection of polygon with half plane lying on negative (left) side of line: this is the natural convention since we use external normals public static IPolygon CropBy(this IPolygon p, Line2 line) { var box = p.BoundingBox(); var point = line.Project(box.Center); var radius = box.Diameter / 2; var collinearDisplacement = radius * line.Direction; var transverseDisplacement = 2 * collinearDisplacement.Rotate90(); var vertex1 = point + collinearDisplacement; var vertex2 = point - collinearDisplacement; var vertices = new List <Vector2> { vertex1, vertex1 + transverseDisplacement, vertex2 + transverseDisplacement, vertex2 }; var square = new Polygon(vertices); return(Intersection(p, square)); }
public static IPolygon Opening(this IPolygon p, double offset) { if (offset < 0) { throw new ArgumentOutOfRangeException("offset", offset, "Expected positive offset"); } return(Clopening(p, p.BoundingBox(), -offset)); }
public static IPolygon Closing(this IPolygon p, double offset) { if (offset < 0) { throw new ArgumentOutOfRangeException("offset", offset, "Expected positive offset"); } var boundingBox = p.BoundingBox().Offset(offset); return(Clopening(p, boundingBox, offset)); }
public static IPolygon RelativeClosing(this IPolygon p, double relativeOffset) { if (relativeOffset < 0) { throw new ArgumentOutOfRangeException("relativeOffset", relativeOffset, "Expected positive relativeOffset"); } var boundingBox = p.BoundingBox(); if (boundingBox.IsEmpty) { return(Polygon.Empty); } double scale = Math.Max(boundingBox.Width, boundingBox.Height); return(p.Closing(relativeOffset * scale)); }
public static IPolygon MinkowskiDifference(IPolygon p, IPolygon q) { if (p.IsEmpty || q.IsEmpty) { return(Polygon.Empty); } var boundingBox = Box2.Hull(p.BoundingBox(), q.BoundingBox()); boundingBox = Box2.Hull(boundingBox, new Box2(-boundingBox.MaxCorner, boundingBox.Dimensions)); var fixedAnswer = new ClipperPolygon(); var fixedP = ConvertToFixedPoint(p, boundingBox); foreach (var qContour in q.Contours) { var fixedQContour = MinusConvertToFixedPoint(qContour, boundingBox); try { var clipper = new Clipper(); clipper.AddPaths(fixedAnswer, PolyType.ptSubject, closed: true); clipper.AddPaths(Clipper.MinkowskiSum(fixedQContour, fixedP, pathIsClosed: true), PolyType.ptClip, closed: true); var tempAnswer = new ClipperPolygon(); clipper.Execute(ClipType.ctUnion, tempAnswer); fixedAnswer = tempAnswer; } catch (Exception e) { Console.WriteLine("EXCEPTION: {0}", e); } } return(ConvertToFloatingPoint(fixedAnswer, boundingBox)); }