NLib Introduction

 

Contents

NLib Changes

NLib source code has it's origins in code developed by Wayne Tiller and Les Piegel, based on their reference work "The Nurbs Book". NLib has an established reputation, and a long maintenance history so that it is a thoroughly tested product. The exclusive rights for maintenance, distribution and development were acquired by Solid Modeling Solutions. 

The code shows some signs of age. It looks very like FORTRAN with one routine per subroutine, and has a abbreviated naming convention and a use of conflicting reserved names that make for a steeper than necessary learning curve.

SMS has made a revised and updated version of NLib, without losing the logic or the rigor of the previous NLib. It is also compatible with the old NLib code, thru a series of #define replacement names. Our new logic for more advanced functionality will only be available in the  new NLib


1) Replaced old 8-character names of routines with more recognizable names

2) Eliminated conflicts from reserved names used elsewhere...such as POINT

3) Reorganized files into groups that reduce the number of files and place similar functions together in one file.

4) Speeded up compile and linking by reducing number of files.

5) Provided user transparency thru use of #define oldname newname

6) Allowed users to compile and link thru the new NLib files without having to make changes in their code.

7) Extended new functionality ( volumes ) within the new library, and future growth.

8) The routine names are now universally N_xxxxxxx, rather than the previous collection of  B_, M_, L_, S_ U_, etc.  A user of NLib can use any local name they like, but all NLib calls are made thru an N_ prefix.

9) We use ST_ within NLib routines for statics, which would not be referenced from user applications directly.

10) Also variable names are changed to make them unique to NLib, with the prefix of ' NL_'  so there should be no further conflicts with POINT, CURVE, SURFACE, REAL etc. 


Debugging:

You can compile and link using the new NLib without making any changes to your application code or compile/link settings.;
However, when you debug a program with the 'old' NLib names, when you trace into the new NLib code, you may find yourself in the  'new-name' world. 
Also the call stack references the new NLib names and not the old names.

NLib Implementation

We are only shipping the revised NLib (formerly called NLib2) as the current and future NLIb version. 

New customers will have no problems working with the new version. Existing customers who have legacy code which references the old NLib names will also be able to run, since they currently include 'nurbs.h'.   The new 'nurbs.h' contains a new 

#include NL_Defines2.h>   

This include has a complete list of 

#define oldnlibname    newnlibname

Customers of other SMS libraries (GSNLib, TSNLib, SMLib etc) can directly reference old NLib routines, and have the 'conversion' performed thru the 'defines'.    We have updated the SMS libraries use the new expanded NLib names directly.

One issue will be that when debugging legacy code, the call will appear from the old NLib name, but when entering the routine, it will display as the new NLib routine.  Also if you want to use a string search on uses of an old NLib name, you will have to use the 'NL_Defines2.h' include to give you the new name for that routine.

If the user would like to do a one-pass conversion of their legacy code, we have provided a Macro which can be used on a directory of files and make the name-change conversion in one pass. This MACRO was written in Python.

Eventually, we would like all users to run off the new names

NLib Rename Macro


Users should not have problems with this name change.

If you would like to update your legacy code with these same name changes, we have 
provided a macro NLibRename.exe (available only for Microsoft Win32 users).

Under Microsoft, click Start, Click All Programs, click Accessories, Click Command Prompt

Navigate to where you just saved NLibRename.exe

Then type: 

NLibRename.exe h


Do you get a list of options? Or do you get an error.

If you get the error, then hit the link below and download and run the installer. 
This will give you the dlls you are missing.

http://www.microsoft.com/downloads/details.aspx?familyid=9B2DA534-3E03-4391-8A4D-074B9F2BC1BF&displaylang=en

Then try NLibRename.exe h in the command prompt again.

If you have a 'good' response to the -h option, then try:

NLibRename.exe ./path to NLib/inc/NL_Defines2.h ./path to directory with source code to change


If you have problems, please email support@smlib.com and we will try to assist you.

Installation

NLib routines are delivered as a project under Microsoft Visual C++.

For other platforms, it is easy to extract the header (.h) and source code (.c) files. The 'Make'file is supplied only as an example, since makefiles can be platform-dependent. It should be easy to stream the source code and header file names into your own makefile.

 Under  VisualC++6.0, if you left mouse click on the NLib.dsw file, all of the routines will be compiled and the Nlib.lib and Nlib.dll files will be put into a directory ./Winlibs.  This Winlibs directory is at the same level as the current Nlib directory.  Winlibs is used by other SMS products ( GNSNlib, TSNLIb, SMLib, and HWLibs) for linking to make their respective executables.

