예제 #1
0
        /// <summary>
        /// Creates a interpolated curve through a set of points.<br/>
        /// <em>Refer to Algorithm A9.1 on The NURBS Book, pp.369-370 for details.</em>
        /// </summary>
        /// <param name="pts">The set of points to interpolate.</param>
        /// <param name="degree">The Curve degree.</param>
        /// <param name="startTangent">The tangent vector for the first point.</param>
        /// <param name="endTangent">The tangent vector for the last point.</param>
        /// <param name="centripetal">True use the chord as per knot spacing, false use the squared chord.</param>
        /// <returns>A the interpolated curve.</returns>
        public static NurbsBase Interpolated(List <Point3> pts, int degree, Vector3?startTangent = null,
                                             Vector3?endTangent = null, bool centripetal = false)
        {
            if (pts.Count < degree + 1)
            {
                throw new Exception($"You must supply at least degree + 1 points. You supplied {pts.Count} pts.");
            }

            // Gets uk parameters.
            List <double> uk = CurveHelpers.Parametrization(pts, centripetal);

            // Compute knot vectors.
            bool       hasTangents = startTangent != null && endTangent != null;
            KnotVector knots       = ComputeKnotsForInterpolation(uk, degree, hasTangents);

            // Global interpolation.
            // Build matrix of basis function coefficients.
            Matrix coeffMatrix = BuildCoefficientsMatrix(pts, degree, hasTangents, uk, knots);
            // Solve for each points.
            List <Point4> ctrlPts = (hasTangents)
                ? SolveCtrlPtsWithTangents(knots, pts, coeffMatrix, degree, new Vector3(startTangent.Value), new Vector3(endTangent.Value))
                : SolveCtrlPts(pts, coeffMatrix);

            return(new NurbsCurve(degree, knots, ctrlPts));
        }
예제 #2
0
        public void It_Refines_The_Curve_Knot(double val, int insertion)
        {
            // Arrange
            int degree = 3;

            List <double> newKnots = new List <double>();

            for (int i = 0; i < insertion; i++)
            {
                newKnots.Add(val);
            }

            List <Point3> pts = new List <Point3>();

            for (int i = 0; i <= 12 - degree - 2; i++)
            {
                pts.Add(new Point3(i, 0.0, 0.0));
            }

            NurbsCurve curve = new NurbsCurve(pts, degree);

            // Act
            NurbsBase curveAfterRefine = KnotVector.Refine(curve, newKnots);
            Point3    p0 = curve.PointAt(2.5);
            Point3    p1 = curveAfterRefine.PointAt(2.5);

            // Assert
            (curve.Knots.Count + insertion).Should().Be(curveAfterRefine.Knots.Count);
            (pts.Count + insertion).Should().Be(curveAfterRefine.ControlPointLocations.Count);
            (p0 == p1).Should().BeTrue();
        }
예제 #3
0
        public void It_Returns_A_Derive_Basic_Function_Given_NI()
        {
            // Arrange
            // Values and formulas from The Nurbs Book p.69 & p.72
            int        degree    = 2;
            int        span      = 4;
            int        order     = 2;
            double     parameter = 2.5;
            KnotVector knots     = new KnotVector {
                0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5
            };

            double[,] expectedResult = new double[, ] {
                { 0.125, 0.75, 0.125 }, { -0.5, 0.0, 0.5 }, { 1.0, -2.0, 1.0 }
            };

            // Act
            List <Vector> resultToCheck = GShark.Evaluate.Curve.DerivativeBasisFunctionsGivenNI(span, parameter, degree, order, knots);

            // Assert
            resultToCheck[0][0].Should().BeApproximately(expectedResult[0, 0], GSharkMath.MaxTolerance);
            resultToCheck[0][1].Should().BeApproximately(expectedResult[0, 1], GSharkMath.MaxTolerance);
            resultToCheck[0][2].Should().BeApproximately(expectedResult[0, 2], GSharkMath.MaxTolerance);

            resultToCheck[1][0].Should().BeApproximately(expectedResult[1, 0], GSharkMath.MaxTolerance);
            resultToCheck[1][1].Should().BeApproximately(expectedResult[1, 1], GSharkMath.MaxTolerance);
            resultToCheck[1][2].Should().BeApproximately(expectedResult[1, 2], GSharkMath.MaxTolerance);

            resultToCheck[2][0].Should().BeApproximately(expectedResult[2, 0], GSharkMath.MaxTolerance);
            resultToCheck[2][1].Should().BeApproximately(expectedResult[2, 1], GSharkMath.MaxTolerance);
            resultToCheck[2][2].Should().BeApproximately(expectedResult[2, 2], GSharkMath.MaxTolerance);

            resultToCheck.Count.Should().Be(order + 1);
            resultToCheck[0].Count.Should().Be(degree + 1);
        }
