/// <summary> /// Initialise a new Extrusion object representing an /// extrusion of the specified profile along the specified path /// </summary> /// <param name="profile">The profile surface to extrude</param> /// <param name="path">The extrusion vector</param> public Extrusion(PlanarRegion profile, Vector path) { _Profile = profile; _Path = path; }
/// <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); }
/// <summary> /// Initialise a new Extrusion object representing an /// extrusion of the specified profile along the specified path /// </summary> /// <param name="profile">The profile perimeter curve. Must be planar.</param> /// <param name="path">The extrusion vector</param> public Extrusion(Curve profile, Vector path) { _Profile = new PlanarRegion(profile); _Path = path; }