Compiling

NLib routines are written in ANSI 'C' and have been compiled under most major operating systems, including those running on PCs, work stations and the Macs. We are not aware of any problem that would produce compilation errors. However, please do check your compile to make sure it complies with the ANSI standard. Some compilers might give a warning message regarding the definition and initialization of global constants given in globals.h.

Customers have written their own 'make' files for their version of GCC or UNIX. They are given here as a suggestion, without any assurance that they will work for your compiler:

cd ../src
find ../src -name '*.c' -print -exec ../unix/compile {} \;
cd ../unix
(This searches on .c instead of .cpp)
* The unix/compile file needs to be changed to:
gcc -std=c99
-DGW_NOT_BUILDING_MS_DLL
-DIW_NOT_BUILDING_MS_DLL
-I. -I../../NLib/inc -I../inc -g -c
$1

 

I am using
gcc (GCC) 3.3.1 (SuSE Linux)
for building the Linux shared library, and
i386-mingw32msvc-gcc (GCC) 3.2.3 (mingw special 20030504-1)
for building the Windows DLL (mingw32 is a cross-compiler toolkit
which runs on Linux but produces object files targeted for Windows --
this is very convenient since Linux is currently my main development
platform for GDL).
NLib (v9):
Here is the compile command-line I am using for Windows:
i386-mingw32msvc-gcc -I../inc -O2 -c -o ../objects/windows/[file].o
[file].c
and for Linux:
gcc -I../inc -O2 -c -o -fPIC -DGW_NOT_BUILDING_MS_DLL
../objects/linux/[file].o [file].c

Representation of Various Entities

Index is used for array subscripts.

  • Index starts at zero (0).
  • An array index of '4' means that there are '5' items in the array.
  • This is standard 'C' practice, but is also the cause of many errors by users.

Point: is always a 3-D entity (x,y,z)

Control Points are always weighted.  The following cases are distinguished
  • 2-D non-rational (x, y, NL_NOZ, NL_NOW)
  • 2-D rational (wx, wy, NL_NOZ, w)
  • 3-D non-rational (x, y, z, NL_NOW)
  • 3-D rational (wx, wy, wz, w)
where NL_NOZ and NL_NOW are predefined identifiers telling  NLib that no z and/or no w component(s) are to be considered.

Knot Vector  is always "clamped'', that is:

  • U = {a(0),...,a(p), u(p+1),...,u(m-p-1),b(m-p),...,b(m)}
where p is the degree of the curve. There are routines to clamp or unclamp knot vectors if the need so arises.

Curve is always in a Bezier-like form, i.e. with end point  interpolation. Curves are mostly created by the system. However, they can be input from a file. The form of the file is explained by the following degree-three curve example:

5     <---    Highest index of control points (n)
3     <---    Degree (p)
1     <---    Rational (1) or non-rational (0) flag
2     <---    Dimension (2 or 3)
0.100000 0.300000 1.000000    <---    Pw(0)
0.700000 0.600000 2.000000    <---    Pw(1)
0.350000 0.600000 1.000000    <---    Pw(2)
0.650000 0.600000 1.000000    <---    Pw(3)
0.975000 0.450000 1.500000    <---    Pw(4)
0.900000 0.300000 1.000000    <---    Pw(5)
0.000000     <---    u(0)
0.000000     <---    u(1)
0.000000     <---    u(2)
0.000000     <---    u(3)
0.300000     <---    u(4)
0.700000     <---    u(5)
1.000000     <---    u(6)
1.000000     <---    u(7)
1.000000     <---    u(8)
1.000000     <---    u(9)
The relationship m=n+p+1 must always hold, where m is the highest index of knots (in the above example have 9 = 5 + 3 + 1).

Surface is always in a Bezier-like form, i.e. with corner point  interpolation. As in the case of curves, surfaces are mostly created by the system. However, they too can be input from a file. The form of the file is explained by the following degree 3 x 2 surface example:

 4 3    <---    Highest indexes in u- and v-directions (n, m)
 3 2    <---    Degrees in u- and v-directions (p, q)
 1      <---    Rational (1) or non-rational (0) flag
 
 8.000000 -8.000000  4.000000 1.000000    <---  Pw(0,0)
 4.000000 -8.000000  0.000000 1.000000    <---  Pw(0,1)