예제 #4
0
        /// <summary>
        /// Computes the non-vanishing basis functions.<br/>
        /// <em>Implementation of Algorithm A2.2 from The NURBS Book by Piegl and Tiller.<br/>
        /// Uses recurrence to compute the basis functions, also known as Cox - deBoor recursion formula.</em>
        /// </summary>
        /// <param name="degree">Degree of a curve.</param>
        /// <param name="knots">Set of knots.</param>
        /// <param name="span">Index span of knots.</param>
        /// <param name="knot">knot value.</param>
        /// <returns>List of non-vanishing basis functions.</returns>
        internal static List <double> BasisFunction(int degree, KnotVector knots, int span, double knot)
        {
            Vector left  = Vector.Zero1d(degree + 1);
            Vector right = Vector.Zero1d(degree + 1);
            // N[0] = 1.0 by definition;
            Vector N = Vector.Zero1d(degree + 1);

            N[0] = 1.0;

            for (int j = 1; j < degree + 1; j++)
            {
                left[j]  = knot - knots[span + 1 - j];
                right[j] = knots[span + j] - knot;
                double saved = 0.0;

                for (int r = 0; r < j; r++)
                {
                    double temp = N[r] / (right[r + 1] + left[j - r]);
                    N[r]  = saved + right[r + 1] * temp;
                    saved = left[j - r] * temp;
                }

                N[j] = saved;
            }

            return(N);
        }
예제 #5
0
        protected NurbsBase(int degree, KnotVector knots, List <Point4> controlPoints)
        {
            if (controlPoints is null)
            {
                throw new ArgumentNullException(nameof(controlPoints));
            }

            if (knots is null)
            {
                throw new ArgumentNullException(nameof(knots));
            }

            if (degree < 1)
            {
                throw new ArgumentException("Degree must be greater than 1!");
            }

            if (knots.Count != controlPoints.Count + degree + 1)
            {
                throw new ArgumentException("Number of controlPoints + degree + 1 must equal knots length!");
            }

            if (!knots.IsValid(degree, controlPoints.Count))
            {
                throw new ArgumentException("Invalid knot format! Should begin with degree + 1 repeats and end with degree + 1 repeats!");
            }

            Weights = Point4.GetWeights(controlPoints);
            Degree  = degree;
            Knots   = knots;
            ControlPointLocations = Point4.PointDehomogenizer1d(controlPoints);
            ControlPoints         = controlPoints;
        }
예제 #6
0
        /// <summary>
        /// Compute R - Eqn 9.67.
        /// </summary>
        private static List <Point3> ComputeValuesR(KnotVector knots, List <double> curveParameters, List <Point3> Rk, int degree, int numberOfCtrPts)
        {
            List <Vector> vectorR = new List <Vector>();

            for (int i = 1; i < numberOfCtrPts - 1; i++)
            {
                List <Vector> ruTemp = new List <Vector>();
                for (int j = 0; j < Rk.Count; j++)
                {
                    double tempBasisVal = Evaluate.Curve.OneBasisFunction(degree, knots, i, curveParameters[j + 1]);
                    ruTemp.Add(Rk[j] * tempBasisVal);
                }

                Vector tempVec = Vector.Zero1d(ruTemp[0].Count);
                for (int g = 0; g < ruTemp[0].Count; g++)
                {
                    foreach (Vector vec in ruTemp)
                    {
                        tempVec[g] += vec[g];
                    }
                }

                vectorR.Add(tempVec);
            }

            return(vectorR.Select(v => new Point3(v[0], v[1], v[2])).ToList());
        }
