opennurbs_knot.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 
00020 //
00021 // Computes tolerance associated with a generic evaluation domain
00022 //
00023 
00024 double ON_DomainTolerance( double a, double b )
00025 {
00026   if ( a == b )
00027     return 0.0;
00028   double tol = (fabs(a)+fabs(b)+fabs(a-b))* ON_SQRT_EPSILON;
00029   if ( tol <  ON_EPSILON )
00030     tol =  ON_EPSILON;
00031   return tol;
00032 }
00033 
00035 //
00036 // Computes tolerance associated with knot[i]
00037 //
00038 
00039 double ON_KnotTolerance( int order, int cv_count, const double* knot, 
00040                                     int knot_index )
00041 {
00042   const int knot_count = ON_KnotCount( order, cv_count );
00043   int i0, i1, j;
00044   double a, b, tol;
00045   i0 = knot_index-order+1;
00046   if ( i0 < 0 )
00047     i0 = 0;
00048   i1 = knot_index+order-1;
00049   if ( i1 >= knot_count )
00050     i1 = knot_count-1;
00051   for ( j = knot_index; j > i0; j-- ) {
00052     if ( knot[j] != knot[knot_index] )
00053       break;
00054   }
00055   a = fabs(knot[knot_index] - knot[j]);
00056   for ( j = knot_index; j < i1; j++ ) {
00057     if ( knot[j] != knot[knot_index] )
00058       break;
00059   }
00060   b = fabs(knot[knot_index] - knot[j]);
00061   tol = (a==0.0 && b==0.0) ? 0.0 : (a + b + fabs(knot[knot_index]))* ON_SQRT_EPSILON;
00062   return tol;
00063 }
00064 
00066 //
00067 // Computes tolerance associated with span of a knot vector
00068 //
00069 
00070 double ON_SpanTolerance( int order, int cv_count, const double* knot, int span_index )
00071 {
00072   const int i0 = span_index+order-2;
00073   return ON_DomainTolerance( knot[i0], knot[i0+1] );
00074 }
00075 
00077 //
00078 // Computes number of knots in knot vector
00079 //
00080 
00081 int ON_KnotCount( int order, int cv_count )
00082 {
00083   return (order+cv_count-2);
00084 }
00085 
00087 //
00088 // Computes number of knots in knot vector
00089 //
00090 
00091 int ON_KnotMultiplicity(
00092           int order,          // order (>=2)
00093           int cv_count,       // cv_count (>=order)
00094           const double* knot, // knot[]
00095           int knot_index      // knot_index
00096           )
00097 {
00098   int knot_count = order+cv_count-2;
00099   int km = 0;
00100   if ( knot && knot_index >= 0 && knot_index < knot_count ) {
00101     while(knot_index > 0 && knot[knot_index] == knot[knot_index-1])
00102       knot_index--;
00103     knot += knot_index;
00104     knot_count -= knot_index;
00105     km = 1;
00106     while ( km < knot_count && knot[0] == knot[km] )
00107       km++;
00108   }
00109   return km;
00110 }
00111 
00113 //
00114 // Computes number of non-empty spans
00115 //
00116 
00117 int ON_KnotVectorSpanCount(
00118           int order,         // order (>=2)
00119           int cv_count,      // cv count
00120           const double* knot // knot[] array
00121           )
00122 {
00123   if ( 0 == knot )
00124   {
00125     if ( 0 != order || 0 != cv_count )
00126     {
00127       ON_ERROR("NULL knot[] passed to ON_KnotVectorSpanCount.");
00128     }
00129     return 0;
00130   }
00131   int i, span_count = 0;
00132   for ( i = order-1; i < cv_count; i++ ) {
00133     if ( knot[i] > knot[i-1] )
00134       span_count++;
00135   }
00136   return span_count;
00137 }
00138 
00140 //
00141 // Gets span vector from knot vector
00142 //
00143 
00144 bool ON_GetKnotVectorSpanVector(
00145           int order,          // order (>=2)
00146           int cv_count,       // cv count
00147           const double* knot, // knot[] array
00148           double* s           // s[] array
00149           )
00150 {
00151   if ( 0 == knot || 0 == s )
00152   {
00153     if ( 0 != order || 0 != cv_count )
00154     {
00155       ON_ERROR("NULL knot[] or s[] passed to ON_KnotVectorSpanCount.");
00156       return false;
00157     }
00158     return true;
00159   }
00160 
00161   int i, span_count = 0;
00162   s[span_count++] = knot[order-2];
00163   for ( i = order-1; i < cv_count; i++ ) {
00164     if ( knot[i] > knot[i-1] )
00165       s[span_count++] = knot[i];
00166   }
00167   return (span_count>1) ? true : false;
00168 }
00169 
00170 
00172 //
00173 // Computes span index for evaluation of parameter
00174 //
00175 
00176 int ON_NurbsSpanIndex(
00177           int order,          // (>=2)
00178           int cv_count,
00179           const double* knot, // knot[] array or length ON_KnotCount(order,cv_count)
00180           double t,           // evaluation parameter
00181           int side,           // side 0 = default, -1 = from below, +1 = from above
00182           int hint            // hint (or 0 if no hint available)
00183           )
00184 {
00185   int j, len;
00186   
00187   // shift knot so that domain is knot[0] to knot[len]
00188   knot += (order-2);
00189   len = cv_count-order+2;
00190   
00191   // see if hint helps 
00192   if (hint > 0 && hint < len-1) {
00193     while(hint > 0 && knot[hint-1] == knot[hint]) hint--;
00194     if (hint > 0) {
00195       // have knot[hint-1] < knot[hint]
00196       if (t < knot[hint]) {
00197         len = hint+1;
00198         hint = 0;
00199       }
00200       else {
00201         if (side < 0 && t == knot[hint]) 
00202           hint--;
00203         knot += hint;
00204         len -= hint;
00205       }
00206     }
00207   }
00208   else
00209     hint = 0;
00210   
00211   j = ON_SearchMonotoneArray(knot,len,t);
00212   if (j < 0)
00213     j = 0;
00214   else if (j >= len-1)
00215     j = len-2;
00216   else if (side < 0) {
00217     // if user wants limit from below and t = an internal knot,
00218     // back up to prevous span
00219     while(j > 0 && t == knot[j]) 
00220       j--;
00221   }
00222   return (j + hint);
00223 }
00224 
00225 
00226 int ON_NextNurbsSpanIndex( int order, int cv_count, const double* knot, int span_index )
00227 
00228 /*
00229 Get index of next non-degenerate NURBS span
00230  
00231 INPUT:
00232   order, cv_count, knot
00233     knot vector
00234   span_index
00235     current span index ( >= 0 and <= cv_count-order )
00236 OUTPUT:
00237   i = ON_NextNurbsSpanIndex()
00238     i>=0: successful - the index of the next span or
00239                        cv_count-order if the input value
00240                        was cv_count-or
00241                        knot[i+order-2] < knot[i+order-1]
00242    <0: failure
00243    
00244 COMMENTS:
00245   The first span in a NURBS has span_index = 0.  The last span in a NURBS
00246   has span_index = cv_count-order.
00247   A span of a degree d NURBS is defined by d+1 CVs and 2*d knots.  For a
00248   given span_index, the associated knots and CVs are
00249     {knot[span_index], ..., knot[span_index+2*d-1]}
00250   and
00251     {CV[span_index], ..., CV[span_index + d]}
00252   The domain of the span is 
00253     [ knot[span_index+order-2], knot[span_index+order-1] ].
00254 
00255 EXAMPLE:
00256   // print the values of all distinct knots in a NURBS's domain
00257   int span_index = 0;
00258   int next_span_index = 0;
00259   for (;;) {
00260     printf( "knot[%2d] = %g\n", span_index+order-2, knot[span_index+order-2] );
00261     next_span_index =ON_NextNurbsSpanIndex( order, cv_count, knot, span_index );
00262     if ( next_span_index < 0 )
00263       break; // illegal input
00264     if ( next_span_index == span_index ) {
00265       // end of the domain
00266       printf( "knot[%2d] = %g\n", cv_count-1, knot[cv_count-1] );
00267       break;
00268     }
00269     next_span_index = span_index;
00270   }
00271 
00272   */
00273 
00274 {
00275 
00276   if (span_index < 0 || span_index > cv_count-order || !knot)
00277     return -1;
00278 
00279   if ( span_index < cv_count-order ) {
00280     do {
00281       span_index++;
00282     }
00283     while ( span_index < cv_count-order && 
00284             knot[span_index+order-2] == knot[span_index+order-1] );
00285   }
00286   return span_index;
00287 }
00288 
00289 
00290 int ON_GetSpanIndices(int order, 
00291                             int cv_count, 
00292                             const double* knot, 
00293                             int* span_indices)
00294 
00295 /* span_indices should have size greater than the number of 
00296    spans (cv_count is big enough).
00297 
00298   returns span count.
00299   fills in span_indices with index of last in each bunch of multiple knots at 
00300   start of span, and first in buch at end of nurb.
00301 
00302 
00303   */
00304 {
00305   int span_index, next_span_index, j;
00306 
00307   span_index = -1;
00308   next_span_index = 0;
00309   j = 0;
00310   while (span_index != next_span_index) {
00311     span_index = next_span_index;
00312     span_indices[j] = span_index + order - 2;
00313     next_span_index = ON_NextNurbsSpanIndex(order, cv_count, knot, span_index);
00314     if (next_span_index < 0) 
00315       return next_span_index;
00316     j++;
00317   } 
00318   
00319   span_indices[j] = span_index + order - 1;
00320 
00321   return j;
00322 }
00323 
00324 
00326 //
00327 // Computes value for superfluous knot used in systems like OpenGL and 3dsMax
00328 //
00329 
00330 double ON_SuperfluousKnot( 
00331                     int order, int cv_count, const double* knot,
00332                     int end )
00333 {
00334   double k;
00335   const int knot_count = order+cv_count-2;
00336   // gets superfluous knot for translation to other formats
00337   k = knot[(end) ? knot_count-1 : 0];
00338   if (order > 2 && cv_count >= 2*order - 2 && cv_count >= 6 ) {
00339     // check for non-clamped knots
00340     if (end) {
00341       if ( knot[cv_count-1] < knot[knot_count-1] )
00342         k += (knot[order+1] - knot[order]);
00343     }
00344     else {
00345       if ( knot[0] < knot[order-2] )
00346         k -= (knot[cv_count-order+1] - knot[cv_count-order]);
00347     }
00348   }
00349   return k;
00350 }
00351 
00353 //
00354 // Used to determine when a knot vector is periodic
00355 //
00356 
00357 bool ON_IsKnotVectorPeriodic(
00358        int order,
00359        int cv_count,
00360        const double* knot
00361        )
00362 
00363 {
00364   double tol;
00365   const double* k1;
00366   int i;
00367 
00368   if ( order < 2 || cv_count < order || !knot ) {
00369     ON_ERROR("ON_IsKnotVectorPeriodic(): illegal input");
00370     return false;
00371   }
00372   
00373   if ( order == 2 )
00374     return false; // convention is that degree 1 curves cannot be periodic.
00375 
00376   if (order <= 4) {
00377     if (cv_count < order+2) 
00378       return false;
00379   }
00380   else if ( cv_count < 2*order-2 ) {
00381     return false;
00382   }
00383 
00384   tol = fabs(knot[order-1] - knot[order-3])* ON_SQRT_EPSILON;
00385   if (tol < fabs(knot[cv_count-1] - knot[order-2])* ON_SQRT_EPSILON) 
00386     tol = fabs(knot[cv_count-1] - knot[order-2])* ON_SQRT_EPSILON;
00387   k1 = knot+cv_count-order+1;
00388   i = 2*(order-2);
00389   while(i--) {
00390     if (fabs(knot[1] - knot[0] + k1[0] - k1[1]) > tol)
00391       return false;
00392     knot++; k1++;
00393   }
00394   return true;
00395 }
00396 
00398 //
00399 // Used to determine when a knot vector is clamped
00400 //
00401 
00402 bool ON_IsKnotVectorClamped(
00403        int order,
00404        int cv_count,
00405        const double* knot,
00406        int end // (default = 2) 0 = left end, 1 = right end, 2 = both
00407        )
00408 
00409 {
00410   if ( order <= 1 || cv_count < order || !knot || end < 0 || end > 2 )
00411     return false;
00412   bool rc = true;
00413   if ( (end == 0 || end == 2) && knot[0] != knot[order-2] )
00414     rc = false;
00415   if ( (end == 1 || end == 2) && knot[cv_count-1] != knot[order+cv_count-3] )
00416     rc = false;
00417   return rc;
00418 }
00419 
00420 bool ON_IsKnotVectorUniform(
00421           int order,
00422           int cv_count,
00423           const double* knot 
00424           )
00425 {
00426   bool rc = (order >= 2 && cv_count >= order && 0 != knot);
00427   if (rc)
00428   {
00429     const double delta = knot[order-1] - knot[order-2];
00430     const double delta_tol = ON_SQRT_EPSILON*delta;
00431     int i0, i1;
00432     double d;
00433     if ( ON_IsKnotVectorClamped(order,cv_count,knot) )
00434     {
00435       i0 = order;
00436       i1 = cv_count;
00437     }
00438     else
00439     {
00440       i0 = 1;
00441       i1 = ON_KnotCount(order,cv_count);
00442     }
00443     for (/*empty*/; i0 < i1 && rc; i0++ )
00444     {
00445       d = knot[i0] - knot[i0-1];
00446       if ( fabs(d - delta) > delta_tol )
00447         rc = false;
00448     }
00449   }
00450   return rc;
00451 }
00452 
00454 //
00455 // Used to determine properties of knot vector
00456 //
00457 
00458 bool ON_KnotVectorHasBezierSpans(
00459           int order,          // order (>=2)
00460           int cv_count,       // cv count
00461           const double* knot  // knot[] array
00462           )
00463 {
00464   int knot_count = ON_KnotCount( order, cv_count );
00465   if ( knot_count < 2 )
00466     return false;
00467   int span_count = ON_KnotVectorSpanCount( order, cv_count, knot );
00468   if ( span_count < 1 )
00469     return false;
00470   if ( order >= 2 && 
00471        cv_count >= order && 
00472        knot_count == (span_count+1)*(order-1) && 
00473        knot[0] == knot[order-2] && knot[cv_count-1] == knot[knot_count-1])
00474     return true;
00475   return false;
00476 }
00477 
00479 //
00480 // Used to determine properties of knot vector
00481 //
00482 
00483 ON::knot_style ON_KnotVectorStyle( 
00484        int order,
00485        int cv_count,
00486        const double* knot
00487        )
00488 {
00489   ON::knot_style s = ON::unknown_knot_style;
00490   if ( order >= 2 && cv_count >= order && knot && knot[order-2] < knot[cv_count-1] ) {
00491     const int knot_count = order+cv_count-2;
00492     const double delta = 0.5*((knot[order-1] - knot[order-2]) + (knot[cv_count-1] - knot[cv_count-2]));
00493     const double ktol = delta*1.0e-6;
00494     int i;
00495     if ( ON_IsKnotVectorClamped( order, cv_count, knot ) ) {
00496       if ( order == cv_count ) {
00497         s = ON::piecewise_bezier_knots;
00498       }
00499       else {
00500         s = ON::clamped_end_knots;
00501         for ( i = order-1; i <= cv_count-1; i++ ) {
00502           if ( fabs(knot[i] - knot[i-1] - delta) > ktol ) {
00503             break;
00504           }
00505         }
00506         if ( i >= cv_count ) {
00507           s = ON::quasi_uniform_knots;
00508         }
00509         else {
00510           const int degree = order-1;
00511           for ( i = order-1; i < cv_count-1; i += degree ) {
00512             if ( knot[i] != knot[i+degree-1] )
00513               break; 
00514           }
00515           if ( i >= cv_count-1 )
00516             s = ON::piecewise_bezier_knots;
00517         }
00518       }
00519     }
00520     else {
00521       // check for uniform knots
00522       s = ON::non_uniform_knots;
00523       for ( i = 1; i < knot_count; i++ ) {
00524         if ( fabs(knot[i] - knot[i-1] - delta) > ktol ) {
00525           break;
00526         }
00527       }
00528       if ( i >= knot_count )
00529         s = ON::uniform_knots; 
00530     }
00531   }
00532   return s;
00533 }
00534 
00535 
00537 //
00538 // Used to set the domain of a knot vector
00539 //
00540 
00541 bool ON_SetKnotVectorDomain( int order, int cv_count, double* knot, double t0, double t1 )
00542 {
00543   bool rc = false;
00544   if ( order < 2 || cv_count < order || 0 == knot || t0 >= t1 || !ON_IsValid(t0) || !ON_IsValid(t1) )
00545   {
00546     ON_ERROR("ON_SetKnotVectorDomain - invalid input");
00547   }
00548   else if (    knot[order-2] >= knot[cv_count-1] 
00549             || !ON_IsValid(knot[order-2]) 
00550             || !ON_IsValid(knot[cv_count-2]) )
00551   {
00552     ON_ERROR("ON_SetKnotVectorDomain - invalid input knot vector");
00553   }
00554   else
00555   {
00556     const ON_Interval oldd(knot[order-2],knot[cv_count-1]);
00557     const ON_Interval newd(t0,t1);
00558     if ( oldd != newd )
00559     {
00560       int i, knot_count = ON_KnotCount(order,cv_count);
00561       for ( i = 0; i < knot_count; i++ )
00562       {
00563         knot[i] = newd.ParameterAt(oldd.NormalizedParameterAt(knot[i]));
00564       }
00565     }
00566     rc = true;
00567   }
00568   return rc;
00569 }
00570 
00571 
00573 //
00574 // Used to get the domain of a knot vector
00575 //
00576 
00577 bool ON_GetKnotVectorDomain(
00578        int order,
00579        int cv_count,
00580        const double* knot,
00581        double* k0, double* k1
00582        )
00583 {
00584   if ( order < 2 || cv_count < order || knot == NULL )
00585     return false;
00586   if ( k0 )
00587     *k0 = knot[order-2];
00588   if ( k1 )
00589     *k1 = knot[cv_count-1];
00590   return true;
00591 }
00592 
00594 //
00595 // Used to reverse knot vectors
00596 //
00597 
00598 bool ON_ReverseKnotVector(
00599        int order,
00600        int cv_count,
00601        double* knot
00602        )
00603 {
00604   if ( order < 2 || cv_count < order || knot == NULL )
00605     return false;
00606   const int knot_count = (order+cv_count-2);
00607   double t;
00608   int i, j;
00609   for ( i = 0, j = knot_count-1; i <= j; i++, j-- ) {
00610     t = knot[i];
00611     knot[i] = -knot[j];
00612     knot[j] = -t;
00613   }
00614   return true;
00615 }
00616 
00618 //
00619 // Used to compare knot vectors
00620 //
00621 
00622 int ON_CompareKnotVector( // returns 
00623                                       // -1: first < second
00624                                       //  0: first == second
00625                                       // +1: first > second
00626           int orderA,
00627           int cv_countA,
00628           const double* knotA,
00629           int orderB,
00630           int cv_countB,
00631           const double* knotB
00632           )
00633 {
00634   const int knot_count = ON_KnotCount(orderA,cv_countA);
00635   int i;
00636   double a, b, atol, btol, ktol, tol;
00637   if ( orderA < orderB )
00638     return -1;
00639   if ( orderA > orderB )
00640     return 1;
00641   if ( cv_countA < cv_countB )
00642     return -1;
00643   if ( cv_countA > cv_countB )
00644     return 1;
00645 
00646   if ( !ON_GetKnotVectorDomain( orderA, cv_countA, knotA, &a, &b ) )
00647     return -1;
00648   atol = ON_DomainTolerance( a, b );
00649   if ( !ON_GetKnotVectorDomain( orderA, cv_countA, knotA, &a, &b ) )
00650     return 1;
00651   btol = ON_DomainTolerance( a, b );
00652   tol = (atol <= btol) ? atol : btol;
00653 
00654   for ( i = 0; i < knot_count; i++ ) {
00655     a = knotA[i];
00656     b = knotB[i];
00657     if ( a == b )
00658       continue;
00659     if ( a < b-tol )
00660       return -1;
00661     if ( b < a-tol )
00662       return 1;
00663     atol = ON_KnotTolerance( orderA, cv_countA, knotA, i );
00664     btol = ON_KnotTolerance( orderB, cv_countB, knotB, i );
00665     ktol = (atol <= btol) ? atol : btol;
00666     if ( a < b-ktol )
00667       return -1;
00668     if ( b < a-ktol )
00669       return 1;
00670   }
00671   return 0;
00672 }
00673 
00675 //
00676 // Used to validate knot vectors
00677 //
00678 
00679 static bool ON_KnotVectorIsNotValid(bool bSilentError)
00680 {
00681   return bSilentError ? false : ON_IsNotValid(); // <-- good place for a breakpoint
00682 }
00683 
00684 bool ON_IsValidKnotVector( int order, int cv_count, const double* knot, ON_TextLog* text_logx )
00685 {
00686   // If low bit of text_log pointer is 1, then ON_Error is not called when the
00687   // knot vector is invalid.
00688   const ON__INT_PTR lowbit = 1;
00689   const ON__INT_PTR hightbits = ~lowbit;
00690   bool bSilentError = ( 0 != (lowbit & ((ON__INT_PTR)text_logx)) );
00691   ON_TextLog* text_log = (ON_TextLog*)(((ON__INT_PTR)text_logx) & hightbits);
00692 
00693   const double *k0, *k1;
00694   int i;
00695   if ( order < 2 )
00696   {
00697     if ( text_log )
00698     {
00699       text_log->Print("Knot vector order = %d (should be >= 2 )\n",order);
00700     }
00701     return ON_KnotVectorIsNotValid(bSilentError);
00702   }
00703   if ( cv_count < order )
00704   {
00705     if ( text_log )
00706     {
00707       text_log->Print("Knot vector cv_count = %d (should be >= order=%d )\n",cv_count,order);
00708     }
00709     return ON_KnotVectorIsNotValid(bSilentError);
00710   }
00711   if ( knot == NULL )
00712   {
00713     if ( text_log )
00714     {
00715       text_log->Print("Knot vector knot array = NULL.\n");
00716     }
00717     return ON_KnotVectorIsNotValid(bSilentError);
00718   }
00719 
00720   for ( i = 0; i < cv_count+order-2; i++ )
00721   {
00722     if ( !ON_IsValid(knot[i]) )
00723     {
00724       if ( text_log )
00725       {
00726         text_log->Print("Knot vector knot[%d]=%g is not valid.\n",i,knot[i]);
00727       }
00728       return ON_KnotVectorIsNotValid(bSilentError);
00729     }
00730   }
00731 
00732   if ( !(knot[order-2] < knot[order-1]) )
00733   {
00734     if ( text_log )
00735     {
00736       text_log->Print("Knot vector order=%d and knot[%d]=%g >= knot[%d]=%g (should have knot[order-2] < knot[order-1]).\n",
00737                        order,order-2,knot[order-2],order-1,knot[order-1]);
00738     }
00739     return ON_KnotVectorIsNotValid(bSilentError);
00740   }
00741   if ( !(knot[cv_count-2] < knot[cv_count-1]) )
00742   {
00743     if ( text_log )
00744     {
00745       text_log->Print("Knot vector cv_count=%d and knot[%d]=%g >= knot[%d]=%g (should have knot[cv_count-2] < knot[cv_count-1]).\n",
00746                        cv_count,cv_count-2,knot[cv_count-2],cv_count-1,knot[cv_count-1]);
00747     }
00748     return ON_KnotVectorIsNotValid(bSilentError);
00749   }
00750 
00751   // entire array must be monotone increasing
00752   k0 = knot;
00753   k1 = knot+1;
00754   i = order + cv_count - 3;
00755   while (i--) {
00756     if ( !(*k1 >= *k0) )
00757     {
00758       if ( text_log )
00759       {
00760         text_log->Print("Knot vector must be increasing but knot[%d]=%g > knot[%d]=%g\n",
00761                          order+cv_count-4-i, *k0, order+cv_count-3-i, *k1 );
00762       }
00763       return ON_KnotVectorIsNotValid(bSilentError);
00764     }
00765     k0++;
00766     k1++;
00767   }
00768 
00769   // must have knot[i+order-1] > knot[i]
00770   k0 = knot;
00771   k1 = knot + order - 1;
00772   i = cv_count-1;
00773   while(i--) {
00774     if ( !(*k1 > *k0) )
00775     {
00776       if ( text_log )
00777       {
00778         text_log->Print("Knot vector order = %d but knot[%d]=%g >= knot[%d]=%g\n",
00779                          order, cv_count-2-i, *k0, cv_count-1-i, *k1 );
00780       }
00781       return ON_KnotVectorIsNotValid(bSilentError);
00782     }
00783     k0++;
00784     k1++;
00785   }
00786 
00787   return true;
00788 }
00789 
00790 
00791 bool ON_ClampKnotVector(
00792           int order,          // order (>=2)
00793           int cv_count,       // cv count
00794           double* knot,       // knot[] array
00795           int end             // 0 = clamp start, 1 = clamp end, 2 = clamp both ends
00796           )
00797 {
00798   // sets initial/final order-2 knot values to match knot[order-2]/knot[cv_count-1]
00799   bool rc = false;
00800   int i, i0;
00801   if ( knot && order >= 2 && cv_count >= order ) {
00802     if ( end == 0 || end == 2 ) {
00803       i0 = order-2;
00804       for ( i = 0; i < i0; i++ ) {
00805         knot[i] = knot[i0];
00806       }
00807       rc = true;
00808     }
00809     if ( end == 1 || end == 2 ) {
00810       const int knot_count = ON_KnotCount(order,cv_count);
00811       i0 = cv_count-1;
00812       for ( i = i0+1; i < knot_count; i++ ) {
00813         knot[i] = knot[i0];
00814       }
00815       rc = true;
00816     }
00817   }
00818   return rc;
00819 }
00820 
00821 
00822 bool ON_MakeKnotVectorPeriodic(
00823           int order,          // order (>=2)
00824           int cv_count,       // cv count (>= (order>=4) ? 2*(order-1) : 5)
00825           double* knot        // knot[] array
00826           )
00827 {
00828   double *k0, *k1;
00829   int i;
00830   
00831   if ( order < 2 || cv_count < order || !knot ) {
00832     ON_ERROR("ON_MakePeriodicKnotVector(): illegal input");
00833     return false;
00834   }
00835 
00836   switch(order) {
00837   case 2:
00838     if ( cv_count < 4 ) {
00839       ON_ERROR("ON_MakePeriodicKnotVector(): illegal input degree=1, cv_count<4");
00840       return false;
00841     }
00842     else {
00843       return true;
00844     }
00845     break;
00846   case 3:
00847     if ( cv_count < 4 ) {
00848       ON_ERROR("ON_MakePeriodicKnotVector(): illegal input degree=2, cv_count<5");
00849       return false;
00850     }
00851     break;
00852   default:
00853     if ( cv_count < 2*order-2 ) {
00854       ON_ERROR("ON_MakePeriodicKnotVector(): illegal input degree>=3, cv_count<2*degree");
00855       return false;
00856     }
00857     break;
00858   }
00859 
00860   k0 = knot + order-2;
00861   k1 = knot + cv_count-1;
00862   i = order-2;
00863   while (i--) {
00864     k1[1] = k0[1]-k0[0]+k1[0];
00865     k0++; k1++;
00866   }
00867   k0 = knot + order-2;
00868   k1 = knot + cv_count-1;
00869   i = order-2;
00870   while (i--) {
00871     k0[-1] = k1[-1] - k1[0] + k0[0];
00872     k0--; 
00873     k1--;
00874   }
00875   return true;
00876 }
00877 
00878 ON_DECL
00879 bool ON_MakeClampedUniformKnotVector(
00880           int order,
00881           int cv_count,
00882           double* knot,
00883           double delta
00884           )
00885 {
00886   bool rc = false;
00887   if ( order >= 2 && cv_count >= order && knot != NULL && delta > 0.0 )
00888   {
00889     double k;
00890     int i;
00891     for ( i = order-2, k = 0.0; i < cv_count; i++, k += delta )
00892       knot[i] = k;
00893     ON_ClampKnotVector(order,cv_count,knot,2);
00894     rc = true;
00895   }
00896   return rc;
00897 }
00898 
00899 // Description:
00900 //   Fill in knot values for a clamped uniform knot
00901 //   vector.
00902 // Parameters:
00903 //   order - [in] (>=2) order (degree+1) of the NURBS
00904 //   cv_count - [in] (>=order) total number of control points
00905 //       in the NURBS.
00906 //   knot - [in/out] Input is an array with room for 
00907 //       ON_KnotCount(order,cv_count) doubles.  Output is
00908 //       a periodic uniform knot vector with domain
00909 //       (0, (1+cv_count-order)*delta).
00910 //   delta - [in] (>0, default=1.0) spacing between knots.
00911 // Returns:
00912 //   true if successful
00913 ON_DECL
00914 bool ON_MakePeriodicUniformKnotVector(
00915           int order,
00916           int cv_count,
00917           double* knot,
00918           double delta
00919           )
00920 {
00921   bool rc = false;
00922   if ( order >= 2 && cv_count >= order && knot != NULL && delta > 0.0 )
00923   {
00924     double k = 0.0;
00925     int i, knot_count = ON_KnotCount(order,cv_count);
00926     for ( i = order-2, k = 0.0; i < knot_count; i++, k += delta )
00927       knot[i] = k;
00928     for ( i = order-3, k = -delta; i >= 0; i--, k -= delta )
00929       knot[i] = k;
00930     rc = true;
00931   }
00932   return rc;
00933 }
00934 
00935 
00936 
00937 double ON_GrevilleAbcissa( // get Greville abcissa
00938           int order,          // order (>=2)
00939           const double* knot  // knot[order-1] array
00940           )
00941 {
00942   double g=0.0;
00943   if ( order <= 2 || knot[0] == knot[order-2]) {
00944     g = knot[0]; // degree = 1 or fully multiple knot
00945   }
00946   else {
00947     // g = (knot[i]+...+knot[i+degree-1])/degree
00948     order--;
00949     const double k = knot[order/2];
00950     const double tol = (knot[order-1]-knot[0]);
00951     const double d = 1.0/((double)order);
00952     while ( order--) {
00953       g += *knot++;
00954     }
00955     g *= d;
00956     if ( fabs(g-k) <= (fabs(g)+tol)* ON_SQRT_EPSILON )
00957       g = k; // sets g to exact value when knot vector is uniform
00958   }
00959   return g;
00960 }
00961 
00962 
00963 bool ON_GetGrevilleAbcissae( // get Greville abcissa from knots
00964           int order,          // order (>=2)
00965           int cv_count,       // cv count (>=order)
00966           const double* knot, // knot[] array
00967           bool bPeriodic,
00968           double* g           // has length cv_count in non-periodic case
00969                               // and length cv_count-order+1 in periodic case
00970           )
00971 {
00972   // Grevielle abscissae for a given knot vector
00973   double x, t0; 
00974   int gi, periodic_check;
00975 
00976   if ( order < 2 || cv_count < order || !knot || !g )
00977     return false;
00978   
00979   const int g_count = (bPeriodic) ? cv_count-order+1 : cv_count;
00980   
00981   if (order == 2) {
00982     // g[i] = knot[i] in degree 1 case
00983     memcpy( g, knot, g_count*sizeof(*g) );
00984   }    
00985   else {
00986     // g = (knot[i]+...+knot[i+degree-1])/degree
00987     t0 = knot[order-2];
00988     gi = 0;
00989     periodic_check = (bPeriodic) ? order-2 : 0;
00990     while (gi < g_count) {
00991       x = ON_GrevilleAbcissa( order, knot++ );
00992       if ( periodic_check ) {
00993         periodic_check--;
00994         if ( x < t0 )
00995           continue;
00996       }
00997       g[gi++] = x;
00998     }
00999   }
01000   
01001   return true;
01002 }
01003 
01004 
01005 bool ON_GetGrevilleKnotVector( // get knots from Greville abcissa
01006           int g_stride,     
01007           const double *g,  // if not periodic, g[cv_count], 
01008                             // if periodic, g[cv_count-order+2]
01009                             // usually, g[0] = 0, g[i] = |P[i]-P[i-1]|^q
01010           bool bPeriodic,
01011           int order, 
01012           int cv_count, 
01013           double* knot
01014           )
01015 {
01016   bool rc = false;
01017   double* p = NULL;
01018   int ki, knot_count, g_count, gi, j, degree;
01019   double k, dd;
01020 
01021   if ( g_stride < 1 || !g || !knot || order < 2 || cv_count < order )
01022     return false;
01023   if ( bPeriodic && order == 2 )
01024     return false;
01025   if ( bPeriodic && cv_count - order + 2 < 3 )
01026     return false;
01027 
01028   degree = order-1;
01029   if ( degree == 1 ) {
01030     for ( j = 0; j < cv_count; j++ ) {
01031       knot[j] = g[j*g_stride];
01032     }
01033     return true;
01034   }
01035   dd = 1.0/degree;
01036   knot_count = ON_KnotCount( order, cv_count );
01037   g_count = (bPeriodic) ? cv_count-order+2 : cv_count;
01038 
01039   if ( bPeriodic ) {
01040     int half_degree = (degree%2) ? degree/2 : 0;
01041     // step 1: set p[] = fully periodic list of abcissa
01042     p = (double*)onmalloc((g_count + 2*degree)*sizeof(*p));
01043     for ( j = 0, gi = g_count-order; j < degree; j++, gi++ ) {
01044       p[j] = g[0] - g[g_count-1] + g[gi];
01045     }
01046     for ( gi = 0, j = degree; gi < g_count; gi++, j++ ) {
01047       p[j] = g[gi];
01048     }
01049     for ( j = g_count+degree, gi = 1; j < g_count+2*degree; j++, gi++ ) {
01050       p[j] = g[g_count-1] - g[0] + g[gi];
01051     }
01052 
01053     // step 2: set new p[i] = old (p[i] + ... + p[i+degree-1]) / degree
01054     for ( j = 0; j < g_count+order; j++ ) {
01055       k = p[j];
01056       for ( ki = 1; ki < degree; ki++ ) 
01057         k += p[j+ki];
01058       k *= dd;
01059       if ( half_degree ) {
01060         // if g[]'s are uniform and degree is odd, then knots = g[]'s
01061         if ( fabs(k-p[j+half_degree]) <=  ON_SQRT_EPSILON*(p[j+degree-1]-p[j]) )
01062           k = p[j+half_degree];
01063       }
01064       p[j] = k;
01065     }
01066 
01067     // step 3: determine where g[0] maximizes NURBS basis functions
01068     {
01069       double* B = (double*)alloca(order*order*sizeof(B[0]));
01070       double maxB  = 0.0;
01071       int maxBj = 0;
01072       for ( j = 0; j < 2*degree; j++ ) {
01073         if ( g[0] > p[j+degree] )
01074           continue;
01075         if ( g[0] < p[j+degree-1] )
01076           break;
01077         ON_EvaluateNurbsBasis( order, p+j, g[0], B );
01078         if ( B[0] > maxB ) {
01079           maxB  = B[0];
01080           maxBj = j;
01081         }
01082       }
01083       memcpy( knot, &p[maxBj], knot_count*sizeof(*knot) );
01084     }
01085 
01086     rc = ON_MakeKnotVectorPeriodic( order, cv_count, knot );
01087   }
01088   else {
01089     // clamped knots
01090     rc = true;
01091     if ( g > knot && g < knot+knot_count ) {
01092       p = (double*)onmalloc(cv_count*sizeof(*p));
01093       for( j = 0; j < cv_count; j++ ) {
01094         p[j] = g[j*g_stride];
01095       }
01096       g = p;
01097       g_stride = 1;
01098     }
01099     for ( ki = 0; ki < degree; ki++ ) {
01100       knot[ki] = g[0];
01101     }
01102     for ( ki = degree, gi = 1; ki < cv_count; ki++, gi++ ) {
01103       k = 0.0;
01104       for ( j = 0; j < degree; j++ ) {
01105         k += g[(gi+j)*g_stride];
01106       }
01107       knot[ki] = k*dd;
01108       if ( knot[ki] < knot[ki-1] || knot[ki] <= knot[ki-degree] ) {
01109         rc = false;
01110       }
01111     }
01112     for ( ki = cv_count-1; ki < knot_count; ki++ ) {
01113       knot[ki] = g[(cv_count-1)*g_stride];
01114     }
01115   }
01116 
01117   if (p)
01118     onfree(p);
01119   return rc;
01120 }
01121 
01122 bool ON_ClampKnotVector(
01123         int cv_dim,   // dimension of cv's = ( = dim+1 for rational cvs )
01124         int order, 
01125         int cv_count,
01126         int cv_stride, 
01127         double* cv,   // NULL or cv array with room for at least knot_multiplicity new cvs
01128         double* knot, // knot array with room for at least knot_multiplicity new knots
01129         int end       // 0 = clamp start, 1 = clamp end, 2 = clamp both ends
01130         )
01131 {
01132   // sets initial/final order-2 knot values to match knot[order-2]/knot[cv_count-1]
01133   bool rc = false;
01134   int i, i0;
01135 
01136   if ( knot && order >= 2 && cv_count >= order ) {
01137     if ( end == 0 || end == 2 ) {
01138       if ( cv ) {
01139         ON_EvaluateNurbsDeBoor(cv_dim,order,cv_stride,cv,knot,1,0.0,knot[order-2]);
01140       }
01141       i0 = order-2;
01142       for (i = 0; i < i0; i++)
01143         knot[i] = knot[i0];
01144       rc = true;
01145     }
01146     if ( end == 1 || end == 2 ) {
01147       i0 = cv_count-order;
01148       knot += i0;
01149       if ( cv ) {
01150         cv += i0*cv_stride;
01151         ON_EvaluateNurbsDeBoor(cv_dim,order,cv_stride,cv,knot,-1,0.0,knot[order-1]);
01152       }
01153       i0 = order-1;
01154       for (i = 2*order-3; i > i0; i--)
01155         knot[i] = knot[i0];
01156       rc = true;
01157     }
01158   }
01159   return rc;
01160 }
01161 
01162 
01163 static bool ON_InsertSingleKnot( int cv_dim, int order, 
01164                              int cv_stride, 
01165                              double *cv,   // NULL or array of length at least order*cv_stride+cv_dim
01166                              double *knot, // array of length at least 2*order-1 and existing knot values in
01167                                            // knot[0], ..., knot[2*order-3]
01168                              double knot_value // knot[order-2] <= knot_value < knot[order-1]
01169                                                // and knot[0] < knot_vale
01170                              )
01171 {
01172   double alpha0, alpha1;
01173   double *k0, *k1, *prev_cv;
01174   int    i, d, cv_inc, degree;
01175 
01176   if ( order < 2 || !knot || knot_value < knot[order-2] || knot[order-1] <= knot_value ) {
01177     ON_ERROR( "ON_InsertSingleKnot() - illegal knot input" );
01178     return false;
01179   }
01180 
01181   if ( cv ) {
01182     if ( cv_dim < 1 || cv_stride < cv_dim  ) {
01183       ON_ERROR( "ON_InsertSingleKnot() - illegal cv input" );
01184       return false;
01185     }
01186   }
01187 
01188   degree = order-1;
01189 
01190   // move last degree many knots over one spot
01191   k1 = knot + 2*degree;
01192   k0 = k1-1;
01193   i = degree;
01194   while (i--) 
01195     *k1-- = *k0--;
01196 
01197   // insert new knot value 
01198   *k1 = knot_value;
01199 
01200   if ( cv ) {
01201     // move last cv over one spot
01202     memcpy( cv+cv_dim*order, cv+cv_dim*degree, cv_dim*sizeof(*cv) );
01203 
01204     // compute new cv values
01205     k0 = knot + degree-1;
01206     k1 = k0 + order;
01207     cv += order*cv_stride;
01208     prev_cv = cv - cv_stride;
01209     cv_inc = cv_stride - cv_dim;
01210     i = degree;
01211     if (knot_value - *k0 <= *k1 - knot_value) {
01212       while (i--) {
01213         alpha1 = (knot_value - *k0)/(*k1 - *k0);
01214         alpha0 = 1.0 - alpha1;
01215         k0--; k1--;
01216         cv -= cv_inc;
01217         prev_cv -= cv_inc;
01218         d = cv_dim;
01219         while (d--) {
01220           --cv;
01221           --prev_cv;
01222           *cv = *cv * alpha1 + *prev_cv * alpha0;
01223         }
01224       }
01225     }
01226     else {
01227       while (i--) {
01228         alpha0 = (*k1 - knot_value)/(*k1 - *k0);
01229         alpha1 = 1.0 - alpha0;
01230         k0--; k1--;
01231         cv -= cv_inc;
01232         prev_cv -= cv_inc;
01233         d = cv_dim;
01234         while (d--) {
01235           --cv;
01236           --prev_cv;
01237           *cv = *cv * alpha1 + *prev_cv * alpha0;
01238         }
01239       }
01240     }
01241   }
01242     
01243   return true;
01244 }
01245 
01246 int ON_InsertKnot( 
01247         double knot_value, 
01248         int knot_multiplicity, 
01249         int cv_dim,   // dimension of cv's = ( = dim+1 for rational cvs )
01250         int order, 
01251         int cv_count,
01252         int cv_stride, 
01253         double* cv,   // NULL or cv array with room for at least knot_multiplicity new cvs
01254         double* knot, // knot array with room for at least knot_multiplicity new knots
01255         int* hint     // optional hint about where to search for span to add knots to
01256                       // pass NULL if no hint is available
01257         )
01258 {
01259   int rc = 0; // return code = number of knots added
01260 
01261   if ( order < 2 || cv_count < order || !knot ) 
01262   {
01263     ON_ERROR("ON_InsertKnot(): illegal input" );
01264     return 0;
01265   }
01266 
01267   if ( cv ) 
01268   {
01269     if ( cv_dim < 1 || cv_stride < cv_dim ) 
01270     {
01271       ON_ERROR("ON_InsertKnot(): illegal input" );
01272       return 0;
01273     }
01274   }
01275 
01276   if ( knot_multiplicity >= order ) 
01277   {
01278     ON_ERROR("ON_InsertKnot(): requested knot_multiplicity > degree" );
01279     return 0;
01280   }
01281 
01282   // shift knot vector and cv array so that knot_value lies in first span
01283   int span_index = ON_NurbsSpanIndex( order, cv_count, knot, knot_value, 1, hint?*hint:0 );
01284   knot += span_index;
01285   if ( cv )
01286     cv += (span_index*cv_stride);
01287   cv_count -= span_index;
01288 
01289   const double knot_tolerance = ON_SpanTolerance( order, cv_count, knot, 0 );
01290 
01291   // check that knot_value is interior to NURBS domain
01292   if ( span_index == 0 ) 
01293   {
01294     if ( knot_value < knot[order-1] ) 
01295     {
01296       if ( knot_value <= knot[order-2] + knot_tolerance ) 
01297       {
01298         ON_ERROR("ON_InsertKnot(): requested knot_value at start of NURBS domain" );
01299         return 0;
01300       }
01301     }
01302   }
01303   if ( span_index == cv_count-order ) 
01304   {
01305     if ( knot_value > knot[order-2] && knot_value >= knot[order-1] - knot_tolerance ) 
01306     {
01307       ON_ERROR("ON_InsertKnot(): requested knot_value at end of NURBS domain" );
01308       return 0;
01309     }
01310   }
01311 
01312   // if knot_value is nearly equal to an existing knot, make it exactly equal
01313   if ( knot_value <= 0.5*(knot[order-2]+knot[order-1]) && fabs( knot_value - knot[order-2] ) <= knot_tolerance ) {
01314     knot_value = knot[order-2];
01315   }
01316   else if ( fabs( knot_value - knot[order-1] ) <= knot_tolerance ) {
01317     knot_value = knot[order-1];
01318   }
01319 
01320   const int degree = order-1;
01321 
01322   // set m = number of knots to add
01323   int m = 0; 
01324   int j;
01325   if ( knot_value == knot[order-2] ) {
01326     for ( j = order-2; m < knot_multiplicity && knot[j-m] == knot_value; m++ )
01327       ; // empty for
01328   }
01329   else if ( knot_value == knot[order-1] ) {
01330     for ( j = order-1; m < knot_multiplicity && knot[j+m] == knot_value; m++ )
01331       ; // empty for
01332   }
01333   m = knot_multiplicity - m;
01334   if ( hint )
01335     *hint = span_index+m;
01336 
01337   if ( m <= 0 )
01338     return 0; // no knots need to be added
01339 
01340   double* new_knot = (double*)onmalloc( ((2*degree+m) + (order+m)*cv_dim)*sizeof(*new_knot) );
01341   if ( !new_knot ) {
01342     ON_ERROR("ON_InsertKnot(): out of memory");
01343     return 0;
01344   }
01345   double* new_cv = 0;
01346   memcpy( new_knot, knot, 2*degree*sizeof(*new_knot) );
01347   if ( cv ) {
01348     new_cv = new_knot + (2*degree+m);
01349     for ( j = 0; j < order; j++ ) {
01350       memcpy( new_cv + j*cv_dim, cv + j*cv_stride, cv_dim*sizeof(*new_cv) );
01351     }
01352   }
01353 
01354   // add m more knots at knot_value
01355   rc = 0;
01356   while (m>0) {
01357     if ( !ON_InsertSingleKnot(cv_dim,order,cv_dim,new_cv,new_knot,knot_value) )
01358       break;
01359     m--;
01360     if ( new_cv )
01361       new_cv += cv_stride; 
01362     new_knot++; 
01363     rc++;
01364   }
01365   new_knot -= rc;
01366   new_cv -= rc*cv_stride;
01367 
01368   if ( rc > 0 ) {
01369     // make room for rc many new knots
01370     int i0 = ON_KnotCount( order, cv_count ) - 1; // knot[i0] = last input knot
01371     int i1 = i0 + rc;
01372     int j  = (cv_count-order);
01373     while (j--)
01374       knot[i1--] = knot[i0--];
01375     
01376     // update knot vector
01377     memcpy ( knot+degree, new_knot+degree, (degree+rc)*sizeof(*new_knot) );
01378 
01379     if ( cv ) {
01380       // make room for rc many new CVs
01381       i0 = (cv_count-1)*cv_stride;             // cv[i0] = last coord of last input cv */
01382       i1 = i0 + rc*cv_stride;
01383       j = cv_count-order;
01384       while (j--) {
01385         memcpy( cv+i1, cv+i0, cv_dim*sizeof(*cv) );
01386         i1 -= cv_stride;
01387         i0 -= cv_stride;
01388       }
01389 
01390       // update cv values
01391       for ( j = 0; j < order+rc; j++ ) {
01392         memcpy( cv, new_cv, cv_dim*sizeof(*new_cv) );
01393         cv += cv_stride;
01394         new_cv += cv_dim;
01395       }
01396     }
01397 
01398   }
01399 
01400   onfree(new_knot);
01401 
01402   return rc;
01403 }
01404 


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