-4.000000 -8.000000  0.000000 1.000000    <---  Pw(0,2)
-8.000000 -8.000000  6.000000 1.000000    <---  Pw(0,3)
 
 8.000000 -3.000000  0.000000 1.000000    <---  Pw(1,0)
 8.000000 -6.000000  0.000000 2.000000    <---  Pw(1,1)
-4.000000 -3.000000  0.000000 1.000000    <---  Pw(1,2)
-8.000000 -3.000000  2.000000 1.000000    <---  Pw(1,3)
 
 8.000000  0.000000  0.000000 1.000000    <---  Pw(2,0)
 6.000000  0.000000  3.000000 1.500000    <---  Pw(2,1)
-4.000000  0.000000  2.000000 1.000000    <---  Pw(2,2)
-8.000000  0.000000  4.000000 1.000000    <---  Pw(2,3)
 
 8.000000  3.000000  2.000000 1.000000    <---  Pw(3,0)
 4.000000  3.000000  0.000000 1.000000    <---  Pw(3,1)
-8.000000  6.000000  0.000000 2.000000    <---  Pw(3,2)
-8.000000  3.000000  0.000000 1.000000    <---  Pw(3,3)
 
 8.000000  8.000000 -2.000000 1.000000    <---  Pw(4,0)
 4.000000  8.000000  0.000000 1.000000    <---  Pw(4,1)
-4.000000  8.000000 -2.000000 1.000000    <---  Pw(4,2)
-8.000000  8.000000  6.000000 1.000000    <---  Pw(4,3)
 
0.000000     <---    u(0)
0.000000     <---    u(1)
0.000000     <---    u(2)
0.000000     <---    u(3)
0.500000     <---    u(4)
1.000000     <---    u(5)
1.000000     <---    u(6)
1.000000     <---    u(7)
1.000000     <---    u(8)
 
0.000000     <---    v(0)
0.000000     <---    v(1)
0.000000     <---    v(2)
0.500000     <---    v(3)
1.000000     <---    v(4)
1.000000     <---    v(5)
1.000000     <---    v(6)
 

The relationships r=n+p+1 and s=m+q+1 must always hold, where r and s are the highest indexes of knots in the u- and v-directions,  respectively (in the above example we have 8=4+3+1 and 6=3+2+1).

Program Design

We explain the major ingredients of a typical NLib application program using a simple example below. The program reads in a NURBS curve, elevates its degree by one in three different ways, and writes the last result out to a file. The names of the input and output files are command line arguments.

#include "nurbs.h"
#include "globals.h"
main( int argc, char *argv[] )
{
  NL_FLAG        error;
  NL_INDEX       n, m, s;
  NL_DEGREE      p;
  NL_CURVE       curP, curQ, curR;
  NL_KNOTVECTOR  *knt
  NL_STACKS      S;
  /* Start NURBS */
  N_InitNurbs(&S);
  /* Input curve */
  N_CrvInitArrays(&curP);
  error = N_CrvReadFromFile(&curP,argv[1],NL_YES,&S);
  if ( error EQ NL_YES )  NL_PRINT_ERROR;
  /***************************/
  /* Elevate degree call 1 */
  /***************************/
  N_CrvInitArrays(&curQ);
  error = N_CrvElevateDegree(&curP,1,&curQ,&S,&S);
  if ( error EQ NL_YES )  NL_PRINT_ERROR;
  /***************************/
  /* Elevate degree call 2 */
  /***************************/
  /* Get knot vector, highest indexes and degree */
  N_CrvGetKnotVector(&curP,&knt);
  N_CrvGetArraySizes(&curP,&n,&m);
  N_CrvGetDegree(&curP,&p);
  /* Compute highest indexes of degree elevated curve */
  N_BasisGetSpanCount(knt,p,&s);
  n = n+s;
  p = p+1;
  m = m+s+1;
  /* Allocate memory for new curve */
  error = N_CrvAllocArrays(&curR,n,p,m,&S);
  if ( error EQ NL_YES )  NL_PRINT_ERROR;
  /* Now degree elevate */
  error = N_CrvElevateDegree(&curP,1,&curR,&S,&S);
  if ( error EQ NL_YES )  NL_PRINT_ERROR;
  /***************************/
  /* Elevate degree call 3 */
  /***************************/
  error = N_CrvElevateDegree(&curP,1,&curP,&S,&S);
  if ( error EQ NL_YES )  NL_PRINT_ERROR;
  /* Output last curve */
  error = N_CrvWriteToFile(&curP,argv[2]);
  if ( error EQ NL_YES )  NL_PRINT_ERROR;
  /* End NURBS */
  N_EndNurbs(&S);
}