예제 #7
0
        /// <summary>
        /// Computes Rk - Eqn 9.63.
        /// </summary>
        private static List <Point3> ComputesValuesRk(KnotVector knots, List <double> curveParameters, int degree, List <Point3> pts, int numberOfCtrPts)
        {
            Point3        pt0 = pts[0];             // Q0
            Point3        ptm = pts[pts.Count - 1]; // Qm
            List <Point3> Rk  = new List <Point3>();

            for (int i = 1; i < pts.Count - 1; i++)
            {
                Point3 pti   = pts[i];
                double n0p   = Evaluate.Curve.OneBasisFunction(degree, knots, 0, curveParameters[i]);
                double nnp   = Evaluate.Curve.OneBasisFunction(degree, knots, numberOfCtrPts - 1, curveParameters[i]);
                Point3 elem2 = pt0 * n0p;
                Point3 elem3 = ptm * nnp;

                Point3 tempVec = new Point3();
                for (int j = 0; j < 3; j++)
                {
                    tempVec[j] = (pti[j] - elem2[j] - elem3[j]);
                }

                tempVec.X = pti.X - elem2.X - elem3.X;
                tempVec.Y = pti.Y - elem2.Y - elem3.Y;
                tempVec.Z = pti.Z - elem2.Z - elem3.Z;

                Rk.Add(tempVec);
            }

            return(Rk);
        }
예제 #8
0
        /// <summary>
        /// This method evaluate a B-spline span using the deBoor algorithm.
        /// https://github.com/mcneel/opennurbs/blob/2b96cf31429dab25bf8a1dbd171227c506b06f88/opennurbs_evaluate_nurbs.cpp#L1249
        /// This method is not implemented for clamped knots.
        /// </summary>
        /// <param name="controlPts">The control points of the curve.</param>
        /// <param name="knots">The knot vector of the curve.</param>
        /// <param name="degree">The value degree of the curve.</param>
        /// <param name="parameter">The parameter value where the curve is evaluated.</param>
        internal static void DeBoor(ref List <Point4> controlPts, KnotVector knots, int degree, double parameter)
        {
            if (Math.Abs(knots[degree] - knots[degree - 1]) < GSharkMath.Epsilon)
            {
                throw new Exception($"DeBoor evaluation failed: {knots[degree]} == {knots[degree + 1]}");
            }

            // deltaT = {knot[order-1] - t, knot[order] -  t, .. knot[2*order-3] - t}
            List <double> deltaT = new List <double>();

            for (int k = 0; k < degree; k++)
            {
                deltaT.Add(knots[degree + 1 + k] - parameter);
            }

            for (int i = degree; i > 0; --i)
            {
                for (int j = 0; j < i; j++)
                {
                    double k0 = knots[degree + 1 - i + j];
                    double k1 = knots[degree + 1 + j];

                    double alpha0 = deltaT[j] / (k1 - k0);
                    double alpha1 = 1.0 - alpha0;

                    Point4 cv1 = controlPts[j + 1];
                    Point4 cv0 = controlPts[j];

                    controlPts[j] = (cv0 * alpha0) + (cv1 * alpha1);
                }
            }
        }
예제 #9
0
        /// <summary>
        /// Constructs a nurbs curve representation of this polyline.
        /// </summary>
        /// <returns>A Nurbs curve shaped like this polyline.</returns>
        private void ToNurbs()
        {
            double        lengthSum = 0;
            List <double> weights   = new List <double>();
            KnotVector    knots     = new KnotVector {
                0, 0
            };
            List <Point4> ctrlPts = new List <Point4>();

            for (int i = 0; i < ControlPointLocations.Count - 1; i++)
            {
                lengthSum += Segments[i].Length;
                knots.Add(lengthSum);
                weights.Add(1.0);
                ctrlPts.Add(new Point4(ControlPointLocations[i], 1.0));
            }
            knots.Add(lengthSum);
            weights.Add(1.0);
            ctrlPts.Add(new Point4(ControlPointLocations.Last(), 1.0));

            Weights       = weights;
            Knots         = knots.Normalize();
            Degree        = 1;
            ControlPoints = ctrlPts;
        }
