예제 #1
0
        /// <summary>
        /// Find Curve Segment At a given Length.
        /// When there is no curve segments in the PolyCurve, return null;
        /// If the provided length is greater than the PolyCurve Length, then it return the last segment in PolyCurve;
        /// </summary>
        /// <param name="length">Segment Length</param>
        public NurbsBase SegmentAtLength(double length)
        {
            NurbsBase segment = null;

            if (length > Length)
            {
                return(_segments.Last());
            }
            if (_segments.Count == 1)
            {
                return(_segments.First());
            }

            double temp = 0;

            foreach (NurbsBase curve in _segments)
            {
                double cumulativeLength = curve.Length + temp;
                if (length >= temp && length < cumulativeLength)
                {
                    segment = curve;
                    break;
                }
                temp = cumulativeLength;
            }

            return(segment);
        }
예제 #2
0
        /// <summary>
        /// Constructs a ruled surface between two curves.
        /// <em>Follows the algorithm at page 337 of The NURBS Book by Piegl and Tiller.</em>
        /// </summary>
        /// <param name="curveA">The first curve.</param>
        /// <param name="curveB">The second curve.</param>
        /// <returns>A ruled surface.</returns>
        public static NurbsSurface Ruled(NurbsBase curveA, NurbsBase curveB)
        {
            IList <NurbsBase> curves = new[] { curveA, curveB };

            curves = CurveHelpers.NormalizedDegree(curves);
            curves = CurveHelpers.NormalizedKnots(curves);

            return(new NurbsSurface(1, curves[0].Degree, new KnotVector(1, 2), curves[0].Knots,
                                    new List <List <Point4> > {
                curves[0].ControlPoints, curves[1].ControlPoints
            }));
        }
예제 #3
0
        /// <summary>
        /// Constructs a surface extruding a curve profile long a direction.
        /// </summary>
        /// <param name="direction">The extrusion direction.</param>
        /// <param name="profile">The profile curve to extrude.</param>
        /// <returns>The extruded surface.</returns>
        public static NurbsSurface FromExtrusion(Vector3 direction, NurbsBase profile)
        {
            Transform     xForm = Core.Transform.Translation(direction);
            List <Point4> translatedControlPts =
                profile.ControlPoints.Select(controlPoint => controlPoint.Transform(xForm)).ToList();

            return(new NurbsSurface(1, profile.Degree, new KnotVector {
                0, 0, 1, 1
            }, profile.Knots,
                                    new List <List <Point4> > {
                profile.ControlPoints, translatedControlPts
            }));
        }
예제 #4
0
        /// <summary>
        /// Constructs a sweep surface with one rail curve.
        /// <em>Follows the algorithm A10.2 at page 477 of The NURBS Book by Piegl and Tiller.</em>
        /// </summary>
        /// <param name="rail">The rail curve.</param>
        /// <param name="profile">The section curve.</param>
        /// <returns>The sweep surface.</returns>
        public static NurbsSurface FromSweep(NurbsBase rail, NurbsBase profile)
        {
            var(tValues, _) = Sampling.Curve.AdaptiveSample(rail, GSharkMath.MaxTolerance);
            List <Plane>     frames = rail.PerpendicularFrames(tValues);
            List <NurbsBase> curves = new List <NurbsBase> {
                profile
            };

            for (int i = 1; i <= frames.Count; i++)
            {
                Transform xForm = Core.Transform.PlaneToPlane(frames[0], frames[i]);
                curves.Add(((NurbsCurve)curves[0]).Transform(xForm));
            }

            return(FromLoft(curves));
        }
예제 #5
0
        /// <summary>
        /// Checks to define if the curve can be appended.
        /// </summary>
        private void HealthChecks(NurbsBase curve, NurbsBase curveToAppend)
        {
            if (_segments.Count <= 0)
            {
                return;
            }

            if (curve.IsClosed)
            {
                throw new InvalidOperationException($"The polyCurve is closed can not be possible to connect the {curveToAppend.GetType()}.");
            }

            if (curve.EndPoint.DistanceTo(curveToAppend.StartPoint) > GSharkMath.Epsilon)
            {
                throw new InvalidOperationException("The two curves can not be connected.");
            }
        }
