INOS
cinosnurbscurve.h
Go to the documentation of this file.
1//******************************************************************************
26//******************************************************************************
27#ifndef INC_CINOSNURBSCURVE_H
28#define INC_CINOSNURBSCURVE_H
29//------------------------------------------------------------------------------
30// defines
31//------------------------------------------------------------------------------
32//
33#define DF_INOS_NURBSCURVE_UNDIFINED_SEG_INDEX 0xFFFFFFFF
34
35// --- general -----------------------------------------------------------------
36//
37typedef double _vector[DF_INOS_NURBSCURVE_MAX_DEGREE+1];
39//
40//------------------------------------------------------------------------------
41// includes
42//------------------------------------------------------------------------------
43//
44// system
45#include <inos.h>
46#include <inosstdtypes.h>
47#include <cinosnurbspoint.h>
48#include <cinosspline.h>
49
50//
51// C++
52//
53// project
54//
55//------------------------------------------------------------------------------
56// class definition
57//------------------------------------------------------------------------------
58//
59// Binomial coefficient up to 5
60static constexpr double BinCoeff[6 * 6] = {
61 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
62 1.0, 1.0, 0.0, 0.0, 0.0, 0.0,
63 1.0, 2.0, 1.0, 0.0, 0.0, 0.0,
64 1.0, 3.0, 3.0, 1.0, 0.0, 0.0,
65 1.0, 4.0, 6.0, 5.0, 1.0, 0.0,
66 1.0, 5.0, 10.0, 10.0, 5.0, 1.0
67};
68
69template <int N> class CINOSNurbsCurve
70{
71 //--- user interface ---------------------------------------------------
72
73 // public member functions
74 public :
75
78 {
79 // check point weight
80 if (aPoint.w != 0.0) {
81 // remove all zero flag
82 m_uFlags &= ~eFlgZeroWeight;
83 // custom weight ?
84 if (aPoint.w != 1.0) {
85 // yes
86 m_uFlags |= eFlgCustomWeight;
87 } // end if
88 }
89 // remove curve valid flag
90 m_uFlags &= ~eFlgCurveValid;
91 // add point to vector
92 P.push_back(aPoint);
93 }
94
97 {
99 // copy coordinates
100 for (uint32 i=0; i<N; i++) {
101 p[i] = aPoint[i];
102 }
103 // finally add it
104 AddPoint(p);
105 }
106
108 void AddKnot(double adKnot, uint32 auMultiplicity)
109 {
110 // add knot values
111 for (uint32 i=0; i<auMultiplicity; i++){
112 // add knot
113 U.push_back(adKnot);
114 }
115 // remove curve valid flag
116 m_uFlags &= ~eFlgCurveValid;
117 }
118
120 void SetPoints(uint32 auPoints)
121 {
122 // resize vector
123 P.reserve(auPoints);
124 }
125
127 uint32 GetPoints()
128 {
129 // return vector size
130 return (uint32)P.size();
131 }
132
135 {
136 // Ensure we have at least 2 points (start and end).
138 }
139
141 uint32 Check()
142 {
143 // remove curve valid flag
144 m_uFlags &= ~eFlgCurveValid;
145
146 // check degree
147 if ((D < 1) || (D > DF_INOS_NURBSCURVE_MAX_DEGREE)) {
148 // invalid degree selected
150 } // end if
151
152 // we need at least degree+1 control points
153 if (P.size() < (D+1)) {
154 // not enough control points, delevate degree if possible
155 if (P.size() > 1) {
156 // adjust degree
157 D = (int)(P.size() - 1);
158 } // end if
159 else {
160 // not possible
162 } // end else
163 } // end if
164
165 // at least one control point weith needs to be != 0
166 if (m_uFlags & eFlgZeroWeight) {
167 // all control point weights are zero
169 } // end if
170
171 // knots defined ?
172 if (0 == U.size()) {
173 // no -> assume uniform, clamped nodes
174 // first node : value = 0, multiplicity = degree+1 (e.g. 0,0,0,0)
175 // mid nodes : value = 1/(points-degree)
176 // last node : value = 1, multiplicity = degree+1 (e.g. 1,1,1,1)
177 AddKnot(0.0, D+1);
178 double dk = 1.0/double(P.size()-D);
179 for (uint32 i=1; i<(P.size()-D); i++) {
180 AddKnot(double(i) * dk, 1);
181 } // end for
182 AddKnot(1.0, D+1);
183 }
184
185 // we need points+degree+1 knots
186 if (U.size() != (P.size()+D+1)) {
187 // wrong number of knots
189 } // end if
190
191 // curve is flag
192 m_uFlags |= eFlgCurveValid;
193
194 // ok
195 return INOS_OK;
196 }
197
198 static constexpr double d43 = 4.0/3.0;
199 static constexpr double d13 = 1.0/3.0;
200
202 double GetLength()
203 {
204 return m_dLength;
205 }
206
207 uint32 Prepare()
208 {
209 // Curve Vaild
210 if((m_uFlags & eFlgCurveValid) == 0) {
211 // Not valid? Check again.
212 uint32 uError = Check();
213 if(uError) {
214 return uError;
215 }
216 }
217
218 // Reset position UofP cache channel for Run.
219 m_sPreviousCache[0].m_uPSpan = 0;
220 m_sPreviousCache[0].m_uSplineIndex = 1;
221 m_sPreviousCache[0].m_uUSpan = D;
222 m_sPreviousCache[0].m_uSegment = 0;
223 m_sPreviousCache[0].m_dDistanceSegBeg = -1.0;
224 m_sPreviousCache[0].m_dDistanceSegEnd = -1.0;
225 m_sPreviousCache[0].m_dP = 0.0;
226
227 // Already prepared?
228 if(m_uFlags & eFlgPrepared) {
229 // Already prepared
230 return 0;
231 }
232
233 // Number of points
234 uint32 uNoP = (uint32)P.size();
235
236 // Splines that interpolate P -> U function
237 m_UofPs.resize(uNoP - 1, nullptr);
238
239
240 // Check for only 2 points and no length
241 if(uNoP == 2 && P[0] == P[1]) {
242 // No length
243 m_dLength = 0.0;
244
245 // Make dummy spline
246 m_UofPs[0] = new CINOSSpline(2);
247
248 // Get shortcut
249 auto Spline = m_UofPs[0];
250
251 // Set first U of P point
252 Spline->SetPoint(0, 0.0, 0.0);
253 // Set second/last U of P point
254 Spline->SetPoint(1, 1.0, 0.0);
255
256 Spline->Calc(false);
257 // curve is prepared
258 m_uFlags |= eFlgPrepared;
259 // return result
260 return 0;
261 }
262
263 // Three points needed for length calculation
267
268 // Temporary lengths
269 double l1 = 0.0;
270 double l2 = 0.0;
271 double ldiff = 0.0;
272
273 // Total length
274 double L = 0.0;
275
276 // Current u value
277 double u = 0.0;
278 // U value of current segment begining
279 double uSeg = 0.0;
280
281 // Delta values
282 const double dUSeg = U.back() / double(uNoP - 1);
283 const double du = dUSeg / double(m_uInterpolationPoints-1);
284 const double du_2 =du * 0.5;
285 const double du_edge =du * 0.0001;
286
287 // Get first point
288 GetPositionU(0.0, point1);
289 for(uint32 uIxP = 0; uIxP < uNoP - 1; uIxP++) {
290 // Create new spline
292
293 // Get shortcut
294 auto Spline = m_UofPs[uIxP];
295
296 // Set first U of P point
297 Spline->SetPoint(0, L, u);
298
299 // Recalculate uSeg and u to minimize numerical errors.
300 uSeg = u = dUSeg * (double)uIxP;
301
302 // get second point for edge 1st derivative calculation
305
306 // Check length non-zero
307 if(ldiff == 0.0) {
308 // length is zero -> remove curve valid flag
309 m_uFlags &= ~eFlgCurveValid;
310 // return error
312 }
313 // 1st derivative at begining of the spline
314 double vStart = du_edge / ldiff;
315
316 // calc length of the current points
317 // the algorithm can be found here :
318 // https://math.stackexchange.com/questions/777830/simpsons-rule-like-method-for-arc-length-approximation
319 // this version is doing the calculation iteratively
320 for (uint32 uIx =1; uIx <m_uInterpolationPoints; uIx ++){
321 // Get two more points for length calculation
324
325 // Calculate the lengths
329
330 // Calculate adjusted length
331 ldiff = d43 * l1 - d13 * l2;
332
333 // Check lengths non-zero
334 if(ldiff == 0.0) {
335 // length is zero -> remove curve valid flag
336 m_uFlags &= ~eFlgCurveValid;
337 // return error
339 }
340
341 // Add adjusted length
342 L = L + ldiff;
343
344 // Calculate the new u
345 u = uSeg + uIx * du;
346
347 // Move the last point to the new first point
348 point1 = point3;
349
350 // Set the new U of P point
351 Spline->SetPoint(uIx, L, u);
352 }
353
354 // Get a point just before the last point to calculate edge 1st derivative
357
358 // Check length non-zero
359 if(l1 == 0.0) {
360 // length is zero -> remove curve valid flag
361 m_uFlags &= ~eFlgCurveValid;
362 // return error
364 }
365
366 // Calculate the 1st derivative
367 double vSEnd = du_edge / l1;
368
369 // Finally calculate the spline for this segment of the nurbs.
370 Spline->Calc(true, CINOSSpline::eBt1stDeriv, vStart,
371 CINOSSpline::eBt1stDeriv, vSEnd, false);
372 }
373
374 // Store the calculated length
375 m_dLength = L;
376
377 // curve is prepared
378 m_uFlags |= eFlgPrepared;
379 // return result
380 return 0;
381 }
382
384 virtual void GetPosition(double adP, TINOSVector<N>& ovPos)
385 {
386 // project P to U (use channel 0)
387 double u = GetLocalU(adP, 0);
388 // calc position at U
390 }
391
393 virtual void GetPosition(double adP, TINOSVector<N>& ovPos, uint32& auSegment)
394 {
395 // project P to U (use channel 0)
396 double u = GetLocalU(adP, 0);
397 // calc position at U
399 // get actual segment (use channel 0)
400 auSegment = GetSegment(0, adP, ovPos);
401 }
402
405 {
406 // project P to u
407 GetPositionU(U.front(), ovPos);
408 }
409
412 {
413 // project P to u
414 GetPositionU(U.back(), ovPos);
415 }
416
419 {
420 if(adU<=U[D]) {
421 m_sPreviousCache[0].m_uUSpan = D;
422 }
423 else if(adU>=U[P.size()]) {
424 m_sPreviousCache[0].m_uUSpan = (uint32)(P.size()-1);
425 }
426 else if(m_sPreviousCache[0].m_uPSpan == DF_INOS_NURBSCURVE_UNDIFINED_SEG_INDEX) {
427 m_sPreviousCache[0].m_uUSpan = FindSpan(adU);
428 }
429 else if(adU >= U[m_sPreviousCache[0].m_uUSpan + 1]) {
430 do {
431 m_sPreviousCache[0].m_uUSpan++;
432 }
433 while(adU >= U[m_sPreviousCache[0].m_uUSpan + 1]);
434 }
435 else if(adU < U[m_sPreviousCache[0].m_uUSpan]) {
436 do {
437 m_sPreviousCache[0].m_uUSpan--;
438 }
439 while(adU < U[m_sPreviousCache[0].m_uUSpan]);
440 }
441
442 GetPositionU(adU, ovPos, m_sPreviousCache[0].m_uUSpan);
443 }
444
446 inline void GetPositionU(double adU, TINOSVector<N>& ovPos)
447 {
449 }
450
452 virtual void GetPositionU(double adU, TINOSVector<N>& ovPos, uint32 auUSpan)
453 {
454 // locals
455 _vector Nb;
457 ovPos.Set(0.0);
458 // custom weights ?
459 if (!(m_uFlags & eFlgCustomWeight)) {
460 // no
461 for(uint32 i=0;i<=D;i++) {
462 ovPos = ovPos + (Nb[i] * P[auUSpan-D+i]);
463 } // end for
464 } // end if
465 else {
466 // yes
467 double w = 0.0;
468 for(uint32 i=0;i<=D;i++) {
469 uint32 ii = auUSpan-D+i;
470 double ww = Nb[i] * P[ii].w;
471 w += ww;
472 ovPos = ovPos + (ww * P[ii]);
473 }
474 if(w != 0.0) {
475 ovPos = ovPos * (1.0/w);
476 }
477 } // end else
478 }
479
481 virtual void GetDerivative(uint32 auLevel, double adP, TINOSVector<N>& ovDer)
482 {
483 // project P to U (use channel auLevel)
484 double u = GetLocalU(adP, auLevel);
485 // calc derivative at U
486 GetDerivativeU(auLevel, u, ovDer);
487 }
488
491 {
492 // call base
493 GetDerivativeU(auLevel, U.front(), ovDer);
494 }
495
498 {
499 // call base
500 GetDerivativeU(auLevel, U.back(), ovDer);
501 }
502
503
506 virtual void GetDerivativeU(uint32 auLevel, double adU, TINOSVector<N>& ovDer)
507 {
508 // ensure correct parameter
509 if (adU > U.back()) adU = U.back();
510 else if (adU < U.front()) adU = U.front();
511
512 // calc derivatives
515 // check level
516 if (auLevel == 1) {
517 // norm to direction vector
518 double l = ders[1].GetMaskedLength(m_uLengthMask);
519 if(l == 0.0) {
520 // no movement, derivative is zero
521 ovDer = 0.0;
522 }
523 else {
524 ovDer = 1.0/l * ders[1];
525 }
526 } // end if
527 else if (auLevel == 2) {
528 double dotProd = 0.0;
529 double div = 0.0;
530 for(int i = 0; i < N; i++) {
531 if (!(m_uLengthMask & (1<<i))){
532 dotProd += ders[1][i] * ders[2][i];
533 div += ders[1][i] * ders[1][i];
534 }
535 }
536 if(div == 0.0) {
537 // no movement, derivative is zero
538 ovDer = 0.0;
539 return;
540 }
541 dotProd /= div;
542 for(int i = 0; i < N; i++) {
543 if (!(m_uLengthMask & (1<<i))){
544 ovDer[i] = ders[2][i] - dotProd * ders[1][i];
545 }
546 else {
547 ovDer[i] = ders[2][i] ;
548 }
549 }
550
551 double l = ovDer.GetMaskedLength(m_uLengthMask);
552
553 // norm to curvature vector
554 div = ders[1].GetMaskedLength(m_uLengthMask);
555
556 if(l > 0.0) {
557 div = div * div * div * l;
558
559
560 // Cross product calculation
561 double dNom;
562 uint8 (&ixs)[N] = m_uLengthDims;
563
564 if(m_uNoLengthDims == 2) {
565 dNom = ders[1][ixs[0]] * ders[2][ixs[1]] - ders[1][ixs[1]] * ders[2][ixs[0]];
566 }
567 else if (m_uNoLengthDims == 3 && (N > 2)) { // (N > 2) only checked to please the compiler
569 crossProd[0] = ders[1][ixs[1]] * ders[2][ixs[2]] - ders[1][ixs[2]] * ders[2][ixs[1]];
570 crossProd[1] =ders[1][ixs[2]] * ders[2][ixs[0]] - ders[1][ixs[0]] * ders[2][ixs[2]];
571 crossProd[2] = ders[1][ixs[0]] * ders[2][ixs[1]] - ders[1][ixs[1]] * ders[2][ixs[0]];
572
573 dNom = crossProd.GetLength();
574 }
575 else {
576 // not supported
577 ovDer = 0.0;
578 return;
579 }
580 ovDer = (dNom / div) * ovDer;
581
582 }
583 else {
584 double acc = ders[2].GetMaskedLength(m_uLengthMask)
585 / (div * div * div);
586 double nom = 1 / (div * div);
587 for(int i = 0; i < N; i++) {
588 if (m_uLengthMask & (1<<i)){
589 ovDer[i] = nom * ovDer[i]
590 + acc * ders[1][i];
591 }
592 }
593 }
594 } // end if
595 else {
596 // not supported
597 // for 3rd derivative use approximation in GetD3max
598 ovDer = 0.0;
599 } // end else
600 }
601
604 {
605 // locals
606 double u = U.front();
607 ovD2Max = 0.0;
608 // search max. second
609 double d = (U.back() - u)/double(m_uInterpolationPoints);
610 while (u<U.back()){
611 // calc D2
613 GetDerivativeU(2, u, derivatives);
614 for (uint32 i=0; i<N; i++){
615 // calc normalised D2
616 double dD2 = fabs(derivatives[i]);
617 // check max
618 if (dD2 > ovD2Max[i]){
619 // set new max
620 ovD2Max[i] = dD2;
621 } // end if
622 } // end for
623 u += d;
624 } // end if
625 }
626
629 {
630 //handled in CINOSMovePathInterpolatorNurbs
631 ovD3Max = 0;
632 } // end GetD3max
633
635 double GetGlobalU(double adP)
636 {
637 if(adP <= 0.0) {
638 return 0.0;
639 }
640 if(adP >= m_dLength) {
641 return U.back();
642 }
643 // locals
644 uint32 i;
645 uint32 l = 0;
646 uint32 u = m_UofPs.size();
647 // binary search
648 do {
649 i = (l+u)>>1;
650 // p in upper part ?
651 if (adP > m_UofPs[i]->GetMaxX()) {
652 l = i;
653 }
654 else if (adP < m_UofPs[i]->GetMinX()){
655 // no
656 u = i;
657 }
658 else {
659 break;
660 }
661 } while (l != u);
662
664 return m_UofPs[i]->GetY(adP, uIndex);
665 }
666
667 double GetLocalU(double adP, uint32 auChannel)
668 {
669 if(adP <= 0.0) {
670 m_sPreviousCache[auChannel].m_uPSpan = 0;
671 m_sPreviousCache[auChannel].m_uSplineIndex = 1;
672 return 0.0;
673 }
674 if(adP >= m_dLength) {
675 m_sPreviousCache[auChannel].m_uPSpan = (uint32)(m_UofPs.size() - 1);
676 m_sPreviousCache[auChannel].m_uSplineIndex = m_uInterpolationPoints - 1;
677 return U.back();
678 }
679 if(m_sPreviousCache[auChannel].m_uPSpan == DF_INOS_NURBSCURVE_UNDIFINED_SEG_INDEX) {
680 // locals
681 uint32 i;
682 uint32 l = 0;
683 uint32 u = (uint32)m_UofPs.size();
684 // binary search
685 do {
686 i = (l+u)>>1;
687 // p in upper part ?
688 if (adP > m_UofPs[i]->GetMaxX()) {
689 l = i;
690 }
691 else if (adP < m_UofPs[i]->GetMinX()){
692 // no
693 u = i;
694 }
695 else {
696 break;
697 }
698 } while (l != u);
699 m_sPreviousCache[auChannel].m_uPSpan = i;
700 }
701 else if(adP >= m_UofPs[m_sPreviousCache[auChannel].m_uPSpan]->GetMaxX()) {
702 do {
703 m_sPreviousCache[auChannel].m_uPSpan++;
704 }
705 while(adP >= m_UofPs[m_sPreviousCache[auChannel].m_uPSpan]->GetMaxX());
706
707 m_sPreviousCache[auChannel].m_uSplineIndex = 1;
708 }
709 else if(adP < m_UofPs[m_sPreviousCache[auChannel].m_uPSpan]->GetMinX()) {
710 do {
711 m_sPreviousCache[auChannel].m_uPSpan--;
712 }
713 while(adP < m_UofPs[m_sPreviousCache[auChannel].m_uPSpan]->GetMinX());
714
715 m_sPreviousCache[auChannel].m_uSplineIndex = m_uInterpolationPoints - 1;
716 }
717
718 return m_UofPs[m_sPreviousCache[auChannel].m_uPSpan]->
719 GetY(adP, m_sPreviousCache[auChannel].m_uSplineIndex);
720 }
721
722 //--- internals --------------------------------------------------------
723
724 friend class CINOSMovePath;
725
726 // constructor / destructor
727 public :
731 uint32 auLengthMask = 0xFFFFFFF8)
734 m_UofPs(0)
735
736 {
738
739 for(uint32 uD = 0; uD<N; uD++) {
740 if((m_uLengthMask&(1<<uD)) == 0) {
743 }
744 }
745
746 // init calculation channels
747 memset(&m_sPreviousCache, 0, sizeof(m_sPreviousCache));
748 for (uint32 i=0; i<eCnsMaxChannels; i++) {
749 m_sPreviousCache[i].m_uPSpan = DF_INOS_NURBSCURVE_UNDIFINED_SEG_INDEX;
750 m_sPreviousCache[i].m_uSplineIndex = DF_INOS_SPLINE_BINARY_SEARCH_INDEX;
751 m_sPreviousCache[i].m_uSegment = 0;
752 m_sPreviousCache[i].m_dDistanceSegBeg = -1.0;
753 m_sPreviousCache[i].m_dDistanceSegEnd = -1.0;
754 m_sPreviousCache[i].m_dP = 0.0;
755 }
756 }
757
760 {
761 for(auto spline : m_UofPs) {
762 if(spline != nullptr) {
763 delete spline;
764 }
765 }
766 }
767
768 // protected methods
769 protected :
770
772 uint32 FindSpan(double u) const
773 {
774 if(u>=U[P.size()])
775 return (uint32)(P.size()-1) ;
776 if(u<=U[D])
777 return D ;
778 int low = D;
779 int high = (int)(P.size()+1) ;
780 int mid = (low+high)/2 ;
781 while(u<U[mid] || u>= U[mid+1]){
782 if(u<U[mid])
783 high = mid ;
784 else
785 low = mid ;
786 mid = (low+high)/2 ;
787 }
788 return mid ;
789 }
790
792 void BasisFuns(double u, uint32 i, _vector& Nb) const
793 {
795 double* right = &left[D+1] ;
796 double temp,saved ;
797 Nb[0] = 1.0 ;
798 for(uint32 j=1; j<= D ; j++){
799 left[j] = u-U[i+1-j] ;
800 right[j] = U[i+j]-u ;
801 saved = 0.0 ;
802 for(uint32 r=0 ; r<j; r++){
803 temp = Nb[r]/(right[r+1]+left[j-r]) ;
804 Nb[r] = saved+right[r+1] * temp ;
805 saved = left[j-r] * temp ;
806 }
807 Nb[j] = saved ;
808 }
809 }
810
812 void DersBasisFuns(uint32 n, double u, uint32 span, _matrix& ders) const
813 {
814 double left[2*(DF_INOS_NURBSCURVE_MAX_DEGREE+1)] ;
815 double* right = &left[D+1] ;
816 _matrix ndu;
817 double saved,temp ;
818 int j,r ;
819 ndu[0][0] = 1.0 ;
820 for(int j=1; j<=(int)D ;j++){
821 left[j] = u-U[span+1-j] ;
822 right[j] = U[span+j]-u ;
823 saved = 0.0 ;
824 for(r=0;r<j ; r++){
825 // Lower triangle
826 ndu[j][r] = right[r+1]+left[j-r] ;
827 temp = ndu[r][j-1]/ndu[j][r] ;
828 // Upper triangle
829 ndu[r][j] = saved+right[r+1] * temp ;
830 saved = left[j-r] * temp ;
831 }
832 ndu[j][j] = saved ;
833 }
834
835 for(int j=(int)D;j>=0;--j)
836 ders[0][j] = ndu[j][D];
837
838 // Compute the derivatives
839 _matrix a;
840 for (int r=0;r<=(int)D;r++) {
841 int s1,s2 ;
842 s1 = 0 ; s2 = 1 ; // alternate rows in array a
843 a[0][0] = 1.0 ;
844 // Compute the kth derivative
845 for (int k=1;k<=(int)n;k++) {
846 double d ;
847 int rk,pk,j1,j2 ;
848 d = 0.0 ;
849 rk = r-k ; pk = D-k ;
850 if (r>=k) {
851 a[s2][0] = a[s1][0]/ndu[pk+1][rk];
852 d = a[s2][0]*ndu[rk][pk] ;
853 }
854 if(rk>=-1){
855 j1 = 1 ;
856 }
857 else {
858 j1 = -rk ;
859 }
860 if(r-1 <= pk){
861 j2 = k-1 ;
862 }
863 else {
864 j2 = D-r ;
865 }
866 for (j=j1;j<=j2;j++){
867 a[s2][j] = (a[s1][j]-a[s1][j-1])/ndu[pk+1][rk+j];
868 d += a[s2][j]*ndu[rk+j][pk];
869 }
870 if (r<=pk) {
871 a[s2][k] = -a[s1][k-1]/ndu[pk+1][r];
872 d += a[s2][k]*ndu[r][pk] ;
873 }
874 ders[k][r] = d ;
875 j = s1 ; s1 = s2 ; s2 = j ; // Switch rows
876 }
877 }
878 // Multiply through by the correct factors
879 r = D ;
880 for(int k=1;k<=(int)n;k++){
881 for(int j=(int)D;j>=0;--j)
882 ders[k][j] *= r ;
883 r *= D-k ;
884 }
885 }
886
887
889 void CurveDerivs(double u, uint32 d, _array_vector& ck)
890 {
891 // locals
892 uint32 du = d;
893 if (D<du) du = D;
894 for (uint32 k=D+1; k<=d; k++) ck[k] = 0.0;
895 uint32 span = FindSpan(u) ;
896 _matrix nders;
898
899 if(m_uFlags & eFlgCustomWeight) {
900 // Get the weighted derivatives (Aders) and weight derivatives (wders)
901 // needed for algorithm below
904
905 for(int k=du;k>=0;--k){
906 Aders[k] = 0.0 ;
907 for(int j=0; j<=(int)D; j++){
908 Aders[k] = Aders[k] + nders[k][j]*P[span-D+j] * P[span-D+j].w;
909 wders[k] = wders[k] + nders[k][j]*P[span-D+j].w ;
910 } // end for
911 } // end for
912
914 double wders0_inv = 1/wders[0];
915
916 for(uint32 k= 0; k<=d; k++) {
918 for(uint32 i=1; i<=k; i++)
919 v = v - BinCoeff[k * 6 + i]*wders[i]*ck[k-i];
920 ck[k] = v*wders0_inv;
921 }
922 }
923 else {
924 for(int k=du;k>=0;--k){
925 ck[k] = 0.0 ;
926 for(int j=0; j<=(int)D; j++){
927 ck[k] = ck[k] + nders[k][j]*P[span-D+j] ;
928 } // end for
929 } // end for
930 }
931 }
932
933 uint32 GetSegment (uint32 auChannel, double adP, TINOSVector<N>& ovPos)
934 {
935 // locals
936 auto& cnl = m_sPreviousCache[auChannel];
937
938 // first call ?
939 if (cnl.m_dDistanceSegEnd<0.0){
940 // yes -> calc distance
941 cnl.m_dDistanceSegEnd = (P[1]-ovPos).GetMaskedLength2(m_uLengthMask);
942 cnl.m_dDistanceSegBeg = (P[0]-ovPos).GetMaskedLength2(m_uLengthMask);
943 cnl.m_uSegment = 0;
944 }
945 // moving forward?
946 else if(adP > cnl.m_dP) {
947 // avoid overflows
948 if (cnl.m_uSegment < P.size()-2) {
949 // calc distance to segment end
950 double dDistanceOld = cnl.m_dDistanceSegEnd;
951 cnl.m_dDistanceSegEnd =
952 (P[cnl.m_uSegment+1]-ovPos).GetMaskedLength2(m_uLengthMask);
953 // segment change ?
954 if (dDistanceOld<cnl.m_dDistanceSegEnd){
955 // yes
956 cnl.m_uSegment++;
957 // Last end is the new begin
958 cnl.m_dDistanceSegBeg = cnl.m_dDistanceSegEnd;
959 // recalc distance to next segment
960 cnl.m_dDistanceSegEnd =
961 (P[cnl.m_uSegment+1]-ovPos).GetMaskedLength2(m_uLengthMask);
962 } // end if
963 else {
964 // update begin in case of turn around.
965 cnl.m_dDistanceSegBeg =
967 } // end if
968 }
969 else {
970 // update begin in case of turn around.
971 cnl.m_dDistanceSegBeg =
973 } // end if
974 }
975 // moving backward?
976 else if(adP < cnl.m_dP) {
977 // avoid undeflows
978 if (cnl.m_uSegment > 0) {
979 // calc distance to segment end
980 double dDistanceOld = cnl.m_dDistanceSegBeg;
981 cnl.m_dDistanceSegBeg =
983 // segment change ?
984 if (dDistanceOld<cnl.m_dDistanceSegEnd){
985 // yes
986 cnl.m_uSegment--;
987 // Last begin is the new end
988 cnl.m_dDistanceSegEnd = cnl.m_dDistanceSegBeg;
989 // recalc distance to next segment
990 cnl.m_dDistanceSegBeg = (P[cnl.m_uSegment]-ovPos).GetLength2(m_uLengthMask);
991 } // end if
992 else {
993 // update end in case of turn around.
994 cnl.m_dDistanceSegEnd = (P[cnl.m_uSegment+1]-ovPos).GetLength2(m_uLengthMask);
995 } // end if
996 }
997 else {
998 // update end in case of turn around.
999 cnl.m_dDistanceSegEnd = (P[cnl.m_uSegment+1]-ovPos).GetLength2(m_uLengthMask);
1000 } // end if
1001 }
1002
1003
1004 cnl.m_dP = adP;
1005 // return result
1006 return cnl.m_uSegment;
1007 }
1008
1009 // protected members
1010 protected:
1011
1012 // curve flags
1013 enum {
1014 eFlgPrepared = 0x00000001, //<! curve is prepared
1015 eFlgCustomWeight = 0x00000002, //<! control points with custom weights
1016 eFlgZeroWeight = 0x00000004, //<! all control points have zero weight
1017 eFlgCurveValid = 0x00000008, //<! curve is valid
1018 };
1019 enum {
1020 eCnsMaxChannels = 4,
1021 };
1022
1024 uint32 m_uFlags = eFlgZeroWeight;
1026 uint32 D = 1;
1028 const uint32 m_uLengthMask = 0xFFFFFFF8;
1032 double m_dLength = std::numeric_limits<double>::quiet_NaN();
1034 inos_std::vector<CINOSNurbsPoint<N>> P;
1036 inos_std::vector<double> U;
1037
1042
1043
1044 // Previous values cache for local get function
1063
1064 inos_std::vector<CINOSSpline*> m_UofPs;
1065
1066 // dynamic object handling
1068};
1069
1071
1072//------------------------------------------------------------------------------
1073// end of file
1074//------------------------------------------------------------------------------
1075
1076#endif // INC_CINOSNURBSCURVE_H
The CINOSNurbsPoint class.
#define DECLARE_DYNAMIC_N(aClass, aN)
Definition cinospartitionmemory.h:338
#define IMPLEMENT_DYNAMIC_N(aClass, aN)
Definition cinospartitionmemory.h:373
Definition cinosmcmodule.h:1900
Definition cinosmovepath.h:566
Definition cinosnurbscurve.h:70
TINOSVector< N > _array_vector[DF_INOS_NURBSCURVE_MAX_DEGREE+1]
get auLevel derivative at param 'adU' (The NURBS book, page 93, A3.2)
Definition cinosnurbscurve.h:505
virtual void GetPositionLast(TINOSVector< N > &ovPos)
get last position
Definition cinosnurbscurve.h:411
void AddPoint(TINOSVector< N > &aPoint)
add control point to curve
Definition cinosnurbscurve.h:96
void BasisFuns(double u, uint32 i, _vector &Nb) const
compute the nonvanishing basis functions (The NURBS book, page 70, A2.2)
Definition cinosnurbscurve.h:792
void DersBasisFuns(uint32 n, double u, uint32 span, _matrix &ders) const
compute nonzero basis functions and their derivatives (The NURBS book, page 72, A2....
Definition cinosnurbscurve.h:812
uint32 m_uFlags
flags
Definition cinosnurbscurve.h:1024
virtual void GetD2max(TINOSVector< N > &ovD2Max)
get max. second derivative over the whole curve
Definition cinosnurbscurve.h:603
uint8 m_uNoLengthDims
numeber of length relevant dimensions
Definition cinosnurbscurve.h:1041
virtual void GetDerivativeEnd(uint32 auLevel, TINOSVector< N > &ovDer)
get auLevel derivative at curve end
Definition cinosnurbscurve.h:497
void GetPositionU(double adU, TINOSVector< N > &ovPos)
get position at param 'adU' (The NURBS book, page 124, A4.1)
Definition cinosnurbscurve.h:446
double GetLength()
get curve length
Definition cinosnurbscurve.h:202
uint32 m_uInterpolationPoints
curve interpolation points
Definition cinosnurbscurve.h:1030
uint8 m_uLengthDims[N]
length relevant dimensions indices
Definition cinosnurbscurve.h:1039
virtual void GetPositionFirst(TINOSVector< N > &ovPos)
get first position
Definition cinosnurbscurve.h:404
void CurveDerivs(double u, uint32 d, _array_vector &ck)
compute curve derivatives (The NURBS book, page 93, A3.2)
Definition cinosnurbscurve.h:889
uint32 Check()
check curve
Definition cinosnurbscurve.h:141
virtual void GetDerivativeBgn(uint32 auLevel, TINOSVector< N > &ovDer)
get auLevel derivative at curve begin
Definition cinosnurbscurve.h:490
inos_std::vector< double > U
knot vector
Definition cinosnurbscurve.h:1036
virtual void GetD3max(TINOSVector< N > &ovD3Max)
get max. 3rd derivative over the whole curve
Definition cinosnurbscurve.h:628
double GetGlobalU(double adP)
approximately project P tu U
Definition cinosnurbscurve.h:635
virtual void GetPosition(double adP, TINOSVector< N > &ovPos, uint32 &auSegment)
get position at 'adP'
Definition cinosnurbscurve.h:393
void AddKnot(double adKnot, uint32 auMultiplicity)
add knot to curve
Definition cinosnurbscurve.h:108
void GetLocalPositionU(double adU, TINOSVector< N > &ovPos)
get position at param 'adU' (The NURBS book, page 124, A4.1)
Definition cinosnurbscurve.h:418
inos_std::vector< CINOSNurbsPoint< N > > P
control points
Definition cinosnurbscurve.h:1034
CINOSNurbsCurve(uint32 auDegree=DF_INOS_NURBSCURVE_MAX_DEGREE, uint32 auInterpolationPoints=DF_INOS_NURBSCURVE_INTERPOLATION_POINTS, uint32 auLengthMask=0xFFFFFFF8)
constructor
Definition cinosnurbscurve.h:729
virtual ~CINOSNurbsCurve()
destructor
Definition cinosnurbscurve.h:759
void AddPoint(CINOSNurbsPoint< N > &aPoint)
add control point to curve
Definition cinosnurbscurve.h:77
void SetPoints(uint32 auPoints)
set number of control points
Definition cinosnurbscurve.h:120
double m_dLength
curve length
Definition cinosnurbscurve.h:1032
uint32 D
curve degree
Definition cinosnurbscurve.h:1026
virtual void GetDerivative(uint32 auLevel, double adP, TINOSVector< N > &ovDer)
get auLevel derivative at 'adP'
Definition cinosnurbscurve.h:481
uint32 FindSpan(double u) const
determine the knot span index (The NURBS book, page 68, A2.1)
Definition cinosnurbscurve.h:772
const uint32 m_uLengthMask
length mask (bit = 1 -> axis is not length relevant)
Definition cinosnurbscurve.h:1028
virtual void GetPositionU(double adU, TINOSVector< N > &ovPos, uint32 auUSpan)
get position at param 'adU' (The NURBS book, page 124, A4.1)
Definition cinosnurbscurve.h:452
void SetInterpolationPoints(uint32 auInterpolationPoints)
set number of interpolation points
Definition cinosnurbscurve.h:134
uint32 GetPoints()
get number of control points
Definition cinosnurbscurve.h:127
virtual void GetPosition(double adP, TINOSVector< N > &ovPos)
get position at 'adP'
Definition cinosnurbscurve.h:384
#define DF_INOS_NURBSCURVE_INTERPOLATION_POINTS
Definition inosdefault.h:188
#define DF_INOS_NURBSCURVE_MAX_DEGREE
Definition inosdefault.h:180
uint32 INOS_OK
Definition inoserror.h:1677
uint32 INOS_MOVEPATH_ERROR_NURBS_RELEVANT_LENGTH_ZERO
Definition inoserror.h:1677
uint32 INOS_MOVEPATH_ERROR_NURBS_ALL_WEIGHTS_ZERO
Definition inoserror.h:1677
uint32 INOS_MOVEPATH_ERROR_NURBS_NUMBER_OF_KNOTS_INVALID
Definition inoserror.h:1677
uint32 INOS_MOVEPATH_ERROR_NURBS_NOT_ENOUGH_POINTS
Definition inoserror.h:1677
uint32 INOS_MOVEPATH_ERROR_NURBS_DEGREE_INVALID
Definition inoserror.h:1677
Definition cinosnurbscurve.h:1045
double m_dDistanceSegEnd
Distance to segment end.
Definition cinosnurbscurve.h:1057
uint32 m_uSplineIndex
current spline index
Definition cinosnurbscurve.h:1049
uint32 m_uUSpan
current span in Us
Definition cinosnurbscurve.h:1051
uint32 m_uPSpan
current span in Ps
Definition cinosnurbscurve.h:1047
uint32 m_uSegment
current segment
Definition cinosnurbscurve.h:1053
double m_dP
P value.
Definition cinosnurbscurve.h:1059
double m_dDistanceSegBeg
Distance to segment begin.
Definition cinosnurbscurve.h:1055