opennurbs_evaluate_nurbs.cpp
Go to the documentation of this file.
00001 /* $NoKeywords: $ */
00002 /*
00003 //
00004 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
00005 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
00006 // McNeel & Associates.
00007 //
00008 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
00009 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
00010 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
00011 //                              
00012 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
00013 //
00015 */
00016 
00017 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
00018 
00019 double ON_EvaluateBernsteinBasis(int degree, int i, double t)
00020 /*****************************************************************************
00021 Evaluate Bernstein basis polynomial
00022 
00023 INPUT:
00024   degree
00025     If degree < 0, then 0.0 is returned.
00026   i
00027     If i < 0 or i > degree, then 0.0 is returned.
00028   t 
00029     The formula for the Bernstein polynomial is valid
00030     for all values of t.
00031 OUTPUT:
00032   TL_EvBernsteinBasis()
00033 
00034          degree!
00035      ---------------- * (1-t)^(degree-i) * t^i, if 0 <= i <= degree
00036      (degree-i)! * i!
00037 
00038      0, otherwise.
00039 
00040   (In this function, 0^0 is treated as 1.)
00041 COMMENTS:
00042   Below, B(d,i,t) is used to denote the i-th Bernstein basis polynomial of 
00043   degree d; i.e., B(d,i,t) = TL_EvBernsteinBasis(d,i,t).
00044 
00045   When degree <= 4, TL_EvBernsteinBasis() computes the value directly. 
00046   When 4 < degree < 9, the value is computed recursively using the formula
00047 
00048     B(d,i,t) = t*B(d-1,i-1,t) + (1-t)*B(d-1,i,t).
00049 
00050   For 9 <= degree, the value is computed using the formula
00051 
00052     B(d,i,t) = TL_EvBinomial(degree-i,i)
00053                *((degree==i) ? 1.0 : pow(1.0-t,(double)(degree-i)))
00054                *((i)         ? pow(t,(double)i) : 1.0);
00055 
00056   The value of a degree d Bezier at t with control vertices
00057   {P_0, ..., P_d} is equal to B(d,0,t)*P_0 + ... + B(d,d,t)*P_d.   
00058   Numerically, this formula is inefficient and unstable.  The
00059   de Casteljau algorithm used in TL_EvdeCasteljau() is faster
00060   and more stable.
00061 
00062 EXAMPLE:
00063   // Use TL_EvBernsteinBasis() to evaluate a 3 dimensional
00064   // non-rational cubic Bezier at 1/4.
00065 
00066   double cv[4][3], t, B[4], answer[3];
00067   int    i, j, degree;
00068 
00069   degree = 3;
00070   t = 0.25;
00071   answer[0] = answer[1] = answer[2] = 0.0;
00072   for (i = 0; i <= degree; i++)
00073     cv[i] = something;
00074   for (i = 0; i <=degree; i++) {
00075     B[i] = TL_EvBernsteinBasis(degree,i,t);
00076     for (j = 0; j < 3; j++)
00077       answer[j] += B[i]*cv[i][j];
00078   }
00079 
00080 REFERENCE:
00081   BOHM-01, Page 7.
00082 RELATED FUNCTIONS:
00083   TL_EvNurbBasis
00084   TL_EvdeCasteljau()
00085   TL_EvBezier()
00086   TL_EvHorner()
00087 *****************************************************************************/
00088 {
00089   double
00090     s;
00091   if (degree < 0 || i < 0 || i > degree)
00092     return 0.0;
00093   switch(degree) {
00094   case 0:                       /* degree 0 */
00095     return 1.0;
00096   case 1:                       /* degree 1 */
00097     return ((i) ? t : 1.0-t);
00098   case 2:                       /* degree 2 */
00099     switch(i) {
00100     case 0:
00101       t = 1.0-t;
00102       return t*t;
00103     case 1:
00104       return 2.0*t*(1.0-t);
00105     default:                    /* i == 2 */
00106       return t*t;
00107     }
00108   case 3:                       /* degree 3 */
00109     switch(i) {
00110     case 0:
00111       t = 1.0 - t;
00112       return t*t*t;
00113     case 1:
00114       s = 1.0-t;
00115       return 3.0*s*s*t;
00116     case 2:
00117       return 3.0*(1.0-t)*t*t;
00118     default:                    /* i == 3 */
00119       return t*t*t;
00120     }
00121   case 4:                       /* degree 4 */
00122     switch(i) {
00123     case 0:
00124       t = 1.0-t;
00125       t = t*t;
00126       return t*t;
00127     case 1:                     /* 4*(1-t)^3*t */
00128       s = 1.0-t;
00129       return 4.0*s*s*s*t;
00130     case 2:                     /* 6*(1-t)^2*t */
00131       s = 1.0-t;
00132       return 6.0*s*s*t*t;
00133     case 3:                     /* 4*(1-t)*t^3 */
00134       return 4.0*(1.0-t)*t*t*t;
00135     default:                    /* t^4 (i == 4) */
00136       t = t*t;
00137       return t*t;
00138     }
00139   default:                      /* degree >= 5 */
00140     /* The "9" was determined to produce the fastest code when
00141      * tested on a SUN Sparc (SUNOS 4.3, gcc -O)
00142      */
00143     if (degree < 9)
00144       return (t*ON_EvaluateBernsteinBasis(degree-1,i-1,t)
00145               + (1-t)*ON_EvaluateBernsteinBasis(degree-1,i,t));
00146     else
00147       return ON_BinomialCoefficient(degree-i,i)*((degree==i)?1.0:pow(1.0-t,(double)(degree-i)))*((i)?pow(t,(double)i):1.0);
00148   }
00149 }
00150 
00151 
00152 void ON_EvaluatedeCasteljau(int dim, int order, int side, int cv_stride, double* cv, double t)
00153 /*****************************************************************************
00154 Evaluate a Bezier using the de Casteljau algorithm
00155 
00156 INPUT:
00157   dim    ( >= 1)
00158   order  ( >= 2)
00159   side   <= 0  return left side of bezier in cv array
00160          >  0  return right side of bezier in cv array
00161   cv     array of order*cv_stride doubles that specify the Bezier's control
00162          vertices.
00163   cv_stride ( >= dim) number of doubles between cv's (typically a multiple of dim).
00164   t      If side <= 0, then t must be > 0.0.
00165          If side >  0, then t must be < 1.0.
00166 OUTPUT:
00167   cv
00168          If side <= 0, the input cv's are replaced with the cv's for
00169          the bezier trimmed/extended to [0,t].  In particular,
00170          {cv[(order-1)*cv_stride], ..., cv[order*cv_stride - 1]} is the value of 
00171          the Bezier at t.
00172          If side > 0, the input cv's are replaced with the cv's for
00173          the Bezier trimmed/extended to [t,1].  In particular,
00174          {cv[0], ..., cv[dim-1]} is the value of the Bezier at t.
00175 COMMENTS:
00176   Set C[i,j] = {cv[j*cv_stride], ..., cv[(j+1)*cv_stride-1]}, if i = 0
00177                 (1-t)*C[i-1,j-1] + t*C[i-1,j], if 0 < i <= d = degree
00178 
00179   The collection of C[i,j]'s is typically drawn in a triangular array:
00180 
00181   C[0,0]
00182            C[1,1]
00183   C[0,1]              C[2,2]
00184            C[1,2]             ...
00185   C[0,2]
00186        
00187   ...                                  C[d,d]
00188                               ...
00189   C[0,d-1]            C[2,d]
00190            C[1,d]
00191   C[0,d]
00192       
00193   The value of the Bezier at t is equal to C[d,d].
00194       
00195   When side < 0, the input cv's are replaced with
00196           C[0,0], C[1,2], ..., C[d,d].  
00197   If the output cv's are used as control vertices for a Bezier, 
00198   then output_bezier(s) = input_bezier(t*s).
00199       
00200   When side >= 0, the input cv's are replace with
00201           C[d,d], C[d-1,d], ..., C[0,d].
00202   If the output cv's are used as control vertices for a Bezier, 
00203   then output_bezier(s) = input_bezier((1-s)*t + s).
00204 
00205   If a Bezier is going to be evaluated more than a few times, it is
00206   faster to convert the Bezier to power basis and evaluate using
00207   TL_EvHorner.  However, Horner's algorithm is not a stable as
00208   de Casteljau's.
00209 EXAMPLE:
00210   // Use TL_EvdeCasteljau() to trim/extend a Bezier
00211   // to the interval [t0,t1], where t0 < t1
00212 
00213   double cv[order][dim], t0, t1
00214 
00215   cv = whatever;
00216   if (1.0 - t0 > t1) {
00217     // first trim at t0, then trim at t1
00218     if (t0 != 0.0) TL_EvdeCasteljau(dim,order, 1,cv,dim,t0); 
00219     t1 = (t1-t0)/(1.0 - t0); // adjust t1 to new domain
00220     if (t1 != 1.0) TL_EvdeCasteljau(dim,order,-1,cv,dim,t1);
00221   }
00222   else {
00223     // first trim at t1, then trim at t0
00224     if (t1 != 1.0) TL_EvdeCasteljau(dim,order,-1,cv,dim,t1);
00225     t0 /= t1; // adjust t0 to new domain
00226     if (t0 != 0.0) TL_EvdeCasteljau(dim,order, 1,cv,dim,t0);
00227   }
00228 REFERENCE:
00229   BOHM-01, Page 8.
00230 RELATED FUNCTIONS:
00231   TL_EvBernsteinBasis
00232   TL_EvBezier
00233   TL_EvdeBoor
00234   TL_EvHorner
00235   TL_ConvertBezierToPolynomial
00236 *****************************************************************************/
00237 {
00238   double
00239     s, *P0, *P1;
00240   int
00241     j, d, off_minus_dim;
00242 
00243   if (t == 0.0 || t == 1.0)
00244     return;
00245 
00246   s = 1.0 - t;
00247 
00248   /* it's ugly and it's fast */
00249   if (cv_stride > dim) {
00250     off_minus_dim = cv_stride - dim;
00251     if (side > 0) {
00252       /* output cv's = bezier trimmed to [t,1] */
00253       while (--order) {
00254         P0 = cv;                /* first cv */
00255         P1 = P0 + cv_stride;       /* next cv */
00256         j = order;
00257         while (j--) {
00258           d = dim;
00259           while (d--) {*P0 = (*P0 * s) + (*P1 * t); P0++; P1++;}
00260           P0 += off_minus_dim; P1 += off_minus_dim;}}
00261     }
00262     else {
00263       /* side <= 0, so output cv's = bezier trimmed to [0,t] */
00264       cv += order*dim;          /* now cv = last control vertex */
00265       while (--order) {
00266         P1 = cv;                /* last cv */
00267         P0 = P1 - cv_stride;       /* next to last cv */
00268         j = order;
00269         while (j--) {
00270           d = dim;
00271           while (d--) {P0--; P1--; *P1 = (*P0 * s) + (*P1 * t);}
00272           P0 -= off_minus_dim; P1 -= off_minus_dim;}}
00273     }
00274   }
00275   else {
00276     if (side > 0) {
00277       /* output cv's = bezier trimmed to [t,1] */
00278       while (--order) {
00279         P0 = cv;                /* first cv */
00280         P1 = P0 + dim;          /* next cv */
00281         j = order;
00282         while (j--) {
00283           d = dim;
00284           while (d--) {*P0 = (*P0 * s) + (*P1 * t); P0++; P1++;}}
00285       }
00286     }
00287     else {
00288       /* side <= 0, so output cv's = bezier trimmed to [0,t] */
00289       cv += order*dim;          /* now cv = last control vertex */
00290       while (--order) {
00291         P1 = cv;                /* last cv */
00292         P0 = P1 - dim;          /* next to last cv */
00293         j = order;
00294         while (j--) {
00295           d = dim;
00296           while (d--) {P0--; P1--; *P1 = (*P0 * s) + (*P1 * t);}}
00297       }
00298     }
00299   }
00300 }
00301 
00302 
00303 
00304 bool ON_IncreaseBezierDegree(
00305         int     dim, 
00306         ON_BOOL32    is_rat, 
00307         int     order, 
00308         int     cv_stride,
00309         double* cv 
00310         )
00311 /*****************************************************************************
00312 Increase the degree of a Bezier
00313  
00314 INPUT:
00315   cvdim (dim + is_rat)
00316   order ( >= 2 )
00317     order of input bezier
00318   cv            
00319     control vertices of bezier
00320   newcv    
00321     array of cvdim*(order+1) doubles (The cv and newcv pointers may be equal.)
00322 OUTPUT:
00323   newcv  Control vertices of an Bezier with order (order+1).  The new Bezier
00324          and the old Bezier evaluate to the same point.  
00325 COMMENTS:
00326   If {B_0, ... B_d} are the control vertices of the input Bezier, then
00327   {C_0, ..., C_{d+1}} are the control vertices of the returned Bezier, 
00328   where,
00329     C_0     = B_0
00330     C_k     = k/(d+1) * B_{k-1}  +  (d+1-k)/(d+1) * B_{k}(1 < k <= d)
00331     C_{d+1} = B_d
00332   The computation is done in a way that permits the pointers cv and newcv
00333   to be equal; i.e., if the cv array is long enough, the degree may be
00334   raised with a call like
00335     TL_IncreaseBezierDegree(cvdim,order,cv,cv);
00336 EXAMPLE:
00337   raise_degree(TL_BEZIER* bez)
00338   {  
00339     // raise the degree of a TL_BEZIER
00340     bez->cv = (double*) onrealloc ( bez->cv, (bez->order+1)*(bez->dim+bez->is_rat) );
00341     TL_IncreaseBezierDegree ( bez->dim+bez->is_rat, bez->order,bez->cv,bez->cv );
00342     bez->order++;
00343   }
00344 REFERENCE:
00345   BOHM-01, Page 7.
00346 RELATED FUNCTIONS:
00347   TL_DecreaseBezierDegree
00348 *****************************************************************************/
00349 {
00350   double a0, a1, d, c0, c1; 
00351   int j;
00352   double* newcv = cv;
00353   const int cvdim = (is_rat)?dim+1:dim;
00354   const int dcv = cv_stride - cvdim;
00355 
00356 
00357   j = cv_stride*order;
00358   newcv += j;
00359   memcpy( newcv, newcv-cv_stride, cvdim*sizeof(*newcv) );
00360   newcv -= (dcv+1);
00361   cv = newcv - cv_stride;
00362   a0 = order;
00363   a1 = 0.0;
00364   d = 1.0/a0;
00365   while (--order) {
00366     a0 -= 1.0;
00367     a1 += 1.0;
00368     c0 = d*a0;
00369     c1 = d*a1;
00370     j = cvdim;
00371     while(j--) {
00372       *newcv = c0 * *cv + c1 * *newcv; 
00373       cv--; 
00374       newcv--;
00375     }
00376     cv -= dcv;
00377     newcv -= dcv;
00378   }
00379   return true;
00380 }
00381 
00382 
00383 bool ON_RemoveBezierSingAt0(
00384                   int dim, 
00385                   int order, 
00386                   int cv_stride,
00387                   double* cv
00388                   )
00389 {
00390   const int cvdim = dim+1;
00391   int j,k,ord0;
00392   ord0 = order;
00393   while(cv[dim] == 0.0) {
00394     order--; 
00395     if (order < 2)
00396       return false;
00397     j = dim; 
00398     while(j--) {
00399       if (cv[j] != 0.0) 
00400         return false;
00401     }
00402     for (j=0;  j<order;  j++) {
00403       for (k=0;  k<cvdim;  k++) 
00404         cv[j*cv_stride+k] = (order*cv[(j+1)*cv_stride+k])/(j+1);
00405     }
00406   }
00407   while (order < ord0)
00408     ON_IncreaseBezierDegree(dim,true,order++,cv_stride,cv);
00409   return true;
00410 }
00411 
00412 
00413 bool ON_RemoveBezierSingAt1(
00414                   int dim, 
00415                   int order, 
00416                   int cv_stride,
00417                   double* cv
00418                   )
00419 {
00420   const int cvdim = dim+1;
00421   int i,k,ord0,CVlen;
00422   ord0 = order;
00423   CVlen=order*cvdim;
00424   while (order > 1 && cv[CVlen-1] == 0.0) {
00425     order--;
00426     if (order < 2)
00427       return false;
00428     i = dim; 
00429     while(i--) {
00430       if (cv[CVlen-1-i] != 0.0)
00431         return false;
00432     }
00433     for (i=0;  i<order;  i++) {
00434       for (k=0;  k<cvdim;  k++) 
00435         cv[i*cv_stride+k] = (order*cv[i*cv_stride+k])/(order-i);
00436     }
00437     CVlen -= cvdim;
00438   }
00439   while(order < ord0)
00440     ON_IncreaseBezierDegree(dim,true,order++,cv_stride,cv);
00441   return false;
00442 }
00443 
00444 
00445 bool ON_EvaluateBezier(
00446                 int dim,              // dimension
00447                 ON_BOOL32 is_rat,          // true if NURBS is rational
00448                 int order,            // order
00449                 int cv_stride,        // cv_stride >= (is_rat)?dim+1:dim
00450                 const double* cv,     // cv[order*cv_stride] array
00451                 double t0, double t1, // domain
00452                 int der_count,        // number of derivatives to compute
00453                 double t,             // evaluation parameter
00454                 int v_stride,         // v_stride (>=dimension)
00455                 double* v             // v[(der_count+1)*v_stride] array
00456                 )
00457 /*****************************************************************************
00458 Evaluate a Bezier
00459  
00460 INPUT:
00461   dim
00462     (>= 1) dimension of Bezier's range
00463   is_rat
00464     0: bezier is not rational
00465     1: bezier is rational
00466   order
00467     (>= 2) (order = degree+1)
00468   cv
00469     array of (dim+is_rat)*order doubles that define the
00470     Bezier's control vertices.
00471   t0, t1  (t0 != t1)
00472     Bezier's domain.   Mathematically, Beziers have domain [0,1].  In practice
00473     Beziers are frequently evaluated at (t-t0)/(t1-t0) and the chain
00474     rule is used to evaluate the derivatives.  This function is the most
00475     efficient place to apply the chain rule.
00476   t
00477     Evaluation parameter
00478   der_count
00479     (>= 0)  number of derivatives to evaluate
00480   answer
00481      answer[i] is NULL or points to an array of dim doubles.
00482 OUTPUT:
00483   ON_EvBezier()
00484     0: successful
00485    -1: failure - rational function had nonzero numerator and zero
00486                  denominator
00487   answer
00488      bez(t)   = answer[0]
00489      bez'(t)  = answer[1]
00490               ...
00491         (n)
00492      bez  (t) = answer[n]
00493 COMMENTS:
00494   Use de Casteljau's algorithm.  Rational fuctions with removable singularities
00495   (like x^2/x) are efficiently and correctly handled.
00496 EXAMPLE:
00497   // ...
00498 REFERENCE:
00499   AUTHOR page ?
00500 RELATED FUNCTIONS:
00501   ON_EvaluatedeCasteljau
00502   ON_EvQuotientRule
00503   ON_EvNurb
00504   ON_EvPolynomialPoint
00505   ON_onvertBezierToPolynomial
00506   ON_onvertPolynomialToBezier
00507   ON_onvertNurbToBezier
00508 *****************************************************************************/
00509 {
00510   unsigned char stack_buffer[4*64*sizeof(double)];
00511   double delta_t;
00512   register double alpha0;
00513   register double alpha1;
00514   register double *cv0, *cv1;
00515   register int i, j, k; 
00516   double* CV, *tmp;
00517   void* free_me = 0;
00518   const int degree = order-1;
00519   const int cvdim = (is_rat)?dim+1:dim;
00520 
00521   if ( cv_stride < cvdim )
00522     cv_stride = cvdim;
00523 
00524   memset( v, 0, v_stride*(der_count+1)*sizeof(*v) );
00525 
00526 #if defined( ON_DEBUG)
00527   if (t0==t1) {
00528     return false;
00529   }
00530 #endif
00531 
00532   i = order*cvdim;
00533   j = 0;
00534   if (der_count > degree) {
00535     if (is_rat)
00536       j = (der_count-degree)*cvdim;
00537     else {
00538       der_count = degree;
00539     }    
00540   }
00541 
00542   size_t sizeofCV = (i+j)*sizeof(*CV);
00543 
00544 
00545   // 21 November 2007 Dale Lear RR 29005 - remove call to alloca()
00546   CV = (double*)( (sizeofCV <= sizeof(stack_buffer)) ? stack_buffer : (free_me=onmalloc(sizeofCV)) );
00547   if (j) {
00548     memset( CV+i, 0, j*sizeof(*CV) );
00549   }
00550   cv0=CV;
00551   if (    t0 == t 
00552        || (t <= 0.5*(t0+t1) && t != t1) 
00553      ) 
00554   {
00555     for ( i = 0; i < order; i++ ) 
00556     {
00557       memcpy( cv0, cv, cvdim*sizeof(*cv0) );
00558       cv0 += cvdim;
00559       cv += cv_stride;
00560     }
00561     cv -= (cv_stride*order);
00562     delta_t = 1.0/(t1 - t);
00563     alpha1 = 1.0/(t1-t0);
00564     alpha0 = (t1-t)*alpha1;
00565     alpha1 *= t-t0;
00566   }
00567   else 
00568   {
00569     cv += (cv_stride*order);
00570     k=order;
00571     while(k--) 
00572     {
00573       cv -= cv_stride; 
00574       memcpy( cv0, cv, cvdim*sizeof(*cv0) );
00575       cv0 += cvdim;
00576     }
00577     delta_t = 1.0/(t0 - t);
00578     alpha0 = 1.0/(t1-t0);
00579     alpha1 = (t1-t)*alpha0;
00580     alpha0 *= t-t0;
00581   }
00582 
00583   /* deCasteljau (from the right) */
00584   if (alpha1 != 0.0) {
00585     j = order; while (--j) {
00586       cv0 = CV;
00587       cv1 = cv0 + cvdim;
00588       i = j; while (i--) {
00589         k = cvdim; 
00590         while (k--) {
00591           *cv0 = *cv0 * alpha0 + *cv1 * alpha1; 
00592           cv0++; 
00593           cv1++;
00594         }
00595       }
00596     }
00597   }
00598   
00599   /* check for removable singularity */
00600   if (is_rat && CV[dim] == 0.0)
00601   {
00602     if ( !ON_RemoveBezierSingAt0(dim,order,cvdim,CV) )
00603     {
00604       if ( free_me )
00605         onfree(free_me);  
00606       return false;
00607     }
00608   }
00609 
00610   /* Lee (from the right) */
00611   if (der_count) { 
00612     tmp=CV;
00613     alpha0 = order;
00614     j = (der_count>=order)?order:der_count+1;
00615     CV += cvdim*j; while(--j) {
00616       alpha0 -= 1.0; cv1 = CV; cv0 = cv1-cvdim;
00617       i=j; while(i--) {
00618         alpha1 = alpha0 * delta_t;
00619         k=cvdim; while(k--) {
00620           cv0--; 
00621           cv1--; 
00622           *cv1 = alpha1*(*cv1 - *cv0);
00623         }
00624       }
00625     }
00626     CV=tmp;
00627   }
00628 
00629   if ( 2 == order )
00630   {
00631     // 7 January 2004  Dale Lear
00632     //    Added to fix those cases when, numerically, t*a + (1.0-t)*a != a.
00633     //    Similar to fix for RR 9683.
00634     j = cv_stride;
00635     for ( i = 0; i < cvdim; i++, j++ )
00636     {
00637       if ( cv[i] == cv[j] )
00638       {
00639         CV[i] = cv[i];
00640       }
00641     }
00642   }
00643 
00644   if (is_rat) {
00645     ON_EvaluateQuotientRule( dim, der_count, cvdim, CV );
00646   }
00647 
00648   for (i=0;i<=der_count;i++) {
00649     memcpy( v, CV, dim*sizeof(*v) );
00650     v += v_stride;
00651     CV += cvdim;
00652   }
00653 
00654   if ( free_me )
00655     onfree(free_me);  
00656 
00657   return true;
00658 }
00659 
00660 
00661 bool ON_EvaluateNurbsBasis( int order, const double* knot, 
00662                                        double t, double* N )
00663 {
00664 /*****************************************************************************
00665 Evaluate B-spline basis functions
00666  
00667 INPUT:
00668   order >= 1 
00669     d = degree = order - 1
00670   knot[]
00671     array of length 2*d.  
00672     Generally, knot[0] <= ... <= knot[d-1] < knot[d] <= ... <= knot[2*d-1].
00673   N[]
00674     array of length order*order
00675 
00676 OUTPUT:
00677   If "N" were declared as double N[order][order], then
00678 
00679                  k
00680     N[d-k][i] = N (t) = value of i-th degree k basis function.
00681                  i
00682   where 0 <= k <= d and k <= i <= d.
00683 
00684         In particular, N[0], ..., N[d] - values of degree d basis functions.
00685   The "lower left" triangle is not initialized.
00686 
00687   Actually, the above is true when knot[d-1] <= t < knot[d].  Otherwise, the
00688   value returned is the value of the polynomial that agrees with N_i^k on the
00689   half open domain [ knot[d-1], knot[d] )
00690 
00691 COMMENTS:
00692   If a degree d NURBS has n control points, then the TL knot vector has
00693   length d+n-1. ( Most literature, including DeBoor and The NURBS Book,
00694   duplicate the TL start and end knot and have knot vectors of length
00695   d+n+1. )
00696   
00697   Assume C is a B-spline of degree d (order=d+1) with n control vertices
00698   (n>=d+1) and knot[] is its knot vector.  Then
00699 
00700     C(t) = Sum( 0 <= i < n, N_{i}(t) * C_{i} )
00701 
00702   where N_{i} are the degree d b-spline basis functions and C_{i} are the control
00703   vertices.  The knot[] array length d+n-1 and satisfies
00704 
00705     knot[0] <= ... <= knot[d-1] < knot[d]
00706     knot[n-2] < knot[n-1] <= ... <= knot[n+d-2]
00707     knot[i] < knot[d+i] for 0 <= i < n-1
00708     knot[i] <= knot[i+1] for 0 <= i < n+d-2
00709 
00710   The domain of C is [ knot[d-1], knot[n-1] ].
00711 
00712   The support of N_{i} is [ knot[i-1], knot[i+d] ).
00713 
00714   If d-1 <= k < n-1 and knot[k] <= t < knot[k+1], then 
00715   N_{i}(t) = 0 if i <= k-d
00716            = 0 if i >= k+2
00717            = B[i-k+d-1] if k-d+1 <= i <= k+1, where B[] is computed by the call
00718              TL_EvNurbBasis( d+1, knot+k-d+1, t, B );
00719 
00720   If 0 <= j < n-d, 0 <= m <= d, knot[j+d-1] <= t < knot[j+d], and B[] is 
00721   computed by the call
00722 
00723     TL_EvNurbBasis( d+1, knot+j, t, B ),
00724 
00725   then 
00726 
00727     N_{j+m}(t) = B[m].
00728 
00729 EXAMPLE:
00730 REFERENCE:
00731   The NURBS book
00732 RELATED FUNCTIONS:
00733   TL_EvNurbBasis
00734   TL_EvNurbBasisDer
00735 *****************************************************************************/
00736   register double a0, a1, x, y;
00737   const double *k0;
00738   double *t_k, *k_t, *N0;
00739   const int d = order-1;
00740   register int j, r;
00741 
00742   t_k = (double*)alloca( d<<4 );
00743   k_t = t_k + d;
00744   
00745   if (knot[d-1] == knot[d]) {
00746                 /* value is defined to be zero on empty spans */
00747     memset( N, 0, order*order*sizeof(*N) );
00748     return true;
00749   }
00750 
00751   N  += order*order-1;
00752         N[0] = 1.0;
00753   knot += d;
00754   k0 = knot - 1;
00755 
00756   for (j = 0; j < d; j++ ) {
00757                 N0 = N;
00758     N -= order+1;
00759     t_k[j] = t - *k0--;
00760     k_t[j] = *knot++ - t;
00761                 
00762     x = 0.0;
00763     for (r = 0; r <= j; r++) {
00764       a0 = t_k[j-r];
00765       a1 = k_t[r];
00766       y = N0[r]/(a0 + a1);
00767       N[r] = x + a1*y;
00768       x = a0*y;
00769     }
00770 
00771     N[r] = x;
00772   }
00773 
00774   // 16 September 2003 Dale Lear (at Chuck's request)
00775   //   When t is at an end knot, do a check to
00776   //   get exact values of basis functions.
00777   //   The problem being that a0*y above can
00778   //   fail to be one by a bit or two when knot
00779   //   values are large.
00780   x = 1.0-ON_SQRT_EPSILON;
00781   if ( N[0] > x )
00782   {
00783     if ( N[0] != 1.0 && N[0] < 1.0 + ON_SQRT_EPSILON )
00784     {
00785       r = 1;
00786       for ( j = 1; j <= d && r; j++ )
00787       {
00788         if ( N[j] != 0.0 )
00789           r = 0;
00790       }
00791       if (r)
00792         N[0] = 1.0;
00793     }
00794   }
00795   else if ( N[d] > x )
00796   {
00797     if ( N[d] != 1.0 && N[d] < 1.0 + ON_SQRT_EPSILON )
00798     {
00799       r = 1;
00800       for ( j = 0; j < d && r; j++ )
00801       {
00802         if ( N[j] != 0.0 )
00803           r = 0;
00804       }
00805       if (r)
00806         N[d] = 1.0;
00807     }
00808   }
00809 
00810   return true;
00811 }
00812 
00813 
00814 bool ON_EvaluateNurbsBasisDerivatives( int order, const double* knot, 
00815                        int der_count, double* N )
00816 {
00817         /* INPUT:
00818          *   Results of the call
00819          *      TL_EvNurbBasis( order, knot, t, N );  (initializes N[] )
00820          *   are sent to
00821          *      TL_EvNurbBasisDer( order, knot, der_count, N ),
00822          *   where 1 <= der_count < order
00823          *
00824          * OUTPUT:
00825    *  If "N" were declared as double N[order][order], then
00826          *
00827    *                                    d
00828    *    N[d-k][i] = k-th derivative of N (t)
00829    *                                    i
00830    *
00831          *  where 0 <= k <= d and 0 <= i <= d.
00832          *
00833          * In particular, 
00834          *   N[0], ..., N[d] - values of degree d basis functions.
00835          *   N[order], ..., N[order_d] - values of first derivative.
00836          *
00837    * Actually, the above is true when knot[d-1] <= t < knot[d].  Otherwise, the
00838    * values returned are the values of the polynomials that agree with N_i^k on the
00839    * half open domain [ knot[d-1], knot[d] )
00840          *
00841          * Ref: The NURBS Book
00842          */
00843         double dN, c;
00844         const double *k0, *k1;
00845         double *a0, *a1, *ptr, **dk;
00846         int i, j, k, jmax;
00847 
00848         const int d = order-1;
00849         const int Nstride = -der_count*order;
00850 
00851         /* workspaces for knot differences and coefficients 
00852          *
00853          * a0[] and a1[] have order doubles
00854          *
00855          * dk[0] = array of d knot differences
00856          * dk[1] = array of (d-1) knot differences
00857          *
00858          * dk[der_count-1] = 1.0/(knot[d] - knot[d-1])
00859          * dk[der_count] = dummy pointer to make loop efficient
00860          */
00861         dk = (double**)alloca( (der_count+1) << 3 ); /* << 3 in case pointers are 8 bytes long */
00862         a0 = (double*)alloca( (order*(2 + ((d+1)>>1))) << 3 ); /* d for a0, d for a1, d*order/2 for dk[]'s and slop to avoid /2 */
00863         a1 = a0 + order;
00864 
00865         /* initialize reciprocal of knot differences */
00866         dk[0] = a1 + order;
00867         for (k = 0; k < der_count; k++) {
00868                 j = d-k;
00869                 k0 = knot++;
00870                 k1 = k0 + j;
00871                 for (i = 0; i < j; i++) 
00872                         dk[k][i] = 1.0/(*k1++ - *k0++);
00873                 dk[k+1] = dk[k] + j;
00874         }
00875         dk--;
00876         /* dk[1] = 1/{t[d]-t[0], t[d+1]-t[1], ..., t[2d-2] - t[d-2], t[2d-1] - t[d-1]}
00877          *       = diffs needed for 1rst derivative
00878          * dk[2] = 1/{t[d]-t[1], t[d+1]-t[2], ..., t[2d-2] - t[d-1]}
00879          *       = diffs needed for 2nd derivative
00880          * ...
00881          * dk[d] = 1/{t[d] - t[d-1]}
00882          *       = diff needed for d-th derivative
00883          *
00884          * d[k][n] = 1.0/( t[d+n] - t[k-1+n] )
00885          */
00886         
00887         N += order;
00888         /* set N[0] ,..., N[d] = 1rst derivatives, 
00889          * N[order], ..., N[order+d] = 2nd, etc.
00890          */
00891         for ( i=0; i<order; i++) {
00892                 a0[0] = 1.0;
00893                 for (k = 1; k <= der_count; k++) {
00894                         /* compute k-th derivative of N_i^d up to d!/(d-k)! scaling factor */
00895                         dN = 0.0;
00896                         j = k-i; 
00897                         if (j <= 0) {
00898                                 dN = (a1[0] = a0[0]*dk[k][i-k])*N[i];
00899                                 j = 1;
00900                         }
00901                         jmax = d-i; 
00902                         if (jmax < k) {
00903                                 while (j <= jmax) {
00904                                         dN += (a1[j] = (a0[j] - a0[j-1])*dk[k][i+j-k])*N[i+j];
00905                                         j++;
00906                                 }
00907                         }
00908                         else {
00909                                 /* sum j all the way to j = k */
00910                                 while (j < k) {
00911                                         dN += (a1[j] = (a0[j] - a0[j-1])*dk[k][i+j-k])*N[i+j];
00912                                         j++;
00913                                 }
00914                                 dN += (a1[k] = -a0[k-1]*dk[k][i])*N[i+k];
00915                         }
00916 
00917                         /* d!/(d-k)!*dN = value of k-th derivative */
00918                         N[i] = dN;
00919                         N += order;
00920                         /* a1[] s for next derivative = linear combination
00921                          * of a[]s used to compute this derivative.
00922                          */
00923                         ptr = a0; a0 = a1; a1 = ptr;
00924                 }
00925                 N += Nstride;
00926         }
00927 
00928         /* apply d!/(d-k)! scaling factor */
00929         dN = c = (double)d;
00930         k = der_count;
00931         while (k--) {
00932                 i = order;
00933                 while (i--)
00934                         *N++ *= c;
00935                 dN -= 1.0;
00936                 c *= dN;
00937         }
00938   return true;
00939 }
00940 
00941 static
00942 bool ON_EvaluateNurbsNonRationalSpan( 
00943                   int dim,             // dimension
00944                   int order,           // order
00945                   const double* knot,  // knot[] array of (2*order-2) doubles
00946                   int cv_stride,       // cv_stride >= (is_rat)?dim+1:dim
00947                   const double* cv,    // cv[order*cv_stride] array
00948                   int der_count,       // number of derivatives to compute
00949                   double t,            // evaluation parameter
00950                   int v_stride,        // v_stride (>=dimension)
00951                   double* v            // v[(der_count+1)*v_stride] array
00952                   )
00953 {
00954   const int stride_minus_dim = cv_stride - dim;
00955   const int cv_len = cv_stride*order;
00956   int i, j, k;
00957   double *N;
00958         double a;
00959 
00960         N = (double*)alloca( (order*order)<<3 );
00961 
00962   if ( stride_minus_dim > 0)
00963   {
00964     i = (der_count+1);
00965     while( i--)
00966     {
00967       memset(v,0,dim*sizeof(v[0]));
00968       v += v_stride;
00969     }
00970     v -= ((der_count+1)*v_stride);
00971   }
00972   else
00973   {
00974     memset( v, 0, (der_count+1)*v_stride*sizeof(*v) );
00975   }
00976 
00977   if ( der_count >= order )
00978     der_count = order-1;
00979 
00980         // evaluate basis functions
00981         ON_EvaluateNurbsBasis( order, knot, t, N );
00982         if ( der_count ) 
00983                 ON_EvaluateNurbsBasisDerivatives( order, knot, der_count, N );
00984 
00985         // convert cv's into answers
00986         for (i = 0; i <= der_count; i++, v += v_stride, N += order) {
00987     for ( j = 0; j < order; j++ ) {
00988       a = N[j];
00989       for ( k = 0; k < dim; k++ ) {
00990         *v++ += a* *cv++;
00991       }
00992       v -= dim;
00993       cv += stride_minus_dim;
00994     }
00995     cv -= cv_len;
00996         }
00997 
00998   if ( 2 == order )
00999   {
01000     // 7 January 2004  Dale Lear
01001     //    Added to fix those cases when, numerically, t*a + (1.0-t)*a != a.
01002     //    Similar to fix for RR 9683.
01003     v -= (der_count+1)*v_stride;
01004     j = cv_stride;
01005     for ( i = 0; i < dim; i++, j++ )
01006     {
01007       if (cv[i] == cv[j] )
01008         v[i] = cv[i];
01009     }
01010   }
01011                 
01012         return true;
01013 }
01014 
01015 static
01016 bool ON_EvaluateNurbsRationalSpan( 
01017                   int dim,             // dimension
01018                   int order,           // order
01019                   const double* knot,  // knot[] array of (2*order-2) doubles
01020                   int cv_stride,       // cv_stride >= (is_rat)?dim+1:dim
01021                   const double* cv,    // cv[order*cv_stride] array
01022                   int der_count,       // number of derivatives to compute
01023                   double t,            // evaluation parameter
01024                   int v_stride,        // v_stride (>=dimension)
01025                   double* v            // v[(der_count+1)*v_stride] array
01026                   )
01027 {
01028   const int hv_stride = dim+1;
01029   double *hv;
01030   int i;
01031   bool rc;
01032 
01033   hv = (double*)alloca( (der_count+1)*hv_stride*sizeof(*hv) );
01034   
01035   rc = ON_EvaluateNurbsNonRationalSpan( dim+1, order, knot, 
01036           cv_stride, cv, der_count, t, hv_stride, hv );
01037   if (rc) {
01038     rc = ON_EvaluateQuotientRule(dim, der_count, hv_stride, hv);
01039   }
01040   if ( rc ) {
01041     // copy answer to v[]
01042     for ( i = 0; i <= der_count; i++ ) {
01043       memcpy( v, hv, dim*sizeof(*v) );
01044       v += v_stride;
01045       hv += hv_stride;
01046     }
01047   }
01048   return rc;
01049 }
01050 
01051 
01052 bool ON_EvaluateNurbsSpan( 
01053                   int dim,             // dimension
01054                   ON_BOOL32 is_rat,         // true if NURBS is rational
01055                   int order,           // order
01056                   const double* knot,  // knot[] array of (2*order-2) doubles
01057                   int cv_stride,       // cv_stride >= (is_rat)?dim+1:dim
01058                   const double* cv,    // cv[order*cv_stride] array
01059                   int der_count,       // number of derivatives to compute
01060                   double t,            // evaluation parameter
01061                   int v_stride,        // v_stride (>=dimension)
01062                   double* v            // v[(der_count+1)*v_stride] array
01063                   )
01064 {
01065   bool rc = false;
01066   if ( knot[0] == knot[order-2] && knot[order-1] == knot[2*order-3] ) {
01067     // Bezier span - use faster Bezier evaluator
01068     rc = ON_EvaluateBezier(dim, is_rat, order, cv_stride, cv,
01069                             knot[order-2], knot[order-1],
01070                             der_count, t, v_stride, v);
01071   }
01072   else {
01073     // generic NURBS span evaluation
01074     rc = (is_rat)
01075          ? ON_EvaluateNurbsRationalSpan( 
01076               dim, order, knot, cv_stride, cv,
01077               der_count, t, v_stride, v )
01078          : ON_EvaluateNurbsNonRationalSpan( 
01079               dim, order, knot, cv_stride, cv,
01080               der_count, t, v_stride, v );
01081   }
01082   return rc;
01083 }
01084 
01085 
01086 bool ON_EvaluateNurbsSurfaceSpan(
01087         int dim,
01088         ON_BOOL32 is_rat,
01089         int order0, int order1,
01090         const double* knot0,
01091         const double* knot1,
01092         int cv_stride0, int cv_stride1,
01093         const double* cv0, // cv at "lower left" of bispan
01094         int der_count,
01095         double t0, double t1,
01096         int v_stride, 
01097         double* v      // returns values
01098         )
01099 {
01100         const int der_count0 = (der_count >= order0) ? order0-1 : der_count;
01101         const int der_count1 = (der_count >= order1) ? order1-1 : der_count;
01102         const double *cv;
01103 
01104         double *N_0, *N_1, *P0, *P;
01105         double c;
01106         int d1max, d, d0, d1, i, j, j0, j1, Pcount, Psize;
01107 
01108   const int cvdim = (is_rat) ? dim+1 : dim;
01109   const int dcv1 = cv_stride1 - cvdim;
01110 
01111         // get work space memory
01112         i = order0*order0;
01113         j = order1*order1;
01114         Pcount = ((der_count+1)*(der_count+2))>>1;
01115         Psize = cvdim<<3;
01116   N_0 = (double*)alloca( ((i + j) << 3) + Pcount*Psize );
01117         N_1 = N_0 + i;
01118         P0  = N_1 + j;
01119         memset( P0, 0, Pcount*Psize );
01120 
01121         /* evaluate basis functions */
01122         ON_EvaluateNurbsBasis( order0, knot0, t0, N_0 );
01123         ON_EvaluateNurbsBasis( order1, knot1, t1, N_1 );
01124         if (der_count0) {
01125     // der_count0 > 0 iff der_count1 > 0 
01126                 ON_EvaluateNurbsBasisDerivatives( order0, knot0, der_count0, N_0 );
01127                 ON_EvaluateNurbsBasisDerivatives( order1, knot1, der_count1, N_1 );
01128         }
01129 
01130   // compute point
01131         P = P0;
01132         for ( j0 = 0; j0 < order0; j0++) {
01133     cv = cv0 + j0*cv_stride0;
01134                 for ( j1 = 0; j1 < order1; j1++ ) {
01135                         c = N_0[j0]*N_1[j1];
01136                         j = cvdim;
01137                         while (j--) 
01138                                 *P++ += c* *cv++;
01139                         P -= cvdim;
01140       cv += dcv1;
01141                 }
01142         }
01143 
01144   if ( der_count > 0 ) {
01145     // compute first derivatives
01146         P += cvdim; // step over point
01147                 for ( j0 = 0; j0 < order0; j0++) {
01148       cv = cv0 + j0*cv_stride0;
01149                         for ( j1 = 0; j1 < order1; j1++ ) {
01150         // "Ds"
01151                                 c = N_0[j0+order0]*N_1[j1];
01152                                 j = cvdim;
01153                                 while (j--) 
01154                                         *P++ += c* *cv++;
01155         cv -= cvdim;
01156 
01157         // "Dt"
01158                                 c = N_0[j0]*N_1[j1+order1];
01159                                 j = cvdim;
01160                                 while (j--) 
01161                                         *P++ += c* *cv++;
01162                                 P -= cvdim;
01163                                 P -= cvdim;
01164 
01165         cv += dcv1;
01166                         }
01167                 }
01168 
01169     if ( der_count > 1 ) {
01170       // compute second derivatives
01171       P += cvdim; // step over "Ds"
01172       P += cvdim; // step over "Dt"
01173       if ( der_count0+der_count1 > 1 ) {
01174         // compute "Dss"
01175                     for ( j0 = 0; j0 < order0; j0++) {
01176           // P points to first coordinate of Dss
01177           cv = cv0 + j0*cv_stride0;
01178                             for ( j1 = 0; j1 < order1; j1++ ) {
01179             if ( der_count0 > 1 ) {
01180               // "Dss"
01181                                       c = N_0[j0+2*order0]*N_1[j1];
01182                                       j = cvdim;
01183                                       while (j--) 
01184                                               *P++ += c* *cv++;
01185               cv -= cvdim;
01186             }
01187             else {
01188               P += cvdim; // Dss = 0
01189             }
01190 
01191             // "Dst"
01192                                     c = N_0[j0+order0]*N_1[j1+order1];
01193                                     j = cvdim;
01194                                     while (j--) 
01195                                             *P++ += c* *cv++;
01196             cv -= cvdim;
01197 
01198             if ( der_count1 > 1 ) {
01199               // "Dtt"
01200                                       c = N_0[j0]*N_1[j1+2*order1];
01201                                       j = cvdim;
01202                                       while (j--) 
01203                                               *P++ += c* *cv++;
01204               cv -= cvdim;
01205                                     P -= cvdim;
01206             }
01207 
01208                                     P -= cvdim;
01209                                     P -= cvdim;
01210             cv += cv_stride1;
01211                             }
01212                     }
01213       }
01214 
01215       if ( der_count > 2 ) 
01216       {
01217         // 12 February 2004 Dale Lear
01218         //     Bug fix for d^n/ds^n when n >= 3
01219         // compute higher derivatives in slower generic loop
01220         for ( d = 3; d <= der_count; d++ ) 
01221         {
01222           P += d*cvdim; // step over (d-1)th derivatives
01223           d1max = (d > der_count1) ? der_count1 : d;
01224                             for ( j0 = 0; j0 < order0; j0++) 
01225           {
01226             cv = cv0 + j0*cv_stride0;
01227                                     for ( j1 = 0; j1 < order1; j1++ ) 
01228             {
01229               for (d0 = d, d1 = 0; 
01230                    d0 > der_count0 && d1 <= d1max; 
01231                    d0--, d1++ ) 
01232               {
01233                 // partial with respect to "s" is zero
01234                 P += cvdim;
01235               }
01236               for ( /*empty*/; d1 <= d1max; d0--, d1++ ) 
01237               {
01238                 c = N_0[j0 + d0*order0]*N_1[j1 + d1*order1];
01239                                               j = cvdim;
01240                                               while (j--) 
01241                                                       *P++ += c* *cv++;
01242                 cv -= cvdim;
01243               }
01244               // remaining partials with respect to "t" are zero
01245               // - reset and add contribution from the next cv
01246               P -= d1*cvdim;
01247               cv += cv_stride1;
01248                                     }
01249                             }
01250         }
01251       }
01252 
01253     }
01254   }
01255 
01256         if ( is_rat ) {
01257                 ON_EvaluateQuotientRule2( dim, der_count, cvdim, P0 );
01258                 Psize -= 8;
01259         }
01260         for ( i = 0; i < Pcount; i++) {
01261                 memcpy( v, P0, Psize );
01262     v += v_stride;
01263                 P0 += cvdim;
01264         }
01265 
01266         return true;
01267 }
01268 
01269 
01270 bool ON_EvaluateNurbsDeBoor(
01271                            int cv_dim,
01272                            int order, 
01273                            int cv_stride,
01274                            double *cv,
01275                            const double *knots, 
01276                            int side,
01277                            double mult_k, 
01278                            double t
01279                            )
01280 /*
01281  * Evaluate a B-spline span using the de Boor algorithm
01282  *
01283  * INPUT:
01284  *   cv_dim
01285  *      >= 1
01286  *   order
01287  *      (>= 2)  There is no restriction on order.  For order >= 18,
01288  *      the necessary workspace is dynamically allocated and deallocated.
01289  *      (The function requires a workspace of 2*order-2 doubles.)
01290  *   cv
01291  *      array of order*cv_dim doubles that specify the B-spline span's
01292  *      control vertices.
01293  *   knots
01294  *      array of 2*(order-1) doubles that specify the B-spline span's
01295  *      knot vector.
01296  *   side
01297  *      -1  return left side of B-spline span in cv array
01298  *      +1  return right side of B-spline span in cv array
01299  *      -2  return left side of B-spline span in cv array
01300  *          Ignore values of knots[0,...,order-3] and assume
01301  *          left end of span has a fully multiple knot with
01302  *          value "mult_k".
01303  *      +2  return right side of B-spline span in cv array
01304  *          Ignore values of knots[order,...,2*order-2] and
01305  *          assume right end of span has a fully multiple
01306  *          knot with value "mult_k".
01307  *      WARNING: If side is != {-2,-1,+1,+2}, this function may crash
01308  *               or return garbage.
01309  *   mult_k
01310  *      Used when side = -2 or +2.
01311  *   t 
01312  *      If side < 0, then the cv's for the portion of the NURB span to
01313  *      the LEFT of t are computed.  If side > 0, then the cv's for the
01314  *      portion the span to the RIGHT of t are computed.  The following
01315  *      table summarizes the restrictions on t:
01316  *
01317  *       value of side         condition t must satisfy
01318  *          -2                    mult_k < t and mult_k < knots[order-1]
01319  *          -1                    knots[order-2] < t
01320  *          +1                    t < knots[order-1]
01321  *          +2                    t < mult_k and knots[order-2] < mult_k
01322  *
01323  * OUTPUT:
01324  *   cv
01325  *      If side <= 0, the input cv's are replaced with the cv's for
01326  *      the B-spline span trimmed/extended to [knots[order-2],t]  with
01327  *      new knot vector {knots[0], ..., knots[order-2], t, ..., t}.
01328  *                                                      \________/
01329  *                                                       order-1 t's
01330  *      In particular, {cv[(order-1)*cv_dim], ..., cv[order*cv_dim - 1]}
01331  *      is the value of the B-spline at t.
01332  *      If side > 0, the input cv's are replaced with the cv's for
01333  *      the B-spline span trimmed/extended to [t,knots[order-1]]  with
01334  *      new knot vector {t, ..., t, knots[order-1], ..., knots[2*order-3]}.
01335  *                       \________/
01336  *                       order-1 t's
01337  *      In particular, {cv[0], ..., cv[cv_dim-1]} is the value of the B-spline
01338  *      at t.
01339  *
01340  *      NOTE WELL: The input knot vector is NOT modified.  If you want to
01341  *                 use the returned control points with the input knot vector,
01342  *                 then it is your responsibility to set
01343  *                    knots[0] = ... = knots[order-2] = t (side > 0)
01344  *                 or
01345  *                    knots[order-1] = ... = knots[2*order-2] = t (side < 0).
01346  *                 See the comments concering +/- 2 values of the "side"
01347  *                 argument.  In most cases, you can avoid resetting knots
01348  *                 by carefully choosing the value of "side" and "mult_k".
01349  *  TL_EvDeBoor()
01350  *   0: successful
01351  *      -1: knot[order-2] == knot[order-1]
01352  *
01353  * COMMENTS:
01354  *
01355  *   This function is the single most important NURB curve function in the
01356  *   TL library.  It is used to evaluate, trim, split and extend NURB curves.
01357  *   It is used to convert portions of NURB curves to Beziers and to create
01358  *   fully multiple end knots.  The functions that perform the above tasks
01359  *   simply call this function with appropriate values and take linear
01360  *   combonations of the returned cv's to compute the desired result.
01361  *
01362  *   Rational cases are handled adding one to the dimension and applying the
01363  *   quotient rule as needed.
01364  *
01365  *   Set a[i,j] = (t-knots[i+j-1])/(knots[i+j+order-2] - knots[i+j-1])
01366  *   Set D[i,j] = {cv[j*cv_dim], ..., cv[(j+1)*cv_dim-1]}, if i = 0
01367  *                (1-a[i,j])*D[i-1,j-1] + a[i,j]*D[i-1,j], if 0 < i <= d = degree
01368  * 
01369  *   The collection of D[i,j]'s is typically drawn in a triangular array:
01370  *
01371  *   D[0,0]
01372  *            D[1,1]
01373  *   D[0,1]              D[2,2]
01374  *            D[1,2]             ...
01375  *   D[0,2]
01376  *  
01377  *   ...                                  D[d,d]
01378  *                               ...
01379  *   D[0,d-1]            D[2,d]
01380  *            D[1,d]
01381  *   D[0,d]
01382  *
01383  *   When side <= 0, the input cv's are replaced with
01384  *   D[0,0], D[1,2], ..., D[d,d].
01385  *
01386  *   When side >  0, the input cv's are replace with
01387  *   D[d,d], D[d-1,d], ..., D[0,d].
01388  *
01389  * EXAMPLE:
01390  *
01391  * REFERENCE:
01392  *   BOHM-01, Page 16.
01393  *   LEE-01, Section 6.
01394  *
01395  * RELATED FUNCTIONS:
01396  *   TL_EvNurbBasis(), TL_EvNurb(), TL_EvdeCasteljau(), TL_EvQuotientRule()
01397  */
01398 {
01399   double 
01400     workarray[21], alpha0, alpha1, t0, t1, dt, *delta_t, *free_delta_t, *cv0, *cv1;
01401   const double 
01402     *k0, *k1;
01403   int
01404     degree, i, j, k;
01405 
01406   const int cv_inc = cv_stride - cv_dim;
01407 
01408   j = 0;
01409   delta_t = workarray;
01410   free_delta_t = 0;
01411   degree = order-1;  
01412   t0 = knots[degree-1];
01413   t1 = knots[degree];
01414   if (t0 == t1) {
01415     ON_ERROR("ON_EvaluateNurbsDeBoor(): knots[degree-1] == knots[degree]");
01416     return false;
01417   }
01418 
01419   if (side < 0) {
01420     /* if right end of span is fully multiple and t = end knot,
01421      * then we're done.
01422      */
01423     if (t == t1 && t1 == knots[2*degree-1])
01424       return true;
01425     /* if left end of span is fully multiple, save time */
01426     if (side == -2)
01427       t0 = mult_k;
01428     else if (t0 == knots[0])
01429       side = -2;
01430     else {
01431       side = -1;
01432       if (degree > 21)
01433         delta_t = free_delta_t = (double*)onmalloc(degree*sizeof(*delta_t));
01434     }
01435     /* delta_t = {t - knot[order-2], t - knot[order-1], ... , t - knot[0]} */
01436     knots += degree-1;
01437     if (side != -2) {
01438       k0=knots; k=degree; while(k--) *delta_t++ = t - *k0--; delta_t -= degree;
01439       cv += order*cv_stride;
01440       k = order; while (--k) { 
01441         cv1 = cv;
01442         cv0 = cv1 - cv_stride;
01443         k0 = knots;             /* *k0 = input_knots[d-1]          */
01444         k1 = k0+k;              /* *k1 = input_knots[d-1+k]        */ 
01445         i = k; while(i--) {
01446           alpha1 = *delta_t++/(*k1-- - *k0--); 
01447           alpha0 = 1.0 - alpha1;
01448           cv0 -= cv_inc;
01449           cv1 -= cv_inc;
01450           j = cv_dim;
01451           while (j--) {cv0--; cv1--; *cv1 = *cv0 * alpha0 + *cv1 * alpha1;} 
01452         }
01453         delta_t -= k;
01454       }
01455     }
01456     else {
01457       dt = t - t0;
01458       // cv += order*cv_dim; // Chuck-n-Dale 21 Sep bug fix change cv_dim to cv_stride
01459       cv += order*cv_stride;
01460       k = order; while (--k) { 
01461         cv1 = cv;
01462         cv0 = cv1 - cv_stride;
01463         k1 = knots+k;
01464         i = k; while(i--) {
01465           alpha1 = dt/(*k1-- - t0); 
01466           alpha0 = 1.0 - alpha1;
01467           cv0 -= cv_inc;
01468           cv1 -= cv_inc;
01469           j = cv_dim;
01470           while (j--) {cv0--; cv1--; *cv1 = *cv0 * alpha0 + *cv1 * alpha1;} 
01471         }
01472       }
01473     }
01474   }
01475   else {
01476     /* if left end of span is fully multiple and t = start knot,
01477      * then we're done.
01478      */
01479     if (t == t0 && t0 == knots[0])
01480       return true;
01481     /* if right end of span is fully multiple, save time */
01482     if (side == 2)
01483       t1 = mult_k;
01484     else if (t1 == knots[2*degree-1])
01485       side = 2;
01486     else {
01487       side = 1;
01488       if (degree > 21)
01489         delta_t = free_delta_t = (double*)onmalloc(degree*sizeof(*delta_t));
01490     }
01491     knots += degree;
01492     if (side == 1) {
01493       /* variable right end knots
01494        * delta_t = {knot[order-1] - t, knot[order] -  t, .. knot[2*order-3] - t}
01495        */
01496       k1=knots; k = degree; while (k--) *delta_t++ = *k1++ - t; delta_t -= degree;
01497       k = order; while (--k) {
01498         cv0 = cv;
01499         cv1 = cv0 + cv_stride;
01500         k1 = knots;
01501         k0 = k1 - k;
01502         i = k; while(i--) {
01503           alpha0 = *delta_t++/(*k1++ - *k0++);
01504           alpha1 = 1.0 - alpha0;
01505           j = cv_dim;
01506           while(j--) {*cv0 = *cv0 * alpha0 + *cv1 * alpha1; cv0++; cv1++;}
01507           cv0 += cv_inc;
01508           cv1 += cv_inc;
01509         }
01510         delta_t -= k;
01511       }
01512     }
01513     else {
01514       /* all right end knots = t1  delta_t = t1 - t */
01515       dt = t1 - t;
01516       k = order; while (--k) {
01517         cv0 = cv;
01518         cv1 = cv0 + cv_stride;
01519         k0 = knots - k;         /* *knots = input_knots[d]       */ 
01520         i = k; while(i--) {
01521           alpha0 = dt/(t1 - *k0++);
01522           alpha1 = 1.0 - alpha0;
01523           j = cv_dim;
01524           while(j--) {*cv0 = *cv0 * alpha0 + *cv1 * alpha1; cv0++; cv1++;}
01525           cv0 += cv_inc;
01526           cv1 += cv_inc;
01527         }
01528       }
01529     }
01530   }
01531     
01532   if (free_delta_t)
01533     onfree(free_delta_t);
01534 
01535   return true;
01536 }
01537 
01538 
01539 bool ON_EvaluateNurbsBlossom(int cvdim,
01540                              int order, 
01541                              int cv_stride,
01542                              const double *CV,//size cv_stride*order
01543                              const double *knot, //nondecreasing, size 2*(order-1)
01544                              // knot[order-2] != knot[order-1]
01545                              const double *t, //input parameters size order-1
01546                              double* P
01547                             )
01548 
01549 {
01550 
01551   if (!CV || !t || !knot) return false;
01552   if (cv_stride < cvdim) return false;
01553   const double* cv;
01554   int degree = order-1;
01555   double workspace[32];
01556   double* space = workspace;
01557   double* free_space = NULL;
01558   if (order > 32){
01559     free_space = (double*)onmalloc(order*sizeof(double));
01560     space = free_space;
01561   }
01562 
01563   int i, j, k;
01564 
01565   for (i=1; i<2*degree; i++){
01566     if (knot[i] - knot[i-1] < 0.0) return false;
01567   }
01568 
01569   if (knot[degree] - knot[degree-1] < ON_EPSILON)
01570     return false;
01571 
01572   for (i=0; i<cvdim; i++){ //do one coordinate at a time
01573 
01574     //load in cvs.
01575     cv = CV+i;
01576     for (j=0; j<order; j++){
01577       space[j] = *cv; //d0j
01578       cv+=cv_stride;
01579     }
01580 
01581     for (j=1; j<order; j++){
01582       for (k=j; k<order; k++){//djk
01583         space[k-j] = (knot[degree+k-j]-t[j-1])/(knot[degree+k-j]-knot[k-1])*space[k-j] +
01584           (t[j-1]-knot[k-1])/(knot[degree+k-j]-knot[k-1])*space[k-j+1];
01585       }
01586     }
01587 
01588     P[i] = space[0];
01589   }
01590 
01591   if (free_space) onfree((void*)free_space);
01592   return true;
01593 }
01594 
01595 
01596 void ON_ConvertNurbSpanToBezier(int cvdim, int order, 
01597                                 int cvstride, double *cv, 
01598                                 const double *knot, double t0, double t1)
01599 /* 
01600  * Convert a Nurb span to a Bezier
01601  *
01602  * INPUT:
01603  *   cvdim
01604  *      (>= 1) 
01605  *   order
01606  *      (>= 2)
01607  *   cv
01608  *      array of order*cvdim doubles that define the Nurb
01609  *      span's control vertices
01610  *   knot
01611  *      array of (2*order - 2) doubles the define the Nurb
01612  *      span's knot vector.  The array should satisfiy
01613  *      knot[0] <= ... <= knot[order-2] < knot[order-1] 
01614  *      <= ... <= knot[2*order-3]
01615  *   t0, t1
01616  *      The portion of the Nurb span to convert to a Bezier.
01617  *      (t0 < t1)
01618  *
01619  * OUTPUT:
01620  *   TL_ConvNurbToBezier()
01621  *       0: successful
01622  *      -1: failure
01623  *   cv
01624  *      Control vertices for the Bezier.
01625  *
01626  * COMMENTS:
01627  *   If you want to convert the entire
01628  *   span to a Bezier, set t0 = knots[order-2] and
01629  *   t1 = knots[order-1].  
01630  *
01631  *   If you want to extend the left end of the span a bit,
01632  *   set t0 = knots[order-2] - a_bit and t1 = knots[order-1].
01633  *
01634  *   If you want to extend the right end of the span a bit,
01635  *   set t0 = knots[order-2] and t1 = knots[order-1] + a_bit.
01636  *
01637  * EXAMPLE:
01638  *   // ...
01639  *
01640  * REFERENCE:
01641  *   BOHM-01, Page 7.
01642  *
01643  * RELATED FUNCTIONS:
01644  *   TL_EvdeBoor(), TL_ConvertBezierToPolynomial
01645  */
01646 {
01647   ON_EvaluateNurbsDeBoor(cvdim,order,cvstride,cv,knot, 1, 0.0, t0);
01648   ON_EvaluateNurbsDeBoor(cvdim,order,cvstride,cv,knot,-2,  t0, t1);
01649 }
01650 


pcl
Author(s): Open Perception
autogenerated on Wed Aug 26 2015 15:27:01