/// <summary> /// Extract all edges and end caps from the path segments in this collection /// </summary> /// <typeparam name="TPath"></typeparam> /// <param name="paths"></param> /// <returns></returns> public static CurveCollection ExtractAllEdges <TPath>(this IList <TPath> paths) where TPath : IWidePath { var result = new CurveCollection(); foreach (TPath path in paths) { //if (path.Spine != null) result.Add(path.Spine); if (path.RightEdge != null) { result.Add(path.RightEdge); } if (path.LeftEdge != null) { result.Add(path.LeftEdge); } if (path.StartCapRight != null) { result.Add(path.StartCapRight); } if (path.StartCapLeft != null) { result.Add(path.StartCapLeft); } if (path.EndCapRight != null) { result.Add(path.EndCapRight); } if (path.EndCapLeft != null) { result.Add(path.EndCapLeft); } } return(result); }
/// <summary> /// 'Explode' this curve into a collection of its constituent /// segments as individual curves. /// </summary> /// <param name="recursive">If true (default), any sub-curves of /// this curve which themselves have sub-curves will also be exploded /// and added to the collection.</param> /// <returns></returns> public override CurveCollection Explode(bool recursive = true) { var result = new CurveCollection(); result.AddRange(ToLines()); return(result); }
/// <summary> /// Extract the boundary curves of each mesh face in this collection /// </summary> /// <returns></returns> public CurveCollection ExtractFaceBoundaries() { CurveCollection result = new CurveCollection(); foreach (MeshFace face in this) { result.Add(face.GetBoundary()); } return(result); }
/// <summary> /// Extract all of the left edges from the path segments in this collection /// </summary> /// <typeparam name="TPath"></typeparam> /// <param name="paths"></param> /// <returns></returns> public static CurveCollection ExtractNetworkPathRightEdges <TPath>(this IList <TPath> paths) where TPath : IWidePath { var result = new CurveCollection(); foreach (TPath path in paths) { result.Add(path.RightEdge); } return(result); }
/// <summary> /// 'Explode' this curve into a collection of its constituent /// segments as individual curves. /// </summary> /// <param name="recursive">If true (default), any sub-curves of /// this curve which themselves have sub-curves will also be exploded /// and added to the collection.</param> /// <returns></returns> public override CurveCollection Explode(bool recursive = true) { var result = new CurveCollection(); foreach (var subCrv in SubCurves) { if (recursive) { result.AddRange(subCrv.Explode()); } else { result.Add(subCrv); } } return(result); }
/// <summary> /// Find the set of curves which represent the intersections between /// the faces in this mesh and a plane aligned with the global XY plane /// at the specified z-level /// </summary> /// <param name="zLevel">The z-coordinate of the flat plane</param> /// <param name="join">If true, the resultant curves will be automatically /// joined together into as few polycurves as possible.</param> /// <returns></returns> public CurveCollection IntersectPlane(double zLevel, bool join = false) { var result = new CurveCollection(); foreach (var face in Faces) { var line = face.IntersectPlane(zLevel); if (line != null) { result.Add(line); } } if (join) { result = result.JoinCurves(true); } return(result); }
/// <summary> /// Initialises a new PlanarSurface with the specified perimeter and void curves. /// </summary> /// <param name="perimeter"></param> /// <param name="voids"></param> public PlanarRegion(Curve perimeter, CurveCollection voids, GeometryAttributes attributes = null) : this(perimeter, attributes) { _Voids = voids; }
/// <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> SplitByLineXY2(Vector splitPt, Vector splitDir, double splitWidth = 0) { var result = new List <PlanarRegion>(); // Offset splitting line by half splitWidth in each direction: Vector offsetDir = splitDir.PerpendicularXY().Unitize(); Vector offset = offsetDir * splitWidth / 2; Vector leftPt = splitPt + offset; Vector rightPt = splitPt - offset; // Find intersection points on perimeter: var perimeterInts = new List <CurveLineIntersection>(); // Left side: IList <CurveLineIntersection> leftInts = Intersect.CurveLineXYIntersections(Perimeter, leftPt, splitDir); perimeterInts.AddRange(leftInts); IList <CurveLineIntersection> rightInts; // Shortcut: If the split has no width, left and right intersections will be the same if (splitWidth == 0) { rightInts = leftInts; } else { rightInts = Intersect.CurveLineXYIntersections(Perimeter, rightPt, splitDir); perimeterInts.AddRange(rightInts); } // If no intersections on the perimeter, the region does not need to be split: if (leftInts.Count <= 1 && rightInts.Count <= 1) { result.Add(this); return(result); } // Voids which do not intersect but will need to be placed: CurveCollection freeVoids = new CurveCollection(); // Find intersection points on voids: foreach (var voidCrv in Voids) { // Left side: var leftVoidInts = Intersect.CurveLineXYIntersections(voidCrv, leftPt, splitDir); foreach (var vI in leftVoidInts) { leftInts.Add(vI); } IList <CurveLineIntersection> rightVoidInts; // Shortcut: If the split has no width, left and right intersections will be the same if (splitWidth == 0) { rightVoidInts = leftVoidInts; } else { rightVoidInts = Intersect.CurveLineXYIntersections(voidCrv, rightPt, splitDir); } foreach (var vI in rightVoidInts) { rightInts.Add(vI); } if (leftVoidInts.Count <= 1 && rightVoidInts.Count <= 1) { // Void is wholly to one side or the other... freeVoids.Add(voidCrv); } } // Tag left and right intersections foreach (var lI in leftInts) { lI.Side = HandSide.Left; } foreach (var rI in rightInts) { rI.Side = HandSide.Right; } // Determine direction of travel along cutting lines: int rightDir = RightCutterDirectionOfTravel(perimeterInts); // 'Fake' intersection to represent perimeter start: CurveLineIntersection startInt = new CurveLineIntersection(Perimeter, 0, double.NaN); // Loop through intersections and build up new sub-regions by traversing connected // intersections along the perimeter, cutting lines and void curves CurveLineIntersection currentInt = startInt; CurveLineIntersection nextStartInt = null; PolyCurve newPerimeter = null; PlanarRegion newRegion = null; // The cutter to travel along (Undefined is perimeter or void cuve): HandSide travelSide = HandSide.Undefined; int segmentCount = perimeterInts.Count + 1; //TODO: Include void intersections for (int i = 0; i < segmentCount; i++) // Loop through intersections { CurveLineIntersection nextInt; // Travel to next intersection, along the cutters or perimeter if (travelSide == HandSide.Left) { // Travel along left cutter if (rightDir == 1) { nextInt = leftInts.ItemWithPrevious(cLI => cLI.LineParameter, currentInt.LineParameter); } else { nextInt = leftInts.ItemWithNext(cLI => cLI.LineParameter, currentInt.LineParameter); } } else if (travelSide == HandSide.Right) { // Travel along right cutter if (rightDir == 1) { nextInt = rightInts.ItemWithNext(cLI => cLI.LineParameter, currentInt.LineParameter); } else { nextInt = rightInts.ItemWithPrevious(cLI => cLI.LineParameter, currentInt.LineParameter); } } else { // Travel to next intersection on perimeter nextInt = perimeterInts.ItemWithNext(cLI => cLI.CurveParameter, currentInt.CurveParameter); // 'Fake' intersection to represent perimeter end: if (nextInt == null) { nextInt = new CurveLineIntersection(Perimeter, 1, double.NaN); } if (nextStartInt == null) { nextStartInt = nextInt; } } if (nextInt != null && currentInt.Curve == nextInt.Curve && // Check both ints on same curve (travelSide == HandSide.Undefined || currentInt.Curve != Perimeter)) { Curve curve = nextInt.Curve; Interval subDomain = new Interval(currentInt.CurveParameter, nextInt.CurveParameter); Vector crvPt = curve.PointAt(subDomain.Mid); HandSide side = SideOfSplit(crvPt, leftPt, rightPt, offsetDir); if (side != HandSide.Undefined) { // TODO: Adjust void curve direction // Add perimeter to outputs Curve subCrv = curve.Extract(subDomain); if (newPerimeter == null) { newPerimeter = new PolyCurve(subCrv.Explode()); newRegion = new PlanarRegion(newPerimeter); result.Add(newRegion); } else { newPerimeter.Add(subCrv, true, true); } } else { //Traversing the gap, need a new start Point startInt = nextInt; } } // Next side to travel: if (travelSide != HandSide.Undefined && (nextInt == null || nextInt.Curve == Perimeter)) { travelSide = HandSide.Undefined; } else { travelSide = nextInt.Side; } if (nextInt == null || nextInt == startInt || nextInt.CurveParameter >= 1) { // Reset to start next segment nextInt = nextStartInt; startInt = nextStartInt; nextStartInt = null; if (newPerimeter != null) { newPerimeter.Close(); } newPerimeter = null; newRegion = null; travelSide = HandSide.Undefined; } currentInt = nextInt; } if (newPerimeter != null) { newPerimeter.Close(); } //TODO: Assign un-intersected voids return(result); }