예제 #6
0
        /// <summary>
        /// Creates a surface of revolution through an arbitrary angle, and axis.
        /// <em>Corresponds the algorithm A8.1 of The NURBS Book by Piegl and Tiller.</em>
        /// </summary>
        /// <param name="curveProfile">Profile curve.</param>
        /// <param name="axis">Revolution axis.</param>
        /// <param name="rotationAngle">Angle in radiance.</param>
        /// <returns>The revolution surface.</returns>
        public static NurbsSurface Revolved(NurbsBase curveProfile, Ray axis, double rotationAngle)
        {
            // if angle is less than 90.
            int        arcCount = 1;
            KnotVector knotsU   = Vector.Zero1d(6).ToKnot();

            if (rotationAngle <= Math.PI && rotationAngle > (Math.PI / 2))
            {
                arcCount  = 2;
                knotsU[3] = knotsU[4] = 0.5;
            }

            if (rotationAngle <= (3 * Math.PI / 2) && rotationAngle > Math.PI)
            {
                arcCount  = 3;
                knotsU    = Vector.Zero1d(6 + 2 * (arcCount - 1)).ToKnot();
                knotsU[3] = knotsU[4] = (double)1 / 3;
                knotsU[5] = knotsU[6] = (double)2 / 3;
            }

            if (rotationAngle <= (4 * Math.PI) && rotationAngle > (3 * Math.PI / 2))
            {
                arcCount  = 4;
                knotsU    = Vector.Zero1d(6 + 2 * (arcCount - 1)).ToKnot();
                knotsU[3] = knotsU[4] = (double)1 / 4;
                knotsU[5] = knotsU[6] = (double)1 / 2;
                knotsU[7] = knotsU[8] = (double)3 / 4;
            }

            // load start and end knots.
            int t = 3 + 2 * (arcCount - 1);

            for (int i = 0; i < 3; i++, t++)
            {
                knotsU[i] = 0.0;
                knotsU[t] = 1.0;
            }

            // some initialization.
            double divideAngle = rotationAngle / arcCount;
            int    n           = 2 * arcCount;
            double wm          = divideAngle / 2; // is the base angle.

            // initialize the sines and cosines only once.
            double angle = 0.0;

            double[] sines   = new double[arcCount + 1];
            double[] cosines = new double[arcCount + 1];
            for (int i = 1; i <= arcCount; i++)
            {
                angle     += divideAngle;
                sines[i]   = Math.Sin(angle);
                cosines[i] = Math.Cos(angle);
            }

            // loop and compute each u row of control points and weights.
            List <List <Point4> > controlPts = new List <List <Point4> >();

            for (int r = 0; r < 2 * arcCount + 1; r++)
            {
                List <Point4> temp = CollectionHelpers.RepeatData(Point4.Zero, curveProfile.ControlPoints.Count);
                controlPts.Add(temp);
            }

            for (int j = 0; j < curveProfile.ControlPointLocations.Count; j++)
            {
                Point3  ptO     = axis.ClosestPoint(curveProfile.ControlPointLocations[j]);
                Vector3 vectorX = curveProfile.ControlPointLocations[j] - ptO;
                double  radius  = vectorX.Length; // the radius at that length.
                Vector3 vectorY = Vector3.CrossProduct(axis.Direction, vectorX);

                if (radius > GSharkMath.Epsilon)
                {
                    vectorX *= (1 / radius);
                    vectorY *= (1 / radius);
                }

                // initialize the first control points and weights.
                Point3 pt0 = curveProfile.ControlPointLocations[j];
                controlPts[0][j] = new Point4(pt0, curveProfile.Weights[j]);

                Vector3 tangent0 = vectorY;
                int     index    = 0;

                for (int i = 1; i <= arcCount; i++)
                {
                    // rotated generatrix point.
                    Point3 pt2 = (Math.Abs(radius) < GSharkMath.Epsilon)
                        ? ptO
                        : ptO + (vectorX * (cosines[i] * radius) + vectorY * (sines[i] * radius));

                    controlPts[index + 2][j] = new Point4(pt2, curveProfile.Weights[j]);

                    // construct the vector tangent to the rotation.
                    Vector3 rotationTangent = vectorX * (-1 * sines[i]) + vectorY * cosines[i];

                    // construct the next control point.
                    if (Math.Abs(radius) < GSharkMath.Epsilon)
                    {
                        controlPts[index + 1][j] = ptO;
                    }
                    else
                    {
                        Line ln0 = new Line(pt0, tangent0, tangent0.Length);
                        Line ln1 = new Line(pt2, rotationTangent, rotationTangent.Length);
                        Intersection.Intersect.LineLine(ln0, ln1, out Point3 intersectionPt, out _, out _, out _);
                        controlPts[index + 1][j] = new Point4(intersectionPt, wm * curveProfile.Weights[j]);
                    }

                    index += 2;
                    if (i >= arcCount)
                    {
                        continue;
                    }
                    pt0      = pt2;
                    tangent0 = rotationTangent;
                }
            }

            return(new NurbsSurface(2, curveProfile.Degree, knotsU, curveProfile.Knots, controlPts.Select(pts => pts.ToList()).ToList()));
        }
