Ejemplo n.º 1
0
        public void It_Returns_A_Binomial_Coefficient(int n, int k, double resultValue)
        {
            // Act
            double valToCheck = GSharkMath.GetBinomial(n, k);

            // Assert
            (System.Math.Abs(valToCheck - resultValue) < GSharkMath.Epsilon).Should().BeTrue();
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Computes the derivatives at the given U and V parameters on a NURBS surface.<br/>
        /// <para>Returns a two dimensional array containing the derivative vectors.<br/>
        /// Increasing U partial derivatives are increasing row-wise.Increasing V partial derivatives are increasing column-wise.<br/>
        /// Therefore, the[0,0] position is a point on the surface, [n,0] is the nth V partial derivative, the[n,n] position is twist vector or mixed partial derivative UV.</para>
        /// <em>Corresponds to algorithm 4.4 from The NURBS Book by Piegl and Tiller.</em>
        /// </summary>
        /// <param name="surface">The surface.</param>
        /// <param name="u">The u parameter at which to evaluate the derivatives.</param>
        /// <param name="v">The v parameter at which to evaluate the derivatives.</param>
        /// <param name="numDerivs">Number of derivatives to evaluate, set as default to 1.</param>
        /// <returns>The derivatives.</returns>
        internal static Vector3[,] RationalDerivatives(NurbsSurface surface, double u, double v, int numDerivs = 1)
        {
            if (u < 0.0 || u > 1.0)
            {
                throw new ArgumentException("The U parameter is not into the domain 0.0 to 1.0.");
            }

            if (v < 0.0 || v > 1.0)
            {
                throw new ArgumentException("The V parameter is not into the domain 0.0 to 1.0.");
            }

            var derivatives = Derivatives(surface, u, v, numDerivs);

            Vector3[,] SKL = new Vector3[numDerivs + 1, numDerivs + 1];

            for (int k = 0; k < numDerivs + 1; k++)
            {
                for (int l = 0; l < numDerivs - k + 1; l++)
                {
                    Vector3 t = derivatives.Item1[k, l];
                    for (int j = 1; j < l + 1; j++)
                    {
                        t -= SKL[k, l - j] * (GSharkMath.GetBinomial(l, j) * derivatives.Item2[0, j]);
                    }

                    for (int i = 1; i < k + 1; i++)
                    {
                        t -= SKL[k - i, l] * (GSharkMath.GetBinomial(k, i) * derivatives.Item2[i, 0]);
                        Vector3 t2 = Vector3.Zero;
                        for (int j = 1; j < l + 1; j++)
                        {
                            t2 += SKL[k - i, l - j] * (GSharkMath.GetBinomial(l, j) * derivatives.Item2[i, j]);
                        }

                        t -= t2 * GSharkMath.GetBinomial(k, i);
                    }
                    SKL[k, l] = t / derivatives.Item2[0, 0];
                }
            }

            return(SKL);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Determines the derivatives of a curve at a given parameter.<br/>
        /// <em>Corresponds to algorithm 4.2 from The NURBS Book by Piegl and Tiller.</em>
        /// </summary>
        /// <param name="curve">The curve object.</param>
        /// <param name="parameter">Parameter on the curve at which the point is to be evaluated</param>
        /// <param name="numberOfDerivatives">The number of derivatives required.</param>
        /// <returns>The derivatives.</returns>
        public static List <Vector3> RationalDerivatives(NurbsBase curve, double parameter, int numberOfDerivatives = 1)
        {
            List <Point4> derivatives = CurveDerivatives(curve, parameter, numberOfDerivatives);
            // Array of derivative of A(t).
            // Where A(t) is the vector - valued function whose coordinates are the first three coordinates
            // of an homogenized pts.
            // Correspond in the book to Aders.
            List <Point3> rationalDerivativePoints = Point4.RationalPoints(derivatives);
            // Correspond in the book to wDers.
            List <double>  weightDers = Point4.GetWeights(derivatives);
            List <Vector3> CK         = new List <Vector3>();

            for (int k = 0; k < numberOfDerivatives + 1; k++)
            {
                Point3 rationalDerivativePoint = rationalDerivativePoints[k];

                for (int i = 1; i < k + 1; i++)
                {
                    double valToMultiply = GSharkMath.GetBinomial(k, i) * weightDers[i];
                    var    pt            = CK[k - i];
                    for (int j = 0; j < rationalDerivativePoint.Size; j++)
                    {
                        rationalDerivativePoint[j] = rationalDerivativePoint[j] - valToMultiply * pt[j];
                    }
                }

                for (int j = 0; j < rationalDerivativePoint.Size; j++)
                {
                    rationalDerivativePoint[j] = rationalDerivativePoint[j] * (1 / weightDers[0]);
                }

                CK.Add(rationalDerivativePoint);
            }
            // Return C(t) derivatives.
            return(CK);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Elevates the degree of a curve.
        /// <em>Implementation of Algorithm A5.9 of The NURBS Book by Piegl and Tiller.</em>
        /// </summary>
        /// <param name="curve">The object curve to elevate.</param>
        /// <param name="finalDegree">The expected final degree. If the supplied degree is less or equal the curve is returned unmodified.</param>
        /// <returns>The curve after degree elevation.</returns>
        internal static NurbsBase ElevateDegree(NurbsBase curve, int finalDegree)
        {
            if (finalDegree <= curve.Degree)
            {
                return(curve);
            }

            int           n  = curve.Knots.Count - curve.Degree - 2;
            int           p  = curve.Degree;
            KnotVector    U  = curve.Knots;
            List <Point4> Pw = curve.ControlPoints;
            int           t  = finalDegree - curve.Degree; // Degree elevate a curve t times.


            // local arrays.
            double[,] bezalfs = new double[p + t + 1, p + 1];
            Point4[] bpts     = new Point4[p + 1];
            Point4[] ebpts    = new Point4[p + t + 1];
            Point4[] nextbpts = new Point4[p - 1];
            double[] alphas   = new double[p - 1];

            int m   = n + p + 1;
            int ph  = finalDegree;
            int ph2 = (int)Math.Floor((double)(ph / 2));

            // Output values;
            List <Point4> Qw = new List <Point4>();
            KnotVector    Uh = new KnotVector();

            // Compute Bezier degree elevation coefficients.
            bezalfs[0, 0] = bezalfs[ph, p] = 1.0;
            for (int i = 1; i <= ph2; i++)
            {
                double inv = 1.0 / GSharkMath.GetBinomial(ph, i);
                int    mpi = Math.Min(p, i);

                for (int j = Math.Max(0, i - t); j <= mpi; j++)
                {
                    bezalfs[i, j] = inv * GSharkMath.GetBinomial(p, j) * GSharkMath.GetBinomial(t, i - j);
                }
            }

            for (int i = ph2 + 1; i <= ph - 1; i++)
            {
                int mpi = Math.Min(p, i);
                for (int j = Math.Max(0, i - t); j <= mpi; j++)
                {
                    bezalfs[i, j] = bezalfs[ph - i, p - j];
                }
            }

            int    mh   = ph;
            int    kind = ph + 1;
            int    r    = -1;
            int    a    = p;
            int    b    = p + 1;
            int    cind = 1;
            double ua   = U[0];

            Qw.Add(Pw[0]);

            for (int i = 0; i <= ph; i++)
            {
                Uh.Add(ua);
            }

            // Initialize first Bezier segment.
            for (int i = 0; i <= p; i++)
            {
                bpts[i] = Pw[i];
            }

            // Big loop thru knot vector.
            while (b < m)
            {
                int i = b;
                while (b < m && Math.Abs(U[b] - U[b + 1]) < GSharkMath.Epsilon)
                {
                    b += 1;
                }

                int mul = b - i + 1;
                mh = mh + mul + t;
                double ub   = U[b];
                int    oldr = r;
                r = p - mul;

                // Insert knot U[b] r times.
                // Checks for integer arithmetic.
                int lbz = (oldr > 0) ? (int)Math.Floor((double)((2 + oldr) / 2)) : 1;
                int rbz = (r > 0) ? (int)Math.Floor((double)(ph - (r + 1) / 2)) : ph;

                if (r > 0)
                {
                    // Inserts knot to get Bezier segment.
                    double numer = ub - ua;
                    for (int k = p; k > mul; k--)
                    {
                        alphas[k - mul - 1] = (numer / (U[a + k] - ua));
                    }

                    for (int j = 1; j <= r; j++)
                    {
                        int save = r - j;
                        int s    = mul + j;
                        for (int k = p; k >= s; k--)
                        {
                            bpts[k] = Point4.Interpolate(bpts[k], bpts[k - 1], alphas[k - s]);
                        }

                        nextbpts[save] = bpts[p];
                    }
                }

                // End of insert knot.
                // Degree elevate Bezier.
                for (int j = lbz; j <= ph; j++)
                {
                    ebpts[j] = Point4.Zero;
                    int mpi = Math.Min(p, j);
                    for (int k = Math.Max(0, j - t); k <= mpi; k++)
                    {
                        ebpts[j] += bpts[k] * bezalfs[j, k];
                    }
                }

                if (oldr > 1)
                {
                    // Must remove knot u=U[a] oldr times.
                    int    first = kind - 2;
                    int    last  = kind;
                    double den   = ub - ua;
                    double bet   = (ub - Uh[kind - 1]) / den;
                    for (int tr = 1; tr < oldr; tr++)
                    {
                        // Knot removal loop.
                        int ii = first;
                        int jj = last;
                        int kj = jj - kind + 1;

                        while (jj - ii > tr)
                        {
                            // Loop and compute the new control points for one removal step.
                            if (ii < cind)
                            {
                                double alf = (ub - Uh[ii]) / (ua - Uh[ii]);
                                Qw.Add(Point4.Interpolate(Qw[ii], Qw[ii - 1], alf));
                            }

                            if (jj >= lbz)
                            {
                                if (jj - tr <= kind - ph + oldr)
                                {
                                    double gam = (ub - Uh[jj - tr]) / den;
                                    ebpts[kj] = Point4.Interpolate(ebpts[kj], ebpts[kj + 1], gam);
                                }
                                else
                                {
                                    ebpts[kj] = Point4.Interpolate(ebpts[kj], ebpts[kj + 1], bet);
                                }
                            }

                            ii += 1;
                            jj -= 1;
                            kj -= 1;
                        }

                        first -= 1;
                        last  += 1;
                    }
                }

                // End of removing knot, n = U[a].
                if (a != p)
                {
                    // Load the knot ua.
                    for (int j = 0; j < ph - oldr; j++)
                    {
                        Uh.Add(ua);
                    }
                }

                for (int j = lbz; j <= rbz; j++)
                {
                    // Load control points into Qw.
                    Qw.Add(ebpts[j]);
                }

                if (b < m)
                {
                    // Set up for the next pass thru loop.
                    for (int j = 0; j < r; j++)
                    {
                        bpts[j] = nextbpts[j];
                    }

                    for (int j = r; j <= p; j++)
                    {
                        bpts[j] = Pw[b - p + j];
                    }

                    a  = b;
                    b += 1;
                    ua = ub;
                }
                else
                {
                    // End knot.
                    for (int j = 0; j <= ph; j++)
                    {
                        Uh.Add(ub);
                    }
                }
            }

            return(new NurbsCurve(finalDegree, Uh, Qw));
        }