예제 #10
0
        /// <summary>
        /// Computes the knot vectors used to calculate a curve global interpolation.
        /// </summary>
        private static KnotVector ComputeKnotsForInterpolation(List <double> curveParameters, int degree, bool hasTangents)
        {
            // Start knot vectors.
            KnotVector knots = CollectionHelpers.RepeatData(0.0, degree + 1).ToKnot();

            // If we have tangent values we need two more control points and knots.
            int start = (hasTangents) ? 0 : 1;
            int end   = (hasTangents) ? curveParameters.Count - degree + 1 : curveParameters.Count - degree;

            // Use averaging method (Eqn 9.8) to compute internal knots in the knot vector.
            for (int i = start; i < end; i++)
            {
                double weightSum = 0.0;
                for (int j = 0; j < degree; j++)
                {
                    weightSum += curveParameters[i + j];
                }

                knots.Add((1.0 / degree) * weightSum);
            }

            // Add end knot vectors.
            knots.AddRange(CollectionHelpers.RepeatData(1.0, degree + 1));
            return(knots);
        }
예제 #11
0
        /// <summary>
        /// Defines the control points defining the tangent values for the first and last points.
        /// </summary>
        private static List <Point4> SolveCtrlPtsWithTangents(KnotVector knots, List <Point3> pts, Matrix coeffMatrix, int degree, Vector3 startTangent, Vector3 endTangent)
        {
            Matrix matrixLu  = Matrix.Decompose(coeffMatrix, out int[] permutation);
            Matrix ptsSolved = new Matrix();

            // Equations 9.11
            double mult0 = knots[degree + 1] / degree;
            // Equations 9.12
            double mult1 = (1 - knots[knots.Count - degree - 2]) / degree;

            // Solve for each dimension.
            for (int i = 0; i < 3; i++)
            {
                Vector b = new Vector {
                    pts[0][i], startTangent[i] * mult0
                };
                // Insert the tangents at the second and second to last index.
                // Equations 9.11
                b.AddRange(pts.Skip(1).Take(pts.Count - 2).Select(pt => pt[i]));
                // Equations 9.12
                b.Add(endTangent[i] * mult1);
                b.Add(pts[pts.Count - 1][i]);

                Vector solution = Matrix.Solve(matrixLu, permutation, b);
                ptsSolved.Add(solution);
            }

            return(ptsSolved.Transpose().Select(pt => new Point4(pt[0], pt[1], pt[2], 1)).ToList());
        }
예제 #12
0
        /// <summary>
        /// Constructs a NURBS surface from a 2D grid of points.<br/>
        /// The grid of points should be organized as, the V direction from left to right and the U direction increases from bottom to top.
        /// </summary>
        /// <param name="degreeU">Degree of surface in U direction.</param>
        /// <param name="degreeV">Degree of surface in V direction.</param>
        /// <param name="points">Points locations.</param>
        /// <param name="weight">A 2D collection of weights.</param>
        /// <returns>A NURBS surface.</returns>
        public static NurbsSurface FromPoints(int degreeU, int degreeV, List <List <Point3> > points, List <List <double> > weight = null)
        {
            KnotVector knotU      = new KnotVector(degreeU, points.Count);
            KnotVector knotV      = new KnotVector(degreeV, points[0].Count);
            var        controlPts = points.Select((pts, i) => pts.Select((pt, j) => weight != null ? new Point4(pt, weight[i][j]) : new Point4(pt)).ToList()).ToList();

            return(new NurbsSurface(degreeU, degreeV, knotU, knotV, controlPts));
        }
예제 #13
0
        [InlineData(new double[] { -0.666, -0.333, 0, 0.333, 0.666, 1, 1.333, 1.666 }, 2, 5, true)]      // Periodic
        public void It_Checks_If_The_Knots_Are_Valid(double[] knots, int degree, int ctrlPts, bool expectedResult)
        {
            // Act
            KnotVector knot = new KnotVector(knots);

            // Assert
            knot.IsValid(degree, ctrlPts).Should().Be(expectedResult);
        }
예제 #14
0
        public void It_Returns_True_If_KnotVector_Is_Clamped(double[] knots, int degree, bool expectedResult)
        {
            // Act
            KnotVector knotVector = new KnotVector(knots);

            // Assert
            knotVector.IsClamped(degree).Should().Be(expectedResult);
        }
예제 #15
0
        public void It_Checks_If_Knots_Is_Periodic(double[] knots, int degree, bool expectedResult)
        {
            // Act
            KnotVector knot = new KnotVector(knots);

            // Assert
            knot.IsPeriodic(degree).Should().Be(expectedResult);
        }