There are several important points:

  • Each routine that calls NLib functions must include the file  nurbs.h. This header file contains all function prototypes, and includes the headers nurbsdef.h, geometry.h and datastr.h.
  • The top level application routine must also include globals.h. This file contains global parameters and constants, including important tolerances (see below).
  • NLib functions work on predefined data types, e.g. NL_FLAG, NL_INDEX, NL_DEGREE, NL_KNOTVECTOR, NL_CURVE and NL_STACKS. These data types act like any other standard data type such as int or double. That is, when one writes NL_CURVE curP, the system allocates memory for a curve object and tags this memory with the name curP.
  • NLib routines start and end with two special functions N_InitNurbs and N_EndNurbs. The first one initializes memory stacks to NULL, and the second one traverses these stacks, deallocates all dynamically allocated memory, and kills the stacks.
  • The calling mechanism of each NLib function is explained in detail in its header.

As an example, here is the explanation of how to call N_CrvElevateDegree (as extracted from its header):

A typical calling example is:

        NL_CURVE   curP, curQ;
        NL_INDEX   t;
        NL_STACKS  SP, SQ;
        ...
        (define curP, get t);
        ...
        N_CrvInitArrays(&curQ);
        N_CrvElevateDegree(&curP,t,&curQ,&SP,&SQ);
        N_CrvElevateDegree(&curP,t,&curP,&SP,&SP);
        ...
 
The header explains
  • how to declare variables;
  • how to pass them to the routine (by value or by reference).
  • how to manage memory (which stack is used for input and output

We shall now walk through the sample program

Various parameters and objects are defined. Note that three curve objects are defined, however, only a knot vector pointer is needed.

The NURBS program is initialized by N_InitNurbs

curP is initialized to NULL telling the N_CrvReadFromFile routine to allocate memory, copy the curve data into curP, and place memory pointers on to the stacks .
 
Call 1 curQ is initialized to NULL telling the degree elevation routine to: 
  •  find out how much memory is needed to store the output curve, and to allocate this memory;
  •  degree elevate curP and to place the result in curQ; and
  •  place memory pointers on to the stacks S.
          This is the most convenient way of calling NLib routines that return a new curve or surface.
 
Call 2 the new degree and the highest indexes of control points and knots are computed first. Then memory is allocated by the N_CrvAllocArrays routine. When calling the degree elevation routine with curR, the routine does the following:            
  • Sees that curR is not NULL and checks if sufficient memory is passed in using curR's memory stacks (the same as curP's in this example). If yes, it continues. If not, it sets t error flag, and returns control to the calling routine.
  • Degree elevates curP and places the output curve  in curR,
 Call 3 when calling the degree elevation routine with the same curve pointer, the routine sees that degree elevation  is to be done in-place, and does the following:
  • kills curP.
  • allocates new memory for curP; and
  • places the degree elevated curve in the new curP.
curP is saved on a file by the N_CrvWriteToFile routine.
 
The program is ended by N_EndNurbs that deallocates all dynamically allocated memory. 
 
The three calls show that there is a lot of flexibility in how to create new geometric entities. For simple operations calls 1 or 3 are recommended. If degree elevation is to be done repeatedly, call 2 is recommended, i.e. allocate enough memory, only once, for all types of degree elevations, and pass this memory to the routine.

Array Arguments

In general, it is safe to say that we never have arrays of points ( ie point data laid out contiguously). What we have is an array of pointers to points.....so the points can be, for example, along either the row or column of an array. We gather the address of each successive point we are interested in and add the address into an array of pointers......

     NL_POINT **Pnt

We do not have to rearrange the input if we switch from row to column. ...just select the addresses differently.

Similarly with other objects, such as the curves in N_CrvDecomposeBez.

The argument " ***CurQ " means " the address of an array of pointers to Curves".

You have:

     NL_CURVE *cur as a pointer to a curve

     NL_CURVE **curQ as an array of curve pointers

          ( do not confuse this with a two dimensional array )

You call N_CrvDecomposeBez with (.......&curQ.....)

