/// <summary> /// Generates a rectangular polycurve on the XY plane centred on the origin /// </summary> /// <param name="depth">The depth of the rectangle</param> /// <param name="width">The width of the rectangle</param> /// <returns></returns> public static PolyCurve Rectangle(double depth, double width, double cornerRadius = 0.0) { cornerRadius = Math.Max(cornerRadius, 0.0); double x = width / 2; double y = depth / 2; double x2 = Math.Max(x - cornerRadius, 0.0); double y2 = Math.Max(y - cornerRadius, 0.0); PolyCurve result = new PolyCurve(new Line(x2, y, -x2, y)); if (cornerRadius > 0) { result.AddArcTangent(new Vector(-1, 0), new Vector(-x, y2)); } result.AddLine(-x, -y2); if (cornerRadius > 0) { result.AddArcTangent(new Vector(0, -1), new Vector(-x2, -y)); } result.AddLine(x2, -y); if (cornerRadius > 0) { result.AddArcTangent(new Vector(1, 0), new Vector(x, -y2)); } result.AddLine(x, y2); if (cornerRadius > 0) { result.AddArcTangent(new Vector(0, 1), new Vector(x2, y)); } return(result); }
/// <summary> /// Generates a trapezoid polygon on the XY plane with the midpoint of each edge /// centred on the origin and with a different top and bottom width. /// </summary> /// <param name="depth">The depth of the trapezoid</param> /// <param name="topWidth">The width of the top of the trapezoid</param> /// <param name="baseWidth">The width of the base of the trapezoid</param> /// <returns></returns> public static PolyCurve Trapezoid(double depth, double topWidth, double baseWidth) { double xT = topWidth / 2; double xB = baseWidth / 2; double y = depth / 2; PolyCurve result = new PolyCurve(new Line(xT, y, -xT, y)); result.AddLine(-xB, -y); result.AddLine(xB, -y); result.AddLine(xT, y); return(result); }
/// <summary> /// Split this region into two (or more) sub-regions along a straight line /// </summary> /// <param name="splitPt">A point on the splitting line</param> /// <param name="splitDir">The direction of the line</param> /// <param name="splitWidth">Optional. The width of the split.</param> /// <returns>The resultant list of regions. If the line does not bisect /// this region and the region could not be split, this collection will contain /// only the original region.</returns> public IList <PlanarRegion> SplitByLineXY(Vector splitPt, Vector splitDir, double splitWidth = 0) { var result = new List <PlanarRegion>(); var lineInts = new List <double>(); var outerInts = Intersect.CurveLineXY(Perimeter, splitPt, splitDir, null, 0, 1, false, lineInts); if (outerInts.Count > 1) { // Sort intersections by position along curve: var sortedInts = new SortedList <double, double>(outerInts.Count); for (int i = 0; i < outerInts.Count; i++) { sortedInts.Add(outerInts[i], lineInts[i]); } outerInts = sortedInts.Keys.ToList(); lineInts = sortedInts.Values.ToList(); int offset = lineInts.IndexOfMin(); outerInts.Shift(offset); lineInts.Shift(offset); // Create segments data structure var segments = new List <PerimeterSegment>(outerInts.Count - 1); for (int i = 0; i < outerInts.Count; i++) { double t0 = outerInts[i]; double t1 = outerInts.GetWrapped(i + 1); double tC0 = lineInts[i]; double tC1 = lineInts.GetWrapped(i + 1); var segment = new PerimeterSegment(Perimeter, t0, t1, tC0, tC1); segments.Add(segment); } //TODO: void intersections bool backwards = true; while (segments.Count > 0) { var offsets = new List <double>(); PerimeterSegment segment = segments.First(); PolyCurve newPerimeter = segment.Extract().ToPolyCurve(); for (int i = 0; i < newPerimeter.SegmentCount; i++) { offsets.Add(0); } PerimeterSegment nextSegment = FindNextPerimeterSegment(segments, segment.CutterDomain.End, backwards); while (nextSegment != null && nextSegment != segment) { Curve nextCurve = nextSegment.Extract(); newPerimeter.AddLine(nextCurve.StartPoint); offsets.Add(splitWidth / 2); newPerimeter.Add(nextCurve); for (int i = 0; i < nextCurve.SegmentCount; i++) { offsets.Add(0); } segments.Remove(nextSegment); nextSegment = FindNextPerimeterSegment(segments, nextSegment.CutterDomain.End, backwards); } segments.RemoveAt(0); if (!newPerimeter.Closed) { /*if (splitWidth > 0) * { * // Temporary bodge to get rid of 'blades' at ends of split * Vector endToEnd = (newPerimeter.StartPoint - newPerimeter.EndPoint).Unitize(); * var line = new Line( * newPerimeter.EndPoint - endToEnd * splitWidth / 4, * newPerimeter.StartPoint + endToEnd * splitWidth / 4); * newPerimeter.AddLine(line.StartPoint); * offsets.Add(0); * newPerimeter.Add(line); * offsets.Add(splitWidth / 2); * newPerimeter.Close(); * offsets.Add(0); * } * else * {*/ newPerimeter.Close(); offsets.Add(splitWidth / 2); //} } backwards = !backwards; if (splitWidth > 0) { var newNewPerimeter = newPerimeter.OffsetInwards(offsets); // Check offset has not inverted perimeter: // TODO: Do this automatically when offsetting? if (newNewPerimeter != null && newNewPerimeter.IsClockwiseXY() == newPerimeter.IsClockwiseXY()) { newPerimeter = newNewPerimeter.ToPolyCurve(); } else { newPerimeter = null; } } if (newPerimeter != null) { result.Add(new PlanarRegion(newPerimeter, Attributes?.Duplicate())); } } // OLD VERSION: /*for (int i = 0; i < outerInts.Count; i++) * { * double t0 = outerInts[i]; * double t1 = outerInts.GetWrapped(i + 1); * Curve newPerimeter = Perimeter.Extract(new Interval(t0, t1))?.ToPolyCurve(); * //TODO: Cut through and include voids * if (!newPerimeter.Closed) * { * ((PolyCurve)newPerimeter).Close(); * if (splitWidth > 0) * { * var offsets = new double[newPerimeter.SegmentCount]; * offsets[offsets.Length - 1] = splitWidth / 2; * var newNewPerimeter = newPerimeter.OffsetInwards(offsets); * // Check offset has not inverted perimeter: * // TODO: Do this automatically when offsetting? * if (newNewPerimeter != null && newNewPerimeter.IsClockwiseXY() == newPerimeter.IsClockwiseXY()) * { * newPerimeter = newNewPerimeter; * } * else newPerimeter = null; * } * } * if (newPerimeter != null) result.Add(new PlanarRegion(newPerimeter, Attributes?.Duplicate())); * }*/ } else { result.Add(this); //Return the original } return(result); }