예제 #16
0
 protected NurbsBase()
 {
     Weights = new List <double>();
     Degree  = 0;
     Knots   = new KnotVector();
     ControlPointLocations = new List <Point3>();
     ControlPoints         = new List <Point4>();
 }
예제 #17
0
        /// <summary>
        /// Computes the value of a basis function for a single value.<br/>
        /// <em>Implementation of Algorithm A2.4 from The NURBS Book by Piegl and Tiller.</em><br/>
        /// </summary>
        /// <param name="degree">Degree of a curve.</param>
        /// <param name="knots">Set of knots.</param>
        /// <param name="span">Index span of knots.</param>
        /// <param name="knot">knot value.</param>
        /// <returns>The single parameter value of the basis function.</returns>
        public static double OneBasisFunction(int degree, KnotVector knots, int span, double knot)
        {
            // Special case at boundaries.
            if ((span == 0 && Math.Abs(knot - knots[0]) < GSharkMath.MaxTolerance) ||
                (span == knots.Count - degree - 2) && Math.Abs(knot - knots[knots.Count - 1]) < GSharkMath.MaxTolerance)
            {
                return(1.0);
            }

            // Local property, parameter is outside of span range.
            if (knot < knots[span] || knot >= knots[span + degree + 1])
            {
                return(0.0);
            }

            List <double> N = CollectionHelpers.RepeatData(0.0, degree + span + 1);

            // Initialize the zeroth degree basic functions.
            for (int j = 0; j < degree + 1; j++)
            {
                if (knot >= knots[span + j] && knot < knots[span + j + 1])
                {
                    N[j] = 1.0;
                }
            }

            // Compute triangular table of basic functions.
            for (int k = 1; k < degree + 1; k++)
            {
                double saved = 0.0;
                if (N[0] != 0.0)
                {
                    saved = ((knot - knots[span]) * N[0]) / (knots[span + k] - knots[span]);
                }

                for (int j = 0; j < degree - k + 1; j++)
                {
                    double uLeft  = knots[span + j + 1];
                    double uRight = knots[span + j + k + 1];

                    if (N[j + 1] == 0.0)
                    {
                        N[j]  = saved;
                        saved = 0.0;
                    }
                    else
                    {
                        double temp = N[j + 1] / (uRight - uLeft);
                        N[j]  = saved + (uRight - knot) * temp;
                        saved = (knot - uLeft) * temp;
                    }
                }
            }

            return(N[0]);
        }
예제 #18
0
        public virtual NurbsBase Reverse()
        {
            List <Point4> controlPts = new List <Point4>(ControlPoints);

            controlPts.Reverse();

            KnotVector knots = KnotVector.Reverse(Knots);

            return(new NurbsCurve(Degree, knots, controlPts));
        }
예제 #19
0
        /// <summary>
        /// Bezier degree reduction.
        /// <em>Refer to The NURBS Book by Piegl and Tiller at page 220.</em>
        /// </summary>
        private static double BezierDegreeReduce(Point4[] bpts, int degree, out Point4[] rbpts)
        {
            // Eq. 5.40
            int r = (int)Math.Floor(((double)degree - 1) / 2);

            Point4[] P = new Point4[degree];
            P[0]            = bpts[0];
            P[P.Length - 1] = bpts.Last();

            bool isDegreeOdd = degree % 2 != 0;

            int r1 = (isDegreeOdd) ? r - 1 : r;

            // Eq. 5.41
            for (int i = 1; i <= r1; i++)
            {
                double alphaI = (double)i / degree;
                P[i] = (bpts[i] - (P[i - 1] * alphaI)) / (1 - alphaI);
            }

            for (int i = degree - 2; i >= r + 1; i--)
            {
                double alphaI = (double)(i + 1) / degree;
                P[i] = (bpts[i + 1] - (P[i + 1] * (1 - alphaI))) / alphaI;
            }

            /* Equations (5.43) and (5.44) express the parametric error {distance between points at corresponding parameter values);
             * the maximums of geometric and parametric errors are not necessarily at the same u value.
             * For p even the maximum error occurs at u = 1/2; for p odd the error is zero at u = 1/2, and it has two peaks a bit to the left and
             * right of u = 1/2. */

            // Eq. 5.43 p even.
            KnotVector    knots           = new KnotVector(degree - 1, P.Length);
            int           span            = knots.Span(degree - 1, 0.5);
            List <double> Br              = Evaluate.Curve.BasisFunction(degree - 1, knots, span, 0.5);
            double        parametricError = bpts[r + 1].DistanceTo((P[r] + P[r + 1]) * 0.5) * Br[r + 1];

            // Eq. 5.42
            if (isDegreeOdd)
            {
                double alphaR = (double)r / degree;
                Point4 PLeft  = (bpts[r] - (P[r - 1] * alphaR)) / (1 - alphaR);

                double alphaR1 = (double)(r + 1) / degree;
                Point4 PRight  = (bpts[r + 1] - (P[r + 1] * (1 - alphaR1))) / alphaR1;

                P[r] = (PLeft + PRight) * 0.5;
                // Eq. 5.44 p odd.
                parametricError = ((1 - alphaR) * 0.5) * ((Br[r] - Br[r + 1]) * PLeft.DistanceTo(PRight));
            }

            rbpts = P;
            return(parametricError);
        }