But N_CrvDecomposeBez receives it as (.........NL_CURVE ***curQ........) and internally builds a set list of curve pointers to newly allocated curves

     NL_CURVE **curA; ....

     build curA[i]; ......

     *curQ= curA;

" take the address of the new curve list curA and put it into the location where curQ is pointing to (if there was no *curQ...but only curQ it would just locally change the address of curQ and not update the one that was sent).

After returning, the calling routine now has the address of the list of curve pointers ( NL_CURVE **CurQ)..

Dynamic Memory Allocation

Memory in NLib routines is allocated by special purpose routines that can be found in the space subdirectory and have the prefix S_. These routines require a memory stack to save pointers of allocated memory. The user can work with an entire hierarchy of stacks, each one of them is local to one or global to many routines. These stacks can control when and where memory is needed. Each NURBS routine has its local stack which is killed, along with all memory residing on it, upon leaving the routine. In addition to this local stack, the routine can take, as arguments, a number of global stacks that can hold memory needed when the routine in no longer active. As an example, let us look at the structure of the degree elevation routine used above.
NL_FLAG  N_CrvElevateDegree( NL_CURVE *curP, NL_INDEX t, NL_CURVE *curQ,
                NL_STACKS *SP, NL_STACKS *SQ )
{
  NL_FLAG  error = NL_NO;
  ...
  NL_STACKS  SL;
  N_InitNurbs(&SL);
  ...
  alfs = N_AllocReal1dArray(p,&SL);
  if ( alfs EQ NULL )  NL_QUIT;
  ...
  N_EndNurbs(&SL);
}
N_CrvElevateDegree is given two global stacks, SP and SQ; one for curP and one for curQ. In addition to this, it has its local stack SL. If the degree is elevated in-place, the new curve curP is placed on to SP. Otherwise, the new curve curQ is placed on to SQ. Any local memory, like alfs, is stored on the local stack SL, and is released upon leaving the routine.

Tolerances and Constants

NLib has two types of tolerances public and private. Public tolerances are declared and initialized in globals.h. Some examples follow:
  •  NL_MTOL models space tolerance, i.e. if two points are closer than NL_MTOL, they are considered the same. The current setting is1.0e-7.
  • NL_PTOL parameter space tolerance, i.e. if two parameters are closer than NL_PTOL, they are considered the same. The current setting is 1.0e-12.
  • NL_LTOL line tolerance, i.e. if the magnitude of the cross product of two lines' unit direction vectors is less then NL_LTOL, the lines are considered parallel. The current setting is 1.0e-12.
  • NL_LUDT LU-decomposition tolerance. It will not allow the computation of LU-decomposed matrices (with or without pivoting) with huge numbers even if the divisions can be performed within the available range of the floating point processor. The current setting  is 1.0e-9.
Private tolerances are declared in individual routines. These tolerances are used to perform numerical computations within the scope of the individual routine. Even though they are NL_PRIVATE, they are never hard coded. They are defined on top of the routine, and adjusted in the body based on the length of the knot vector, the bounding box of the curve/surface, etc. Their initial settings are based on extensive experiments, and can be altered easily as the user sees fit.
 
There are a number of constants and predefined entities NLib relies on. All of them are defined in globals.h. A few examples follow:
  • NL_WMIN and NL_WMAX minimum and maximum allowable weights. Current settings 1.0e-2 and 10, respectively.
  • NL_DMAX highest degree. Currently 28. Warning NL_DMAX  cannot be modified without considering the definition of NL_INDEX and NL_INTEGER data types. The binomial coefficients are  represented for efficiency reason as integers. The current definition  of NL_INDEX and NL_INTEGER is long, which may have different maximum values on different systems. The ANSI standard requires long to be at least 2,147,483,647.
  • NL_ITLIM iteration limit. Currently 50 (if iterations, such as Newton, do not converge within 50 steps, they probably never will).

 

Floating Point Operations

Floating point operations are performed in double precision. There are two types of error checks:

  • Certain numbers are checked against predefined tolerances before any crucial operation, such as division, occurs. For example, if a number is to be divided by the distance between two points, then even if the division could be done, it is not done if the distance is less than the  model space tolerance.
  •  When no specific tolerances are involved, operation checks are performed by the N_FloatOpIsBad routine. It's calling mechanism is:

       NL_REAL  x, y;
        ...
        if ( N_FloatOpIsBad(x,y,NL_ADDITION) )  NL_ERROR(NL_NUM_ERR);
        if ( N_FloatOpIsBad(x,y,NL_SUBTRACTION) )  NL_ERROR(NL_NUM_ERR);
        if ( N_FloatOpIsBad(x,y,MULTIPLICATION) )  NL_ERROR(NL_NUM_ERR);
        if ( N_FloatOpIsBad(x,y,NL_DIVISION) )  NL_ERROR(NL_NUM_ERR);

        ...

