1 /* $NoKeywords: $ */
2 /*
3 //
4 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
5 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
6 // McNeel & Associates.
7 //
8 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
9 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
10 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
11 //
12 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
13 //
14 ////////////////////////////////////////////////////////////////
15 */
16 
17 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
18 
19 /////////////////////////////////////////////////////////////////
20 //
21 // Computes tolerance associated with a generic evaluation domain
22 //
23 
ON_DomainTolerance(double a,double b)24 double ON_DomainTolerance( double a, double b )
25 {
26   if ( a == b )
27     return 0.0;
28   double tol = (fabs(a)+fabs(b)+fabs(a-b))* ON_SQRT_EPSILON;
29   if ( tol <  ON_EPSILON )
30     tol =  ON_EPSILON;
31   return tol;
32 }
33 
34 /////////////////////////////////////////////////////////////////
35 //
36 // Computes tolerance associated with knot[i]
37 //
38 
ON_KnotTolerance(int order,int cv_count,const double * knot,int knot_index)39 double ON_KnotTolerance( int order, int cv_count, const double* knot,
40                                     int knot_index )
41 {
42   const int knot_count = ON_KnotCount( order, cv_count );
43   int i0, i1, j;
44   double a, b, tol;
45   i0 = knot_index-order+1;
46   if ( i0 < 0 )
47     i0 = 0;
48   i1 = knot_index+order-1;
49   if ( i1 >= knot_count )
50     i1 = knot_count-1;
51   for ( j = knot_index; j > i0; j-- ) {
52     if ( knot[j] != knot[knot_index] )
53       break;
54   }
55   a = fabs(knot[knot_index] - knot[j]);
56   for ( j = knot_index; j < i1; j++ ) {
57     if ( knot[j] != knot[knot_index] )
58       break;
59   }
60   b = fabs(knot[knot_index] - knot[j]);
61   tol = (a==0.0 && b==0.0) ? 0.0 : (a + b + fabs(knot[knot_index]))* ON_SQRT_EPSILON;
62   return tol;
63 }
64 
65 /////////////////////////////////////////////////////////////////
66 //
67 // Computes tolerance associated with span of a knot vector
68 //
69 
ON_SpanTolerance(int order,int,const double * knot,int span_index)70 double ON_SpanTolerance( int order, int, const double* knot, int span_index )
71 {
72   const int i0 = span_index+order-2;
73   return ON_DomainTolerance( knot[i0], knot[i0+1] );
74 }
75 
76 /////////////////////////////////////////////////////////////////
77 //
78 // Computes number of knots in knot vector
79 //
80 
ON_KnotCount(int order,int cv_count)81 int ON_KnotCount( int order, int cv_count )
82 {
83   return (order+cv_count-2);
84 }
85 
86 /////////////////////////////////////////////////////////////////
87 //
88 // Computes number of knots in knot vector
89 //
90 
ON_KnotMultiplicity(int order,int cv_count,const double * knot,int knot_index)91 int ON_KnotMultiplicity(
92           int order,          // order (>=2)
93           int cv_count,       // cv_count (>=order)
94           const double* knot, // knot[]
95           int knot_index      // knot_index
96           )
97 {
98   int knot_count = order+cv_count-2;
99   int km = 0;
100   if ( knot && knot_index >= 0 && knot_index < knot_count ) {
101     while(knot_index > 0 && knot[knot_index] == knot[knot_index-1])
102       knot_index--;
103     knot += knot_index;
104     knot_count -= knot_index;
105     km = 1;
106     while ( km < knot_count && knot[0] == knot[km] )
107       km++;
108   }
109   return km;
110 }
111 
112 /////////////////////////////////////////////////////////////////
113 //
114 // Computes number of non-empty spans
115 //
116 
ON_KnotVectorSpanCount(int order,int cv_count,const double * knot)117 int ON_KnotVectorSpanCount(
118           int order,         // order (>=2)
119           int cv_count,      // cv count
120           const double* knot // knot[] array
121           )
122 {
123   if ( 0 == knot )
124   {
125     if ( 0 != order || 0 != cv_count )
126     {
127       ON_ERROR("NULL knot[] passed to ON_KnotVectorSpanCount.");
128     }
129     return 0;
130   }
131   int i, span_count = 0;
132   for ( i = order-1; i < cv_count; i++ ) {
133     if ( knot[i] > knot[i-1] )
134       span_count++;
135   }
136   return span_count;
137 }
138 
139 /////////////////////////////////////////////////////////////////
140 //
141 // Gets span vector from knot vector
142 //
143 
ON_GetKnotVectorSpanVector(int order,int cv_count,const double * knot,double * s)144 bool ON_GetKnotVectorSpanVector(
145           int order,          // order (>=2)
146           int cv_count,       // cv count
147           const double* knot, // knot[] array
148           double* s           // s[] array
149           )
150 {
151   if ( 0 == knot || 0 == s )
152   {
153     if ( 0 != order || 0 != cv_count )
154     {
155       ON_ERROR("NULL knot[] or s[] passed to ON_KnotVectorSpanCount.");
156       return false;
157     }
158     return true;
159   }
160 
161   int i, span_count = 0;
162   s[span_count++] = knot[order-2];
163   for ( i = order-1; i < cv_count; i++ ) {
164     if ( knot[i] > knot[i-1] )
165       s[span_count++] = knot[i];
166   }
167   return (span_count>1) ? true : false;
168 }
169 
170 
171 /////////////////////////////////////////////////////////////////
172 //
173 // Computes span index for evaluation of parameter
174 //
175 
ON_NurbsSpanIndex(int order,int cv_count,const double * knot,double t,int side,int hint)176 int ON_NurbsSpanIndex(
177           int order,          // (>=2)
178           int cv_count,
179           const double* knot, // knot[] array or length ON_KnotCount(order,cv_count)
180           double t,           // evaluation parameter
181           int side,           // side 0 = default, -1 = from below, +1 = from above
182           int hint            // hint (or 0 if no hint available)
183           )
184 {
185   int j, len;
186 
187   // shift knot so that domain is knot[0] to knot[len]
188   knot += (order-2);
189   len = cv_count-order+2;
190 
191   // see if hint helps
192   if (hint > 0 && hint < len-1) {
193     while(hint > 0 && knot[hint-1] == knot[hint]) hint--;
194     if (hint > 0) {
195       // have knot[hint-1] < knot[hint]
196       if (t < knot[hint]) {
197         len = hint+1;
198         hint = 0;
199       }
200       else {
201         if (side < 0 && t == knot[hint])
202           hint--;
203         knot += hint;
204         len -= hint;
205       }
206     }
207   }
208   else
209     hint = 0;
210 
211   j = ON_SearchMonotoneArray(knot,len,t);
212   if (j < 0)
213     j = 0;
214   else if (j >= len-1)
215     j = len-2;
216   else if (side < 0) {
217     // if user wants limit from below and t = an internal knot,
218     // back up to prevous span
219     while(j > 0 && t == knot[j])
220       j--;
221   }
222   return (j + hint);
223 }
224 
225 
ON_NextNurbsSpanIndex(int order,int cv_count,const double * knot,int span_index)226 int ON_NextNurbsSpanIndex( int order, int cv_count, const double* knot, int span_index )
227 
228 /*
229 Get index of next non-degenerate NURBS span
230 
231 INPUT:
232   order, cv_count, knot
233     knot vector
234   span_index
235     current span index ( >= 0 and <= cv_count-order )
236 OUTPUT:
237   i = ON_NextNurbsSpanIndex()
238     i>=0: successful - the index of the next span or
239                        cv_count-order if the input value
240                        was cv_count-or
241                        knot[i+order-2] < knot[i+order-1]
242    <0: failure
243 
244 COMMENTS:
245   The first span in a NURBS has span_index = 0.  The last span in a NURBS
246   has span_index = cv_count-order.
247   A span of a degree d NURBS is defined by d+1 CVs and 2*d knots.  For a
248   given span_index, the associated knots and CVs are
249     {knot[span_index], ..., knot[span_index+2*d-1]}
250   and
251     {CV[span_index], ..., CV[span_index + d]}
252   The domain of the span is
253     [ knot[span_index+order-2], knot[span_index+order-1] ].
254 
255 EXAMPLE:
256   // print the values of all distinct knots in a NURBS's domain
257   int span_index = 0;
258   int next_span_index = 0;
259   for (;;) {
260     printf( "knot[%2d] = %g\n", span_index+order-2, knot[span_index+order-2] );
261     next_span_index =ON_NextNurbsSpanIndex( order, cv_count, knot, span_index );
262     if ( next_span_index < 0 )
263       break; // illegal input
264     if ( next_span_index == span_index ) {
265       // end of the domain
266       printf( "knot[%2d] = %g\n", cv_count-1, knot[cv_count-1] );
267       break;
268     }
269     next_span_index = span_index;
270   }
271 
272   */
273 
274 {
275 
276   if (span_index < 0 || span_index > cv_count-order || !knot)
277     return -1;
278 
279   if ( span_index < cv_count-order ) {
280     do {
281       span_index++;
282     }
283     while ( span_index < cv_count-order &&
284             knot[span_index+order-2] == knot[span_index+order-1] );
285   }
286   return span_index;
287 }
288 
289 
ON_GetSpanIndices(int order,int cv_count,const double * knot,int * span_indices)290 int ON_GetSpanIndices(int order,
291                             int cv_count,
292                             const double* knot,
293                             int* span_indices)
294 
295 /* span_indices should have size greater than the number of
296    spans (cv_count is big enough).
297 
298   returns span count.
299   fills in span_indices with index of last in each bunch of multiple knots at
300   start of span, and first in buch at end of nurb.
301 
302 
303   */
304 {
305   int span_index, next_span_index, j;
306 
307   span_index = -1;
308   next_span_index = 0;
309   j = 0;
310   while (span_index != next_span_index) {
311     span_index = next_span_index;
312     span_indices[j] = span_index + order - 2;
313     next_span_index = ON_NextNurbsSpanIndex(order, cv_count, knot, span_index);
314     if (next_span_index < 0)
315       return next_span_index;
316     j++;
317   }
318 
319   span_indices[j] = span_index + order - 1;
320 
321   return j;
322 }
323 
324 
325 /////////////////////////////////////////////////////////////////
326 //
327 // Computes value for superfluous knot used in systems like OpenGL and 3dsMax
328 //
329 
ON_SuperfluousKnot(int order,int cv_count,const double * knot,int end)330 double ON_SuperfluousKnot(
331                     int order, int cv_count, const double* knot,
332                     int end )
333 {
334   double k;
335   const int knot_count = order+cv_count-2;
336   // gets superfluous knot for translation to other formats
337   k = knot[(end) ? knot_count-1 : 0];
338   if (order > 2 && cv_count >= 2*order - 2 && cv_count >= 6 ) {
339     // check for non-clamped knots
340     if (end) {
341       if ( knot[cv_count-1] < knot[knot_count-1] )
342         k += (knot[order+1] - knot[order]);
343     }
344     else {
345       if ( knot[0] < knot[order-2] )
346         k -= (knot[cv_count-order+1] - knot[cv_count-order]);
347     }
348   }
349   return k;
350 }
351 
352 /////////////////////////////////////////////////////////////////
353 //
354 // Used to determine when a knot vector is periodic
355 //
356 
ON_IsKnotVectorPeriodic(int order,int cv_count,const double * knot)357 bool ON_IsKnotVectorPeriodic(
358        int order,
359        int cv_count,
360        const double* knot
361        )
362 
363 {
364   double tol;
365   const double* k1;
366   int i;
367 
368   if ( order < 2 || cv_count < order || !knot ) {
369     ON_ERROR("ON_IsKnotVectorPeriodic(): illegal input");
370     return false;
371   }
372 
373   if ( order == 2 )
374     return false; // convention is that degree 1 curves cannot be periodic.
375 
376   if (order <= 4) {
377     if (cv_count < order+2)
378       return false;
379   }
380   else if ( cv_count < 2*order-2 ) {
381     return false;
382   }
383 
384   tol = fabs(knot[order-1] - knot[order-3])* ON_SQRT_EPSILON;
385   if (tol < fabs(knot[cv_count-1] - knot[order-2])* ON_SQRT_EPSILON)
386     tol = fabs(knot[cv_count-1] - knot[order-2])* ON_SQRT_EPSILON;
387   k1 = knot+cv_count-order+1;
388   i = 2*(order-2);
389   while(i--) {
390     if (fabs(knot[1] - knot[0] + k1[0] - k1[1]) > tol)
391       return false;
392     knot++; k1++;
393   }
394   return true;
395 }
396 
397 /////////////////////////////////////////////////////////////////
398 //
399 // Used to determine when a knot vector is clamped
400 //
401 
ON_IsKnotVectorClamped(int order,int cv_count,const double * knot,int end)402 bool ON_IsKnotVectorClamped(
403        int order,
404        int cv_count,
405        const double* knot,
406        int end // (default = 2) 0 = left end, 1 = right end, 2 = both
407        )
408 
409 {
410   if ( order <= 1 || cv_count < order || !knot || end < 0 || end > 2 )
411     return false;
412   bool rc = true;
413   if ( (end == 0 || end == 2) && knot[0] != knot[order-2] )
414     rc = false;
415   if ( (end == 1 || end == 2) && knot[cv_count-1] != knot[order+cv_count-3] )
416     rc = false;
417   return rc;
418 }
419 
ON_IsKnotVectorUniform(int order,int cv_count,const double * knot)420 bool ON_IsKnotVectorUniform(
421           int order,
422           int cv_count,
423           const double* knot
424           )
425 {
426   bool rc = (order >= 2 && cv_count >= order && 0 != knot);
427   if (rc)
428   {
429     const double delta = knot[order-1] - knot[order-2];
430     const double delta_tol = ON_SQRT_EPSILON*delta;
431     int i0, i1;
432     double d;
433     if ( ON_IsKnotVectorClamped(order,cv_count,knot) )
434     {
435       i0 = order;
436       i1 = cv_count;
437     }
438     else
439     {
440       i0 = 1;
441       i1 = ON_KnotCount(order,cv_count);
442     }
443     for (/*empty*/; i0 < i1 && rc; i0++ )
444     {
445       d = knot[i0] - knot[i0-1];
446       if ( fabs(d - delta) > delta_tol )
447         rc = false;
448     }
449   }
450   return rc;
451 }
452 
453 /////////////////////////////////////////////////////////////////
454 //
455 // Used to determine properties of knot vector
456 //
457 
ON_KnotVectorHasBezierSpans(int order,int cv_count,const double * knot)458 bool ON_KnotVectorHasBezierSpans(
459           int order,          // order (>=2)
460           int cv_count,       // cv count
461           const double* knot  // knot[] array
462           )
463 {
464   int knot_count = ON_KnotCount( order, cv_count );
465   if ( knot_count < 2 )
466     return false;
467   int span_count = ON_KnotVectorSpanCount( order, cv_count, knot );
468   if ( span_count < 1 )
469     return false;
470   if ( order >= 2 &&
471        cv_count >= order &&
472        knot_count == (span_count+1)*(order-1) &&
473        knot[0] == knot[order-2] && knot[cv_count-1] == knot[knot_count-1])
474     return true;
475   return false;
476 }
477 
478 /////////////////////////////////////////////////////////////////
479 //
480 // Used to determine properties of knot vector
481 //
482 
ON_KnotVectorStyle(int order,int cv_count,const double * knot)483 ON::knot_style ON_KnotVectorStyle(
484        int order,
485        int cv_count,
486        const double* knot
487        )
488 {
489   ON::knot_style s = ON::unknown_knot_style;
490   if ( order >= 2 && cv_count >= order && knot && knot[order-2] < knot[cv_count-1] ) {
491     const int knot_count = order+cv_count-2;
492     const double delta = 0.5*((knot[order-1] - knot[order-2]) + (knot[cv_count-1] - knot[cv_count-2]));
493     const double ktol = delta*1.0e-6;
494     int i;
495     if ( ON_IsKnotVectorClamped( order, cv_count, knot ) ) {
496       if ( order == cv_count ) {
497         s = ON::piecewise_bezier_knots;
498       }
499       else {
500         s = ON::clamped_end_knots;
501         for ( i = order-1; i <= cv_count-1; i++ ) {
502           if ( fabs(knot[i] - knot[i-1] - delta) > ktol ) {
503             break;
504           }
505         }
506         if ( i >= cv_count ) {
507           s = ON::quasi_uniform_knots;
508         }
509         else {
510           const int degree = order-1;
511           for ( i = order-1; i < cv_count-1; i += degree ) {
512             if ( knot[i] != knot[i+degree-1] )
513               break;
514           }
515           if ( i >= cv_count-1 )
516             s = ON::piecewise_bezier_knots;
517         }
518       }
519     }
520     else {
521       // check for uniform knots
522       s = ON::non_uniform_knots;
523       for ( i = 1; i < knot_count; i++ ) {
524         if ( fabs(knot[i] - knot[i-1] - delta) > ktol ) {
525           break;
526         }
527       }
528       if ( i >= knot_count )
529         s = ON::uniform_knots;
530     }
531   }
532   return s;
533 }
534 
535 
536 /////////////////////////////////////////////////////////////////
537 //
538 // Used to set the domain of a knot vector
539 //
540 
ON_SetKnotVectorDomain(int order,int cv_count,double * knot,double t0,double t1)541 bool ON_SetKnotVectorDomain( int order, int cv_count, double* knot, double t0, double t1 )
542 {
543   bool rc = false;
544   if ( order < 2 || cv_count < order || 0 == knot || t0 >= t1 || !ON_IsValid(t0) || !ON_IsValid(t1) )
545   {
546     ON_ERROR("ON_SetKnotVectorDomain - invalid input");
547   }
548   else if (    knot[order-2] >= knot[cv_count-1]
549             || !ON_IsValid(knot[order-2])
550             || !ON_IsValid(knot[cv_count-2]) )
551   {
552     ON_ERROR("ON_SetKnotVectorDomain - invalid input knot vector");
553   }
554   else
555   {
556     const ON_Interval oldd(knot[order-2],knot[cv_count-1]);
557     const ON_Interval newd(t0,t1);
558     if ( oldd != newd )
559     {
560       int i, knot_count = ON_KnotCount(order,cv_count);
561       for ( i = 0; i < knot_count; i++ )
562       {
563         knot[i] = newd.ParameterAt(oldd.NormalizedParameterAt(knot[i]));
564       }
565     }
566     rc = true;
567   }
568   return rc;
569 }
570 
571 
572 /////////////////////////////////////////////////////////////////
573 //
574 // Used to get the domain of a knot vector
575 //
576 
ON_GetKnotVectorDomain(int order,int cv_count,const double * knot,double * k0,double * k1)577 bool ON_GetKnotVectorDomain(
578        int order,
579        int cv_count,
580        const double* knot,
581        double* k0, double* k1
582        )
583 {
584   if ( order < 2 || cv_count < order || knot == NULL )
585     return false;
586   if ( k0 )
587     *k0 = knot[order-2];
588   if ( k1 )
589     *k1 = knot[cv_count-1];
590   return true;
591 }
592 
593 /////////////////////////////////////////////////////////////////
594 //
595 // Used to reverse knot vectors
596 //
597 
ON_ReverseKnotVector(int order,int cv_count,double * knot)598 bool ON_ReverseKnotVector(
599        int order,
600        int cv_count,
601        double* knot
602        )
603 {
604   if ( order < 2 || cv_count < order || knot == NULL )
605     return false;
606   const int knot_count = (order+cv_count-2);
607   double t;
608   int i, j;
609   for ( i = 0, j = knot_count-1; i <= j; i++, j-- ) {
610     t = knot[i];
611     knot[i] = -knot[j];
612     knot[j] = -t;
613   }
614   return true;
615 }
616 
617 /////////////////////////////////////////////////////////////////
618 //
619 // Used to compare knot vectors
620 //
621 
ON_CompareKnotVector(int orderA,int cv_countA,const double * knotA,int orderB,int cv_countB,const double * knotB)622 int ON_CompareKnotVector( // returns
623                                       // -1: first < second
624                                       //  0: first == second
625                                       // +1: first > second
626           int orderA,
627           int cv_countA,
628           const double* knotA,
629           int orderB,
630           int cv_countB,
631           const double* knotB
632           )
633 {
634   const int knot_count = ON_KnotCount(orderA,cv_countA);
635   int i;
636   double a, b, atol, btol, ktol, tol;
637   if ( orderA < orderB )
638     return -1;
639   if ( orderA > orderB )
640     return 1;
641   if ( cv_countA < cv_countB )
642     return -1;
643   if ( cv_countA > cv_countB )
644     return 1;
645 
646   if ( !ON_GetKnotVectorDomain( orderA, cv_countA, knotA, &a, &b ) )
647     return -1;
648   atol = ON_DomainTolerance( a, b );
649   if ( !ON_GetKnotVectorDomain( orderA, cv_countA, knotA, &a, &b ) )
650     return 1;
651   btol = ON_DomainTolerance( a, b );
652   tol = (atol <= btol) ? atol : btol;
653 
654   for ( i = 0; i < knot_count; i++ ) {
655     a = knotA[i];
656     b = knotB[i];
657     if ( a == b )
658       continue;
659     if ( a < b-tol )
660       return -1;
661     if ( b < a-tol )
662       return 1;
663     atol = ON_KnotTolerance( orderA, cv_countA, knotA, i );
664     btol = ON_KnotTolerance( orderB, cv_countB, knotB, i );
665     ktol = (atol <= btol) ? atol : btol;
666     if ( a < b-ktol )
667       return -1;
668     if ( b < a-ktol )
669       return 1;
670   }
671   return 0;
672 }
673 
674 /////////////////////////////////////////////////////////////////
675 //
676 // Used to validate knot vectors
677 //
678 
ON_KnotVectorIsNotValid(bool bSilentError)679 static bool ON_KnotVectorIsNotValid(bool bSilentError)
680 {
681   return bSilentError ? false : ON_IsNotValid(); // <-- good place for a breakpoint
682 }
683 
ON_IsValidKnotVector(int order,int cv_count,const double * knot,ON_TextLog * text_logx)684 bool ON_IsValidKnotVector( int order, int cv_count, const double* knot, ON_TextLog* text_logx )
685 {
686   // If low bit of text_log pointer is 1, then ON_Error is not called when the
687   // knot vector is invalid.
688   const ON__INT_PTR lowbit = 1;
689   const ON__INT_PTR hightbits = ~lowbit;
690   bool bSilentError = ( 0 != (lowbit & ((ON__INT_PTR)text_logx)) );
691   ON_TextLog* text_log = (ON_TextLog*)(((ON__INT_PTR)text_logx) & hightbits);
692 
693   const double *k0, *k1;
694   int i;
695   if ( order < 2 )
696   {
697     if ( text_log )
698     {
699       text_log->Print("Knot vector order = %d (should be >= 2 )\n",order);
700     }
701     return ON_KnotVectorIsNotValid(bSilentError);
702   }
703   if ( cv_count < order )
704   {
705     if ( text_log )
706     {
707       text_log->Print("Knot vector cv_count = %d (should be >= order=%d )\n",cv_count,order);
708     }
709     return ON_KnotVectorIsNotValid(bSilentError);
710   }
711   if ( knot == NULL )
712   {
713     if ( text_log )
714     {
715       text_log->Print("Knot vector knot array = NULL.\n");
716     }
717     return ON_KnotVectorIsNotValid(bSilentError);
718   }
719 
720   for ( i = 0; i < cv_count+order-2; i++ )
721   {
722     if ( !ON_IsValid(knot[i]) )
723     {
724       if ( text_log )
725       {
726         text_log->Print("Knot vector knot[%d]=%g is not valid.\n",i,knot[i]);
727       }
728       return ON_KnotVectorIsNotValid(bSilentError);
729     }
730   }
731 
732   if ( !(knot[order-2] < knot[order-1]) )
733   {
734     if ( text_log )
735     {
736       text_log->Print("Knot vector order=%d and knot[%d]=%g >= knot[%d]=%g (should have knot[order-2] < knot[order-1]).\n",
737                        order,order-2,knot[order-2],order-1,knot[order-1]);
738     }
739     return ON_KnotVectorIsNotValid(bSilentError);
740   }
741   if ( !(knot[cv_count-2] < knot[cv_count-1]) )
742   {
743     if ( text_log )
744     {
745       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",
746                        cv_count,cv_count-2,knot[cv_count-2],cv_count-1,knot[cv_count-1]);
747     }
748     return ON_KnotVectorIsNotValid(bSilentError);
749   }
750 
751   // entire array must be monotone increasing
752   k0 = knot;
753   k1 = knot+1;
754   i = order + cv_count - 3;
755   while (i--) {
756     if ( !(*k1 >= *k0) )
757     {
758       if ( text_log )
759       {
760         text_log->Print("Knot vector must be increasing but knot[%d]=%g > knot[%d]=%g\n",
761                          order+cv_count-4-i, *k0, order+cv_count-3-i, *k1 );
762       }
763       return ON_KnotVectorIsNotValid(bSilentError);
764     }
765     k0++;
766     k1++;
767   }
768 
769   // must have knot[i+order-1] > knot[i]
770   k0 = knot;
771   k1 = knot + order - 1;
772   i = cv_count-1;
773   while(i--) {
774     if ( !(*k1 > *k0) )
775     {
776       if ( text_log )
777       {
778         text_log->Print("Knot vector order = %d but knot[%d]=%g >= knot[%d]=%g\n",
779                          order, cv_count-2-i, *k0, cv_count-1-i, *k1 );
780       }
781       return ON_KnotVectorIsNotValid(bSilentError);
782     }
783     k0++;
784     k1++;
785   }
786 
787   return true;
788 }
789 
790 
ON_ClampKnotVector(int order,int cv_count,double * knot,int end)791 bool ON_ClampKnotVector(
792           int order,          // order (>=2)
793           int cv_count,       // cv count
794           double* knot,       // knot[] array
795           int end             // 0 = clamp start, 1 = clamp end, 2 = clamp both ends
796           )
797 {
798   // sets initial/final order-2 knot values to match knot[order-2]/knot[cv_count-1]
799   bool rc = false;
800   int i, i0;
801   if ( knot && order >= 2 && cv_count >= order ) {
802     if ( end == 0 || end == 2 ) {
803       i0 = order-2;
804       for ( i = 0; i < i0; i++ ) {
805         knot[i] = knot[i0];
806       }
807       rc = true;
808     }
809     if ( end == 1 || end == 2 ) {
810       const int knot_count = ON_KnotCount(order,cv_count);
811       i0 = cv_count-1;
812       for ( i = i0+1; i < knot_count; i++ ) {
813         knot[i] = knot[i0];
814       }
815       rc = true;
816     }
817   }
818   return rc;
819 }
820 
821 
ON_MakeKnotVectorPeriodic(int order,int cv_count,double * knot)822 bool ON_MakeKnotVectorPeriodic(
823           int order,          // order (>=2)
824           int cv_count,       // cv count (>= (order>=4) ? 2*(order-1) : 5)
825           double* knot        // knot[] array
826           )
827 {
828   double *k0, *k1;
829   int i;
830 
831   if ( order < 2 || cv_count < order || !knot ) {
832     ON_ERROR("ON_MakePeriodicKnotVector(): illegal input");
833     return false;
834   }
835 
836   switch(order) {
837   case 2:
838     if ( cv_count < 4 ) {
839       ON_ERROR("ON_MakePeriodicKnotVector(): illegal input degree=1, cv_count<4");
840       return false;
841     }
842     else {
843       return true;
844     }
845     break;
846   case 3:
847     if ( cv_count < 4 ) {
848       ON_ERROR("ON_MakePeriodicKnotVector(): illegal input degree=2, cv_count<5");
849       return false;
850     }
851     break;
852   default:
853     if ( cv_count < 2*order-2 ) {
854       ON_ERROR("ON_MakePeriodicKnotVector(): illegal input degree>=3, cv_count<2*degree");
855       return false;
856     }
857     break;
858   }
859 
860   k0 = knot + order-2;
861   k1 = knot + cv_count-1;
862   i = order-2;
863   while (i--) {
864     k1[1] = k0[1]-k0[0]+k1[0];
865     k0++; k1++;
866   }
867   k0 = knot + order-2;
868   k1 = knot + cv_count-1;
869   i = order-2;
870   while (i--) {
871     k0[-1] = k1[-1] - k1[0] + k0[0];
872     k0--;
873     k1--;
874   }
875   return true;
876 }
877 
878 ON_DECL
ON_MakeClampedUniformKnotVector(int order,int cv_count,double * knot,double delta)879 bool ON_MakeClampedUniformKnotVector(
880           int order,
881           int cv_count,
882           double* knot,
883           double delta
884           )
885 {
886   bool rc = false;
887   if ( order >= 2 && cv_count >= order && knot != NULL && delta > 0.0 )
888   {
889     double k;
890     int i;
891     for ( i = order-2, k = 0.0; i < cv_count; i++, k += delta )
892       knot[i] = k;
893     ON_ClampKnotVector(order,cv_count,knot,2);
894     rc = true;
895   }
896   return rc;
897 }
898 
899 // Description:
900 //   Fill in knot values for a clamped uniform knot
901 //   vector.
902 // Parameters:
903 //   order - [in] (>=2) order (degree+1) of the NURBS
904 //   cv_count - [in] (>=order) total number of control points
905 //       in the NURBS.
906 //   knot - [in/out] Input is an array with room for
907 //       ON_KnotCount(order,cv_count) doubles.  Output is
908 //       a periodic uniform knot vector with domain
909 //       (0, (1+cv_count-order)*delta).
910 //   delta - [in] (>0, default=1.0) spacing between knots.
911 // Returns:
912 //   true if successful
913 ON_DECL
ON_MakePeriodicUniformKnotVector(int order,int cv_count,double * knot,double delta)914 bool ON_MakePeriodicUniformKnotVector(
915           int order,
916           int cv_count,
917           double* knot,
918           double delta
919           )
920 {
921   bool rc = false;
922   if ( order >= 2 && cv_count >= order && knot != NULL && delta > 0.0 )
923   {
924     double k = 0.0;
925     int i, knot_count = ON_KnotCount(order,cv_count);
926     for ( i = order-2, k = 0.0; i < knot_count; i++, k += delta )
927       knot[i] = k;
928     for ( i = order-3, k = -delta; i >= 0; i--, k -= delta )
929       knot[i] = k;
930     rc = true;
931   }
932   return rc;
933 }
934 
935 
936 
ON_GrevilleAbcissa(int order,const double * knot)937 double ON_GrevilleAbcissa( // get Greville abcissa
938           int order,          // order (>=2)
939           const double* knot  // knot[order-1] array
940           )
941 {
942   double g=0.0;
943   if ( order <= 2 || knot[0] == knot[order-2]) {
944     g = knot[0]; // degree = 1 or fully multiple knot
945   }
946   else {
947     // g = (knot[i]+...+knot[i+degree-1])/degree
948     order--;
949     const double k = knot[order/2];
950     const double tol = (knot[order-1]-knot[0]);
951     const double d = 1.0/((double)order);
952     while ( order--) {
953       g += *knot++;
954     }
955     g *= d;
956     if ( fabs(g-k) <= (fabs(g)+tol)* ON_SQRT_EPSILON )
957       g = k; // sets g to exact value when knot vector is uniform
958   }
959   return g;
960 }
961 
962 
ON_GetGrevilleAbcissae(int order,int cv_count,const double * knot,bool bPeriodic,double * g)963 bool ON_GetGrevilleAbcissae( // get Greville abcissa from knots
964           int order,          // order (>=2)
965           int cv_count,       // cv count (>=order)
966           const double* knot, // knot[] array
967           bool bPeriodic,
968           double* g           // has length cv_count in non-periodic case
969                               // and length cv_count-order+1 in periodic case
970           )
971 {
972   // Grevielle abscissae for a given knot vector
973   double x, t0;
974   int gi, periodic_check;
975 
976   if ( order < 2 || cv_count < order || !knot || !g )
977     return false;
978 
979   const int g_count = (bPeriodic) ? cv_count-order+1 : cv_count;
980 
981   if (order == 2) {
982     // g[i] = knot[i] in degree 1 case
983     memcpy( g, knot, g_count*sizeof(*g) );
984   }
985   else {
986     // g = (knot[i]+...+knot[i+degree-1])/degree
987     t0 = knot[order-2];
988     gi = 0;
989     periodic_check = (bPeriodic) ? order-2 : 0;
990     while (gi < g_count) {
991       x = ON_GrevilleAbcissa( order, knot++ );
992       if ( periodic_check ) {
993         periodic_check--;
994         if ( x < t0 )
995           continue;
996       }
997       g[gi++] = x;
998     }
999   }
1000 
1001   return true;
1002 }
1003 
1004 
ON_GetGrevilleKnotVector(int g_stride,const double * g,bool bPeriodic,int order,int cv_count,double * knot)1005 bool ON_GetGrevilleKnotVector( // get knots from Greville abcissa
1006           int g_stride,
1007           const double *g,  // if not periodic, g[cv_count],
1008                             // if periodic, g[cv_count-order+2]
1009                             // usually, g[0] = 0, g[i] = |P[i]-P[i-1]|^q
1010           bool bPeriodic,
1011           int order,
1012           int cv_count,
1013           double* knot
1014           )
1015 {
1016   bool rc = false;
1017   double* p = NULL;
1018   int ki, knot_count, g_count, gi, j, degree;
1019   double k, dd;
1020 
1021   if ( g_stride < 1 || !g || !knot || order < 2 || cv_count < order )
1022     return false;
1023   if ( bPeriodic && order == 2 )
1024     return false;
1025   if ( bPeriodic && cv_count - order + 2 < 3 )
1026     return false;
1027 
1028   degree = order-1;
1029   if ( degree == 1 ) {
1030     for ( j = 0; j < cv_count; j++ ) {
1031       knot[j] = g[j*g_stride];
1032     }
1033     return true;
1034   }
1035   dd = 1.0/degree;
1036   knot_count = ON_KnotCount( order, cv_count );
1037   g_count = (bPeriodic) ? cv_count-order+2 : cv_count;
1038 
1039   if ( bPeriodic ) {
1040     int half_degree = (degree%2) ? degree/2 : 0;
1041     // step 1: set p[] = fully periodic list of abcissa
1042     p = (double*)onmalloc((g_count + 2*degree)*sizeof(*p));
1043     for ( j = 0, gi = g_count-order; j < degree; j++, gi++ ) {
1044       p[j] = g[0] - g[g_count-1] + g[gi];
1045     }
1046     for ( gi = 0, j = degree; gi < g_count; gi++, j++ ) {
1047       p[j] = g[gi];
1048     }
1049     for ( j = g_count+degree, gi = 1; j < g_count+2*degree; j++, gi++ ) {
1050       p[j] = g[g_count-1] - g[0] + g[gi];
1051     }
1052 
1053     // step 2: set new p[i] = old (p[i] + ... + p[i+degree-1]) / degree
1054     for ( j = 0; j < g_count+order; j++ ) {
1055       k = p[j];
1056       for ( ki = 1; ki < degree; ki++ )
1057         k += p[j+ki];
1058       k *= dd;
1059       if ( half_degree ) {
1060         // if g[]'s are uniform and degree is odd, then knots = g[]'s
1061         if ( fabs(k-p[j+half_degree]) <=  ON_SQRT_EPSILON*(p[j+degree-1]-p[j]) )
1062           k = p[j+half_degree];
1063       }
1064       p[j] = k;
1065     }
1066 
1067     // step 3: determine where g[0] maximizes NURBS basis functions
1068     {
1069       double* B = (double*)alloca(order*order*sizeof(B[0]));
1070       double maxB  = 0.0;
1071       int maxBj = 0;
1072       for ( j = 0; j < 2*degree; j++ ) {
1073         if ( g[0] > p[j+degree] )
1074           continue;
1075         if ( g[0] < p[j+degree-1] )
1076           break;
1077         ON_EvaluateNurbsBasis( order, p+j, g[0], B );
1078         if ( B[0] > maxB ) {
1079           maxB  = B[0];
1080           maxBj = j;
1081         }
1082       }
1083       memcpy( knot, &p[maxBj], knot_count*sizeof(*knot) );
1084     }
1085 
1086     rc = ON_MakeKnotVectorPeriodic( order, cv_count, knot );
1087   }
1088   else {
1089     // clamped knots
1090     rc = true;
1091     if ( g > knot && g < knot+knot_count ) {
1092       p = (double*)onmalloc(cv_count*sizeof(*p));
1093       for( j = 0; j < cv_count; j++ ) {
1094         p[j] = g[j*g_stride];
1095       }
1096       g = p;
1097       g_stride = 1;
1098     }
1099     for ( ki = 0; ki < degree; ki++ ) {
1100       knot[ki] = g[0];
1101     }
1102     for ( ki = degree, gi = 1; ki < cv_count; ki++, gi++ ) {
1103       k = 0.0;
1104       for ( j = 0; j < degree; j++ ) {
1105         k += g[(gi+j)*g_stride];
1106       }
1107       knot[ki] = k*dd;
1108       if ( knot[ki] < knot[ki-1] || knot[ki] <= knot[ki-degree] ) {
1109         rc = false;
1110       }
1111     }
1112     for ( ki = cv_count-1; ki < knot_count; ki++ ) {
1113       knot[ki] = g[(cv_count-1)*g_stride];
1114     }
1115   }
1116 
1117   if (p)
1118     onfree(p);
1119   return rc;
1120 }
1121 
ON_ClampKnotVector(int cv_dim,int order,int cv_count,int cv_stride,double * cv,double * knot,int end)1122 bool ON_ClampKnotVector(
1123         int cv_dim,   // dimension of cv's = ( = dim+1 for rational cvs )
1124         int order,
1125         int cv_count,
1126         int cv_stride,
1127         double* cv,   // NULL or cv array with room for at least knot_multiplicity new cvs
1128         double* knot, // knot array with room for at least knot_multiplicity new knots
1129         int end       // 0 = clamp start, 1 = clamp end, 2 = clamp both ends
1130         )
1131 {
1132   // sets initial/final order-2 knot values to match knot[order-2]/knot[cv_count-1]
1133   bool rc = false;
1134   int i, i0;
1135 
1136   if ( knot && order >= 2 && cv_count >= order ) {
1137     if ( end == 0 || end == 2 ) {
1138       if ( cv ) {
1139         ON_EvaluateNurbsDeBoor(cv_dim,order,cv_stride,cv,knot,1,0.0,knot[order-2]);
1140       }
1141       i0 = order-2;
1142       for (i = 0; i < i0; i++)
1143         knot[i] = knot[i0];
1144       rc = true;
1145     }
1146     if ( end == 1 || end == 2 ) {
1147       i0 = cv_count-order;
1148       knot += i0;
1149       if ( cv ) {
1150         cv += i0*cv_stride;
1151         ON_EvaluateNurbsDeBoor(cv_dim,order,cv_stride,cv,knot,-1,0.0,knot[order-1]);
1152       }
1153       i0 = order-1;
1154       for (i = 2*order-3; i > i0; i--)
1155         knot[i] = knot[i0];
1156       rc = true;
1157     }
1158   }
1159   return rc;
1160 }
1161 
1162 
ON_InsertSingleKnot(int cv_dim,int order,int cv_stride,double * cv,double * knot,double knot_value)1163 static bool ON_InsertSingleKnot( int cv_dim, int order,
1164                              int cv_stride,
1165                              double *cv,   // NULL or array of length at least order*cv_stride+cv_dim
1166                              double *knot, // array of length at least 2*order-1 and existing knot values in
1167                                            // knot[0], ..., knot[2*order-3]
1168                              double knot_value // knot[order-2] <= knot_value < knot[order-1]
1169                                                // and knot[0] < knot_vale
1170                              )
1171 {
1172   double alpha0, alpha1;
1173   double *k0, *k1, *prev_cv;
1174   int    i, d, cv_inc, degree;
1175 
1176   if ( order < 2 || !knot || knot_value < knot[order-2] || knot[order-1] <= knot_value ) {
1177     ON_ERROR( "ON_InsertSingleKnot() - illegal knot input" );
1178     return false;
1179   }
1180 
1181   if ( cv ) {
1182     if ( cv_dim < 1 || cv_stride < cv_dim  ) {
1183       ON_ERROR( "ON_InsertSingleKnot() - illegal cv input" );
1184       return false;
1185     }
1186   }
1187 
1188   degree = order-1;
1189 
1190   // move last degree many knots over one spot
1191   k1 = knot + 2*degree;
1192   k0 = k1-1;
1193   i = degree;
1194   while (i--)
1195     *k1-- = *k0--;
1196 
1197   // insert new knot value
1198   *k1 = knot_value;
1199 
1200   if ( cv ) {
1201     // move last cv over one spot
1202     memcpy( cv+cv_dim*order, cv+cv_dim*degree, cv_dim*sizeof(*cv) );
1203 
1204     // compute new cv values
1205     k0 = knot + degree-1;
1206     k1 = k0 + order;
1207     cv += order*cv_stride;
1208     prev_cv = cv - cv_stride;
1209     cv_inc = cv_stride - cv_dim;
1210     i = degree;
1211     if (knot_value - *k0 <= *k1 - knot_value) {
1212       while (i--) {
1213         alpha1 = (knot_value - *k0)/(*k1 - *k0);
1214         alpha0 = 1.0 - alpha1;
1215         k0--; k1--;
1216         cv -= cv_inc;
1217         prev_cv -= cv_inc;
1218         d = cv_dim;
1219         while (d--) {
1220           --cv;
1221           --prev_cv;
1222           *cv = *cv * alpha1 + *prev_cv * alpha0;
1223         }
1224       }
1225     }
1226     else {
1227       while (i--) {
1228         alpha0 = (*k1 - knot_value)/(*k1 - *k0);
1229         alpha1 = 1.0 - alpha0;
1230         k0--; k1--;
1231         cv -= cv_inc;
1232         prev_cv -= cv_inc;
1233         d = cv_dim;
1234         while (d--) {
1235           --cv;
1236           --prev_cv;
1237           *cv = *cv * alpha1 + *prev_cv * alpha0;
1238         }
1239       }
1240     }
1241   }
1242 
1243   return true;
1244 }
1245 
ON_InsertKnot(double knot_value,int knot_multiplicity,int cv_dim,int order,int cv_count,int cv_stride,double * cv,double * knot,int * hint)1246 int ON_InsertKnot(
1247         double knot_value,
1248         int knot_multiplicity,
1249         int cv_dim,   // dimension of cv's = ( = dim+1 for rational cvs )
1250         int order,
1251         int cv_count,
1252         int cv_stride,
1253         double* cv,   // NULL or cv array with room for at least knot_multiplicity new cvs
1254         double* knot, // knot array with room for at least knot_multiplicity new knots
1255         int* hint     // optional hint about where to search for span to add knots to
1256                       // pass NULL if no hint is available
1257         )
1258 {
1259   int rc = 0; // return code = number of knots added
1260 
1261   if ( order < 2 || cv_count < order || !knot )
1262   {
1263     ON_ERROR("ON_InsertKnot(): illegal input" );
1264     return 0;
1265   }
1266 
1267   if ( cv )
1268   {
1269     if ( cv_dim < 1 || cv_stride < cv_dim )
1270     {
1271       ON_ERROR("ON_InsertKnot(): illegal input" );
1272       return 0;
1273     }
1274   }
1275 
1276   if ( knot_multiplicity >= order )
1277   {
1278     ON_ERROR("ON_InsertKnot(): requested knot_multiplicity > degree" );
1279     return 0;
1280   }
1281 
1282   // shift knot vector and cv array so that knot_value lies in first span
1283   int span_index = ON_NurbsSpanIndex( order, cv_count, knot, knot_value, 1, hint?*hint:0 );
1284   knot += span_index;
1285   if ( cv )
1286     cv += (span_index*cv_stride);
1287   cv_count -= span_index;
1288 
1289   const double knot_tolerance = ON_SpanTolerance( order, cv_count, knot, 0 );
1290 
1291   // check that knot_value is interior to NURBS domain
1292   if ( span_index == 0 )
1293   {
1294     if ( knot_value < knot[order-1] )
1295     {
1296       if ( knot_value <= knot[order-2] + knot_tolerance )
1297       {
1298         ON_ERROR("ON_InsertKnot(): requested knot_value at start of NURBS domain" );
1299         return 0;
1300       }
1301     }
1302   }
1303   if ( span_index == cv_count-order )
1304   {
1305     if ( knot_value > knot[order-2] && knot_value >= knot[order-1] - knot_tolerance )
1306     {
1307       ON_ERROR("ON_InsertKnot(): requested knot_value at end of NURBS domain" );
1308       return 0;
1309     }
1310   }
1311 
1312   // if knot_value is nearly equal to an existing knot, make it exactly equal
1313   if ( knot_value <= 0.5*(knot[order-2]+knot[order-1]) && fabs( knot_value - knot[order-2] ) <= knot_tolerance ) {
1314     knot_value = knot[order-2];
1315   }
1316   else if ( fabs( knot_value - knot[order-1] ) <= knot_tolerance ) {
1317     knot_value = knot[order-1];
1318   }
1319 
1320   const int degree = order-1;
1321 
1322   // set m = number of knots to add
1323   int m = 0;
1324   int j;
1325   if ( knot_value == knot[order-2] ) {
1326     for ( j = order-2; m < knot_multiplicity && knot[j-m] == knot_value; m++ )
1327       ; // empty for
1328   }
1329   else if ( knot_value == knot[order-1] ) {
1330     for ( j = order-1; m < knot_multiplicity && knot[j+m] == knot_value; m++ )
1331       ; // empty for
1332   }
1333   m = knot_multiplicity - m;
1334   if ( hint )
1335     *hint = span_index+m;
1336 
1337   if ( m <= 0 )
1338     return 0; // no knots need to be added
1339 
1340   double* new_knot = (double*)onmalloc( ((2*degree+m) + (order+m)*cv_dim)*sizeof(*new_knot) );
1341   if ( !new_knot ) {
1342     ON_ERROR("ON_InsertKnot(): out of memory");
1343     return 0;
1344   }
1345   double* new_cv = 0;
1346   memcpy( new_knot, knot, 2*degree*sizeof(*new_knot) );
1347   if ( cv ) {
1348     new_cv = new_knot + (2*degree+m);
1349     for ( j = 0; j < order; j++ ) {
1350       memcpy( new_cv + j*cv_dim, cv + j*cv_stride, cv_dim*sizeof(*new_cv) );
1351     }
1352   }
1353 
1354   // add m more knots at knot_value
1355   rc = 0;
1356   while (m>0) {
1357     if ( !ON_InsertSingleKnot(cv_dim,order,cv_dim,new_cv,new_knot,knot_value) )
1358       break;
1359     m--;
1360     if ( new_cv )
1361       new_cv += cv_stride;
1362     new_knot++;
1363     rc++;
1364   }
1365   new_knot -= rc;
1366   new_cv -= rc*cv_stride;
1367 
1368   if ( rc > 0 ) {
1369     // make room for rc many new knots
1370     int i0 = ON_KnotCount( order, cv_count ) - 1; // knot[i0] = last input knot
1371     int i1 = i0 + rc;
1372     int j  = (cv_count-order);
1373     while (j--)
1374       knot[i1--] = knot[i0--];
1375 
1376     // update knot vector
1377     memcpy ( knot+degree, new_knot+degree, (degree+rc)*sizeof(*new_knot) );
1378 
1379     if ( cv ) {
1380       // make room for rc many new CVs
1381       i0 = (cv_count-1)*cv_stride;             // cv[i0] = last coord of last input cv */
1382       i1 = i0 + rc*cv_stride;
1383       j = cv_count-order;
1384       while (j--) {
1385         memcpy( cv+i1, cv+i0, cv_dim*sizeof(*cv) );
1386         i1 -= cv_stride;
1387         i0 -= cv_stride;
1388       }
1389 
1390       // update cv values
1391       for ( j = 0; j < order+rc; j++ ) {
1392         memcpy( cv, new_cv, cv_dim*sizeof(*new_cv) );
1393         cv += cv_stride;
1394         new_cv += cv_dim;
1395       }
1396     }
1397 
1398   }
1399 
1400   onfree(new_knot);
1401 
1402   return rc;
1403 }
1404 
1405