예제 #1
0
파일: Extrusion.cs 프로젝트: lulzzz/Nucleus
 /// <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;
 }
예제 #2
0
        /// <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);
        }
예제 #3
0
파일: Extrusion.cs 프로젝트: lulzzz/Nucleus
 /// <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;
 }