Utilities

NLib has an extensive set of utilities to perform such tasks as making objects, input/output, converting objects, etc. One of the most important tasks performed by these functions is to hide the definition of various objects while providing access to their components. For example, to get the highest indexes of control points and knots of a curve object, one could write:
NL_INDEX   n, m;
NL_CURVE   *cur;
...
n = cur->pol->n;
m = cur->knt->m;

This requires knowledge of the NL_CURVE object. It also requires that the entire library be searched and modified if any change is made to its definition. In order to avoid this, NLib has an extensive set of utility routines to create objects from their individual components, and to break them into the many constituents. In the above example, one should write:

INDEX   n, m;
NL_CURVE   *cur;
...
N_CrvGetArraySizes(cur,&n,&m);

Each category of routines where objects are dealt with, e.g. NURBS, geometry and mathematics, has its own constructors and destructors. We strongly recommend that the application programmer use these routines. They have the following advantages:

  •   they are easier to understand;
  •   they are less prone to errors (the compiler catches the error if the are called incorrectly); and
  •   they allow changes to be made to the definitions of the objects.

Error Checking

NLib has a set of routines to check errors. They are in the error directory and have the prefix E_. We strongly recommend that these routines be used to make sure that curves and surfaces are correct before entering NURBS routines. The general philosophy  is: Whenever an object is passed into a function, it is assumed that its definition is correct.

Naming Conficts

NLib include files contain uses of #define such as #define NL_POINT, #define EXIT, #define NL_BOOLEAN which conflict with #defines that are found in windows.h and other Microsoft libraries.  The easiest solution to this is to use one set of 'include' files for compiling NLib routines (as delivered within SMLib). Then, make a copy of those  'include' files and comment out the conflicting 'defines' and then use this new set of include files with your application.

Another solution is with the use of 'namespace'.  This effectively puts 'NLib::' into all NLib routine and 'define' names, and makes any reference unique to NLib.  That means that any call to routine 'N_xxxxxx()"  now becomes 'NLib::N_xxxxxx()'.  This is an approach that new NLib users can adopt. However, other SMS library products and Harmonyware products do not use the namespace directive.

To implement namespace:  

  • Edit NLib/inc/Nurbs.h
  • At the beginning of the header,   add
    #ifdef __cplusplus
    namespace NLib {
    #endif
  • and at the end of the file,  add:
#ifdef __cplusplus
}
#endif

Installation and Usage Tips

The directory \examples\ contains a few example programs.

The curve/surface evaluators use some fixed- length arrays declared with dimensions NL_MAXDEG and NL_MAXDER. The current settings (in nurbsdef.h) for these evaluators are NL_MAXDEG=28 (maximum degree) and NL_MAXDER=5 (maximum derivative order). If you need to change these, you should do so before compiling NLib (you must also change NL_DMAX in globals.h to be the same as NL_MAXDEG).

"The NURBS Book" (Springer-Verlag, ISBN 3-540-61545-8), by Les Piegl and Wayne Tiller is excellent documentation for NLib. The first 12 chapters describe the underlying mathematics and algorithms, and Chapter 13 describes the system architecture (data structures, memory management, error handling, utilities, example programs, etc). We suggest you buy it.

A few tips for using NLib (see "The NURBS Book" for more detail)

1. NLib requires NURBS curves/surfaces to have "clamped", or  "nonperiodic" knot vectors; i.e. end multiplicities equal to degree plus 1. Furthermore, internal knots may not have multiplicity  greater than degree.

2. There are functions to "clamp" curves/surfaces (specifically:  N_Iges126Crv and N_Iges128Srf), and knot removal can be used where internal knots have multiplicities greater than degree.

3. When importing curves/surfaces from other systems, it is advisable to use the functions N_Iges126Crv and N_Iges128Srf. These check if the NURBs  definitions are compatible with NLib.

4. A main program must include the files  nurbs.h and globals.h (see example programs).

5. Any program should start with a call to N_InitNurbs and end with a call to N_EndNurbs (see example programs).

