# NURBS - Non Uniform Rational B-Splines.

My son learned about rational polynomials and rational functions recently and I volunteered
to talk about how they are used in the "real world" - in the form of NURBS. Here are some notes
I gathered in preparation. I gave the 20 minute talk on 20-DEC-2000 at Lincoln Sudbury RHS.

Rhino's Gallery. lots of cool images made with their NURBS modeller.

Breezy Intro for GEEKS #1 scanned from a world famous PEX book (Hardenbergh)

Breezy Intro for GEEKS #2 CAUTION, some formulas...

## Trivial Python NURBCurve evaluation code

In April 2003, I ported my NURBS playground to Python and embedded it in a tiny App I am using to try to do some art like the image on the right. I must warn you that the image on the right did get a bit of processing after the App snapped it.

The source for the application is twist1.py and it is a terrible mess of a UI, but, it has been useful to me. Perhaps you will find it useful. You will also need Point.py

### This evaluates a 3D NURBCurve

```
def C(t, order, points, weights, knots):
c = Point([0,0,0])
rational = 0
i = 0
while i < len(points):
b = B(i, order, t, knots)
p = points[i] * (b * weights[i])
c = c + p
rational = rational + b*weights[i]
i = i + 1
return c * (1.0/rational)

def B(i,k,t,knots):
ret = 0
if k>0:
n1 = (t-knots[i])*B(i,k-1,t,knots)
d1 = knots[i+k] - knots[i]
n2 = (knots[i+k+1] - t) * B(i+1,k-1,t,knots)
d2 = knots[i+k+1] - knots[i+1]
if d1 > 0.0001 or d1 < -0.0001:
a = n1 / d1
else:
a = 0
if d2 > 0.0001 or d2 < -0.0001:
b = n2 / d2
else:
b = 0
ret = a + b
#print "B i = %d, k = %d, ret = %g, a = %g, b = %g\n"%(i,k,ret,a,b)
else:
if knots[i] <= t and t <= knots[i+1]:
ret = 1
else:
ret = 0
return ret

```

## NURBS code for a circle Circle Example with OpenGL code included below and ancient PEX C code which takes three XYZ points and put a circle thru them. The example is taken from the book Mathematical Elements for Computer Graphics, by David F. Rogers and J Alan Adams.

Here is a little NURBCurve playground using that same example. It evaluates the curve in a very transparent, if very inefficient way. However, if you are trying to build up your understand of how NURBS work, this bit of source if for you.

There is also a good page based on a talk given to college students by Markus Altmann

```/*
* OpenGL code for drawing a circle with a NURBS curve.
*
* Method found on page 374, Mathematical Elements for Computer Graphics,
*   2nd ed. David F. Rogers and J Alan Adams. McGraw Hill, 1990.
* This is the triangle method, using 7 control points at the corners
*   and middles of an equilateral triangle, with knot vector
*   [ 0, 0, 0, 1, 1, 2, 2, 3, 3, 3 ] 10 knots (nCtrlPoints + order)
*   [ 1.0, 0.5, 1.0, 0.5, 1.0, 0.5, 1.0] weights, one per ctrlPoint.
* Control points are the corners and midpoints of an equilateral triangle
* 0,0 - 1,0 - 0,sqrt(3)/2 except it has been translated to -.5, -.5
* The first point is repeated as the 7th point.
*
* see picture at http://www.jch.com/NURBS/NURBCirc.gif
* and other notes at http://www.jch.com/NURBS/
* YON - Jan C. Hardenbergh
*/

GLUnurbsObj *pNurb = NULL;
int nCtrlPoints = 7;
GLfloat ctrlPoints;
GLfloat pointsWeights  = {
{0,-.5, 0, 1},
{.5,-.5, 0, 0.5},
{0.25, -0.0669873, 0, 1},
{0, 0.3880254, 0, 0.5},
{-.25,  -0.0669873, 0, 1},
{-.5,-.5, 0, 0.5},
{0,-.5, 0, 1}};

// Knot vector
int order = 3;
int nKnots = 10;
GLfloat Knots = {0,0,0,1,1,2,2,3,3,3};
#define kStride 4

// Called to draw scene
void RenderScene(void)
{
int i, j;

// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Render the NURB

// make sure we are setup
if (!pNurb)
{
// Setup the Nurbs object
pNurb = gluNewNurbsRenderer();
gluNurbsProperty(pNurb, GLU_SAMPLING_TOLERANCE, 5.0f);
//gluNurbsProperty(pNurb, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON);
//gluNurbsProperty(pNurb, GLU_DISPLAY_MODE, (GLfloat)GLU_FILL);

// make the NURBS control points from the points & weights
for(i = 0; i < nCtrlPoints; i++)
{
ctrlPoints[i] = pointsWeights[i];
for (j = 0; j < 3; j++)
{
ctrlPoints[i][j] = pointsWeights[i][j]*ctrlPoints[i];
}
}
}

glColor3f(1,0,1);

// Begin the NURB definition
gluBeginCurve(pNurb);

// Send the Non Uniform Rational BSpline
gluNurbsCurve(pNurb, nKnots, Knots, kStride,
&ctrlPoints, order, GL_MAP1_VERTEX_4);

gluEndCurve(pNurb);

// Draw the control points in red
glPointSize(3.0f);
glColor3f(1,0,0);
glBegin(GL_POINTS);
for(i = 0; i < nCtrlPoints; i++)
glVertex3fv(pointsWeights[i]);
glEnd();

// Flush drawing commands
glFlush();
}

```
3-DEC-2000 jch    -  updated 29-MAY-2003