예제 #20
0
        public void CreateUniformPeriodicKnotVector_Throws_An_Exception_If_Are_Not_Valid_Inputs(int degree, int numberOfControlPts)
        {
            // Are identifies as not valid inputs when:
            // Degree and control points count is less than 2.
            // Degree is bigger than the control points count.
            // Act
            Func <KnotVector> funcResult = () => KnotVector.UniformPeriodic(degree, numberOfControlPts);

            // Assert
            funcResult.Should().Throw <Exception>();
        }
예제 #21
0
        public void It_Throws_An_Exception_If_Input_Knot_Vector_Is_Empty()
        {
            // Assert
            KnotVector knots = new KnotVector();

            // Act
            Func <KnotVector> func = () => knots.Normalize();

            // Arrange
            func.Should().Throw <Exception>().WithMessage("Input knot vector cannot be empty");
        }
예제 #22
0
        /// <summary>
        /// Samples a curve in an adaptive way. <br/>
        /// <em>Corresponds to this algorithm http://ariel.chronotext.org/dd/defigueiredo93adaptive.pdf </em>
        /// </summary>
        /// <param name="curve">The curve to sampling.</param>
        /// <param name="tolerance">The tolerance for the adaptive division.</param>
        /// <returns>A tuple collecting the parameter where it was sampled and the points.</returns>
        public static (List <double> tValues, List <Point3> pts) AdaptiveSample(NurbsBase curve, double tolerance = GSharkMath.MinTolerance)
        {
            if (curve.Degree != 1)
            {
                return(AdaptiveSampleRange(curve, curve.Knots[0], curve.Knots[curve.Knots.Count - 1], tolerance));
            }
            KnotVector copyKnot = new KnotVector(curve.Knots);

            copyKnot.RemoveAt(0);
            copyKnot.RemoveAt(copyKnot.Count - 1);
            return(copyKnot, curve.ControlPointLocations);
        }
예제 #23
0
        public void KnotMultiplicity_Returns_Knot_Multiplicity_At_The_Given_Index(double knot, int expectedMultiplicity)
        {
            // Arrange
            KnotVector knots = new KnotVector {
                0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3.3, 4, 4, 4
            };

            // Act
            int multiplicity = knots.Multiplicity(knot);

            // Assert
            multiplicity.Should().Be(expectedMultiplicity);
        }
예제 #24
0
        public void It_Creates_A_Copy_Of_The_Knot_Vector()
        {
            // Assert
            KnotVector knotVector = new KnotVector {
                0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3.3, 4, 4, 4
            };

            // Act
            KnotVector knotVectorCopy = knotVector.Copy();

            // Arrange
            knotVectorCopy.Should().NotBeSameAs(knotVector);
            knotVectorCopy.Should().BeEquivalentTo(knotVector);
        }
예제 #25
0
        public void It_Returns_The_KnotSpan_Given_A_Parameter(int expectedValue, double parameter)
        {
            // Arrange
            KnotVector knotVector = new KnotVector {
                0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5
            };
            int degree = 2;

            // Act
            int result = knotVector.Span(knotVector.Count - degree - 2, 2, parameter);

            // Assert
            result.Should().Be(expectedValue);
        }