6. Generally, if an array is passed into a function, and if an integer> (say n) is also passed, then n will usually indicate the highestvalid index of the array, not the number of elements in the array.  Since array indices start at 0, n+1 is the actual number of array elements. This may seem unnatural for some users, but it corresponds  to the notation and algorithm descriptions of "The NURBS Book"

7. All angles are to be expressed in degrees, not radians.

References

The NLib products are based on solid research in NURBS technology. The publications below by Les Piegl and/or Wayne Tiller are examples of key papers providing a scientific basis for major NLib routines.

  • Rational B-splines for curve and surface representation, IEEE Computer Graphics and Applications, Vol. 3, No. 6, 1983, pp 61-69.
  • The NURBS Book, Second Revised Edition, Springer-Verlag, 1997.
  • Curve and surface constructions using rational B-splines, Computer-Aided Design, Vol. 19, No. 9, 1987, 485-498.
  • A menagerie of rational B-spline circles, IEEE Computer Graphics and Applications, Vol. 9, September, 1989, pp 48-56.
  • Modifying the shape of rational B-splines. Part 1: curves, Computer-Aided Design, Vol. 21, No. 8, 1989, pp 509-518.
  • Modifying the shape of rational B-splines. Part 2: surfaces, Computer-Aided Design, Vol. 21, No. 9, 1989, pp 538-546.
  • Data reduction using cubic rational B-spline, IEEE Computer Graphics and Applications, May, pp 60-68, 1992.
  • Knot-removal algorithms for NURBS curves and surfaces, Computer-Aided Design, Vol. 24, No. 8, 1992, pp 445-453.
  • Delaunay triangulation using a uniform grid, IEEE Computer Graphics and Applications, May, 1993, pp 36-47.
  • Software engineering approach to degree elevation of B-spline curves, Computer-Aided Design, Vol. 26, No. 1, pp 17-28 , 1994.
  • Algorithm for degree reduction of B-spline curves, Computer-Aided Design, Vol. 27, No. 2, pp 101-110, 1995.
  • Algorithm for approximate NURBS skinning, Computer-Aided Design, Vol. 28, No. 9, pp 699-706, 1996.
  • Symbolic operators for NURBS, Computer-Aided Design, Vol. 29, No. 5, pp 361-368, 1997
  • Algorithm for computing the product of two B-splines, in A. Le Mehaute, C. Rabut and L. L. Schumaker (eds.) Curves and surfaces with applications in CAGD, Vanderbilt University Press, Nashville, TN, 1997, pp 337-344.
  • Geometry-based triangulation of trimmed NURBS surfaces, Computer-Aided Design, Vol. 30, No 1, pp 11-18, 1998.
  • Computing the derivatives of NURBS with respect to a knot, Computer Aided Geometric Design, Vol. 15, No. 9, pp 925-934, 1998.
  • Approximation of offsets of NURBS curves and surfaces, Computer-Aided Design, Vol. 31, No. 2, pp 147-156, 1999.
  • Cross-sectional design with boundary constraints, Engineering with Computers, Vol. 15, 1999, pp 171-180.
  • Filling n-sided regions with NURBS patches, The Visual Computer, Vol. 15, No. 2, pp 77-89, 1999.
  • Reducing control points in surface interpolation, IEEE Computer Graphics and Applications, Vol. 20, No. 5, 2000, pp 70-74.
  • Surface approximation to scanned data, The Visual Computer, Vol. 16, No. 7, 2000, pp 386-395.
  • Curve interpolation with arbitrary end derivatives, Engineering with computers, Vol. 16, 2000, pp 73-79.
  • Least-squares NURBS curve approximation with arbitrary end derivatives, Engineering with computers, Vol. 16, 2000, pp 109-116.
  • Parametrization for surface fitting in reverse engineering, Computer-Aided Design, Vol. 33, No. 8, 2001, pp 593-603.

Legal Stuff

All of the software and documentation received with this release is copyrighted by Solid Modeling Solutions, Inc. You may not distribute source code or documentation for this software outside of the company and the site which owns the license. The standard license agreement allows you to freely distribute object code in any application which does not contain a programmatic interface. All software and documentation is considered proprietary information and the intellectual property of Solid Modeling Solutions, Inc. This document contains trade secret information which is deemed proprietary.

Copyright 1998-2010 Solid Modeling Solutions All rights reserved.
Information in this document is subject to change without notice.