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