예제 #7
0
        /// <summary>
        /// Constructs a NURBS surface from a set of NURBS curves.<br/>
        /// </summary>
        /// <param name="curves">Set of a minimum of two curves to create the surface.</param>
        /// <param name="loftType">Enum to choose the type of loft generation.</param>
        /// <returns>A NURBS surface.</returns>
        public static NurbsSurface FromLoft(IList <NurbsBase> curves, LoftType loftType = LoftType.Normal)
        {
            if (curves == null)
            {
                throw new ArgumentException("An invalid number of curves to perform the loft.");
            }

            if (curves.Count < 2)
            {
                throw new ArgumentException("An invalid number of curves to perform the loft.");
            }

            if (curves.Any(x => x == null))
            {
                throw new ArgumentException("The input set contains null curves.");
            }

            bool isClosed = curves[0].IsClosed;

            foreach (NurbsBase c in curves.Skip(1))
            {
                if (isClosed != c.IsClosed)
                {
                    throw new ArgumentException("Loft only works if all curves are open, or all curves are closed.");
                }
            }

            // Copy curves for possible operation of homogenization.
            IList <NurbsBase> copyCurves = new List <NurbsBase>(curves);

            // Clamp curves if periodic.
            if (copyCurves[0].IsPeriodic)
            {
                for (int i = 0; i < copyCurves.Count; i++)
                {
                    copyCurves[i] = copyCurves[i].ClampEnds();
                }
            }

            // If necessary, the curves can be brought to a common degree and knots, as we do for the ruled surface.
            // In fact, the ruled surface is a special case of a skinned surface.
            if (copyCurves.Any(c => c.Degree != copyCurves[0].Degree))
            {
                copyCurves = CurveHelpers.NormalizedDegree(copyCurves);
                copyCurves = CurveHelpers.NormalizedKnots(copyCurves);
            }

            int                   degreeV              = copyCurves[0].Degree;
            int                   degreeU              = 3;
            KnotVector            knotVectorU          = new KnotVector();
            KnotVector            knotVectorV          = copyCurves[0].Knots;
            List <List <Point4> > surfaceControlPoints = new List <List <Point4> >();

            switch (loftType)
            {
            case LoftType.Normal:
                List <List <Point4> > tempPts = new List <List <Point4> >();
                for (int n = 0; n < copyCurves[0].ControlPointLocations.Count; n++)
                {
                    List <Point3> pts = copyCurves.Select(c => c.ControlPointLocations[n]).ToList();
                    NurbsBase     crv = Fitting.Curve.Interpolated(pts, degreeU);
                    tempPts.Add(crv.ControlPoints);
                    knotVectorU = crv.Knots;
                }
                surfaceControlPoints = CollectionHelpers.Transpose2DArray(tempPts);
                break;

            case LoftType.Loose:
                surfaceControlPoints = copyCurves.Select(c => c.ControlPoints).ToList();
                knotVectorU          = new KnotVector(degreeU, copyCurves.Count);
                break;
            }
            return(new NurbsSurface(degreeU, degreeV, knotVectorU, knotVectorV, surfaceControlPoints));
        }