/// <summary> /// https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm#Pseudo_code /// Fails if result would be empty /// </summary> public static bool TryConvexClip(Polygon2 subject, Polygon2 clip, out Polygon2 result) { bool Inside(IntVector2 p, IntLineSegment2 edge) => GeometryOperations.Clockness(edge.First, edge.Second, p) != Clockness.CounterClockwise; List <IntVector2> outputList = subject.Points; for (var i = 0; i < clip.Points.Count - 1; i++) { var clipEdge = new IntLineSegment2(clip.Points[i], clip.Points[i + 1]); List <IntVector2> inputList = outputList; outputList = new List <IntVector2>(); var S = inputList[inputList.Count - 2]; for (var j = 0; j < inputList.Count - 1; j++) { var E = inputList[j]; if (Inside(E, clipEdge)) { if (!Inside(S, clipEdge)) { var SE = new IntLineSegment2(S, E); if (!GeometryOperations.TryFindLineLineIntersection(SE, clipEdge, out var intersection)) { throw new NotImplementedException(); } outputList.Add(intersection.LossyToIntVector2()); } outputList.Add(E); } else if (Inside(S, clipEdge)) { var SE = new IntLineSegment2(S, E); if (!GeometryOperations.TryFindLineLineIntersection(SE, clipEdge, out var intersection)) { throw new NotImplementedException(); } outputList.Add(intersection.LossyToIntVector2()); } S = E; } if (outputList.Count == 0) { result = null; return(false); } outputList.Add(outputList[0]); } result = new Polygon2(outputList); return(true); }
public static PolyTree ExtrudePolygon(IReadOnlyList <IntVector2> points, int offset) { if (points.Count <= 1) { throw new NotImplementedException("Not implemented: extrude 0 or 1 points"); } if (offset <= 0) { throw new ArgumentOutOfRangeException(); } List <IntVector2> polygonPoints = new List <IntVector2>(points); // hack: fidget the last point slightly to enforce having area var last = points[points.Count - 1]; var secondToLast = points[points.Count - 2]; var secondToLastToLast = secondToLast.To(last); if (secondToLastToLast == IntVector2.Zero) { polygonPoints.Add(last + new IntVector2(1, 0)); } else if (secondToLastToLast.X == 0) { polygonPoints.Add(last + new IntVector2(1, 0)); } else { polygonPoints.Add(last + new IntVector2(0, 1)); } for (int i = points.Count - 2; i >= 0; i--) { polygonPoints.Add(points[i]); } var inputHairlinePolygon = new Polygon2(polygonPoints); var outputPolygons = PolygonOperations.Offset() .Include(inputHairlinePolygon) .Dilate(offset) .Execute(); return(outputPolygons); }