예제 #26
0
        public virtual NurbsBase Close()
        {
            // Wrapping control points
            List <Point4> pts = new List <Point4>(ControlPoints);

            for (int i = 0; i < Degree; i++)
            {
                pts.Add(pts[i]);
            }

            KnotVector knots = KnotVector.UniformPeriodic(Degree, pts.Count);

            return(new NurbsCurve(Degree, knots, pts));
        }
예제 #27
0
        /// <summary>
        /// Internal constructor used to validate the NURBS surface.
        /// </summary>
        /// <param name="degreeU">The degree in the U direction.</param>
        /// <param name="degreeV">The degree in the V direction.</param>
        /// <param name="knotsU">The knotVector in the U direction.</param>
        /// <param name="knotsV">The knotVector in the V direction.</param>
        /// <param name="controlPts">Two dimensional array of points.</param>
        internal NurbsSurface(int degreeU, int degreeV, KnotVector knotsU, KnotVector knotsV, List <List <Point4> > controlPts)
        {
            if (controlPts == null)
            {
                throw new ArgumentNullException("Control points array connot be null!");
            }
            if (degreeU < 1)
            {
                throw new ArgumentException("DegreeU must be greater than 1!");
            }
            if (degreeV < 1)
            {
                throw new ArgumentException("DegreeV must be greater than 1!");
            }
            if (knotsU == null)
            {
                throw new ArgumentNullException("KnotU cannot be null!");
            }
            if (knotsV == null)
            {
                throw new ArgumentNullException("KnotV cannot be null!");
            }
            if (knotsU.Count != controlPts.Count() + degreeU + 1)
            {
                throw new ArgumentException("Points count + degreeU + 1 must equal knotsU count!");
            }
            if (knotsV.Count != controlPts.First().Count() + degreeV + 1)
            {
                throw new ArgumentException("Points count + degreeV + 1 must equal knotsV count!");
            }
            if (!knotsU.IsValid(degreeU, controlPts.Count()))
            {
                throw new ArgumentException("Invalid knotsU!");
            }
            if (!knotsV.IsValid(degreeV, controlPts.First().Count()))
            {
                throw new ArgumentException("Invalid knotsV!");
            }

            DegreeU = degreeU;
            DegreeV = degreeV;
            KnotsU  = (Math.Abs(knotsU.GetDomain(degreeU).Length - 1.0) > GSharkMath.Epsilon) ? knotsU.Normalize() : knotsU;
            KnotsV  = (Math.Abs(knotsV.GetDomain(degreeV).Length - 1.0) > GSharkMath.Epsilon) ? knotsV.Normalize() : knotsV;
            Weights = Point4.GetWeights2d(controlPts);
            ControlPointLocations = Point4.PointDehomogenizer2d(controlPts);
            ControlPoints         = controlPts;
            DomainU = new Interval(KnotsU.First(), KnotsU.Last());
            DomainV = new Interval(KnotsV.First(), KnotsV.Last());
        }
예제 #28
0
        public void It_Creates_An_Unclamped_Uniform_KnotVector()
        {
            // Arrange
            int        degree             = 3;
            int        ctrlPts            = 5;
            KnotVector expectedKnotVector = new KnotVector {
                0.0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0
            };

            // Act
            KnotVector knots = new KnotVector(degree, ctrlPts, false);

            // Assert
            knots.Should().BeEquivalentTo(expectedKnotVector);
        }
예제 #29
0
        public void It_Reverses_A_Knot_Vectors()
        {
            // Assert
            KnotVector knotVector = new KnotVector {
                0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3.3, 4, 4, 4
            };
            KnotVector expectedKnotVector = new KnotVector {
                0, 0, 0, 0.7000000000000002, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4
            };

            // Act
            KnotVector reversedKnots = KnotVector.Reverse(knotVector);

            // Arrange
            reversedKnots.Should().BeEquivalentTo(expectedKnotVector);
        }
예제 #30
0
        public void It_Returns_A_Normalized_Knot_Vector()
        {
            // Arrange
            KnotVector knots = new KnotVector {
                -5, -5, -3, -2, 2, 3, 5, 5
            };
            KnotVector knotsExpected = new KnotVector {
                0.0, 0.0, 0.2, 0.3, 0.7, 0.8, 1.0, 1.0
            };

            // Act
            KnotVector normalizedKnots = knots.Normalize();

            // Assert
            normalizedKnots.Should().BeEquivalentTo(knotsExpected);
        }