1

To learn a little about how NURBS curves work I decided to implement a NURBS class in C#. Following several different resources online I have created a basic class. Much of its functionality I have tested and verified the behaviours of. However, when evaluating points on the curves I find myself getting into situations where a singularity occurs within the NURBS basis function. I have implemented the basis function as per the algorithm below. enter image description here

My implementation of this function can be seen here in C#.

    // i is the knot index, filled by iterating over control points which are less than the number of knots
    // p is the degree
    // x is the position to evaluate at
    private double N (int i, int p, double x) {
        double ti0 = knotVector[i];     //u_{i}
        double ti1 = knotVector[i+1];   //u_{i+1}

        double tip = knotVector[i+p];   // u_{i+p}
        double tip1 = knotVector[i+p+1];// u_{i+p+1}

        if (p == 0) {
            if (ti0 <= x && x < ti1) {
                return 1;
            } else {
                return 0;
            }
        }

        double fi0 = (x - ti0) / (tip - ti0);
        double gi1 = (tip1 - x) / (tip1 - ti1);

        return fi0 * N(i, p-1, x) 
             + gi1 * N(i+1, p-1, x);
    }

Where this basis function is used in the property below to evaluate the coordinates of the point in 3d space.

public Vec3 this[double t] {
        get {
            double x = 0, y = 0, z = 0;
            double rationalWeight = 0;
            double[] ns = new double[this.ControlPoints.Length];

            for (int i = 0; i < this.ControlPoints.Length; i++) {
                double n = N(i, this.Degree, t);
                ns[i] = n;
                double temp = n * this.ControlPoints[i].Weight;
                rationalWeight += temp;
            }

            for (int i = 0; i < this.ControlPoints.Length; i++) {
                double temp = ns[i];
                x += this.ControlPoints[i].X * this.ControlPoints[i].Weight * temp / rationalWeight;
                y += this.ControlPoints[i].Y * this.ControlPoints[i].Weight * temp / rationalWeight;
                z += this.ControlPoints[i].Z * this.ControlPoints[i].Weight * temp / rationalWeight;
            }
            return new Vec3(x,y,z);
        }
    }

For instance, for this curve

  • degree 3
  • points [(-4, -4, 0), (-2, 4, 0), (2, -4, 0), (4, 4, 0)]
  • weights [1, 1, 1, 1]
  • knots [0,0,0,0,1,1,1,1]

I end up getting a cases, such as at x = 0.5, where (tip - ti0) and (tip1 - ti1) are 0 resulting in divide by 0 and NaN issues. Instead of getting a correct value (as verified from the curve link earlier), I am simply getting "Not a Number" from the function. From my reading so far I have found nothing to describing dealing singularities. This indicates to me that I am missing something in my implementation or have misunderstood how parts of it work.

Does anyone have an idea where I have gone wrong with this implementation of the basis function?

Colin
  • 39
  • 1

1 Answers1

0

The problem is that you didn't understand the mathematics behind the interpolation function. Let's say you have 2-dimensional points with coordinates x and y. Then N is a function that maps a parameter u to a point (x,y).

But what you did is you interpreted N as a function that maps x to y, which is not correct. u is not the x-coordinate, it's just a parameter.

Xaver
  • 1,035
  • 9
  • 17
  • So you are saying the N function maps the parameter, in this case, to a 3 dimensional point rather than that work being done in the indexer property? None of the reading I have seen so far mention that, they all just show the same algorithm as above. How would I modify this function to return a 3d point? The knot vector is just scalar values and so is the parametre 'x' leading to a function of all scalars somehow returning a vector? Any more assistance you could provide in helping me better understand this would be greatly appreciated. – Colin Jan 21 '21 at 16:37