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 //
37 typedef 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
60 static 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 
69 template <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 
96  void AddPoint(TINOSVector<N>& aPoint)
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 
134  void SetInterpolationPoints(uint32 auInterpolationPoints)
135  {
136  // Ensure we have at least 2 points (start and end).
137  m_uInterpolationPoints = auInterpolationPoints < 2 ? 2 : auInterpolationPoints;
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
264  TINOSVector<N> point1;
265  TINOSVector<N> point2;
266  TINOSVector<N> point3;
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
291  m_UofPs[uIxP] = new CINOSSpline(m_uInterpolationPoints);
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
303  GetPositionU(u+du_edge, point2);
304  ldiff = (point2 - point1).GetMaskedLength(m_uLengthMask) ;
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
322  GetPositionU(u+du_2, point2);
323  GetPositionU(u+du, point3);
324 
325  // Calculate the lengths
326  l1 = (point2 - point1).GetMaskedLength(m_uLengthMask)
327  + (point3 - point2).GetMaskedLength(m_uLengthMask);
328  l2 = (point3 - point1).GetMaskedLength(m_uLengthMask);
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
355  GetPositionU(u-du_edge, point2);
356  l1 = (point3 - point2).GetMaskedLength(m_uLengthMask) ;
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
389  GetLocalPositionU(u, ovPos);
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
398  GetPositionU(u, ovPos);
399  // get actual segment (use channel 0)
400  auSegment = GetSegment(0, adP, ovPos);
401  }
402 
404  virtual void GetPositionFirst(TINOSVector<N>& ovPos)
405  {
406  // project P to u
407  GetPositionU(U.front(), ovPos);
408  }
409 
411  virtual void GetPositionLast(TINOSVector<N>& ovPos)
412  {
413  // project P to u
414  GetPositionU(U.back(), ovPos);
415  }
416 
418  void GetLocalPositionU(double adU, TINOSVector<N>& ovPos)
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  {
448  GetPositionU(adU, ovPos, FindSpan(adU));
449  }
450 
452  virtual void GetPositionU(double adU, TINOSVector<N>& ovPos, uint32 auUSpan)
453  {
454  // locals
455  _vector Nb;
456  BasisFuns(adU, auUSpan, 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 
490  virtual void GetDerivativeBgn(uint32 auLevel, TINOSVector<N>& ovDer)
491  {
492  // call base
493  GetDerivativeU(auLevel, U.front(), ovDer);
494  }
495 
497  virtual void GetDerivativeEnd(uint32 auLevel, TINOSVector<N>& ovDer)
498  {
499  // call base
500  GetDerivativeU(auLevel, U.back(), ovDer);
501  }
502 
503 
505  typedef TINOSVector<N> _array_vector[DF_INOS_NURBSCURVE_MAX_DEGREE+1];
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
513  _array_vector ders;
514  CurveDerivs(adU, auLevel, ders);
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
568  TINOSVector<N> crossProd;
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 
603  virtual void GetD2max(TINOSVector<N>& ovD2Max)
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
612  TINOSVector<N> derivatives;
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 
628  virtual void GetD3max(TINOSVector<N>& ovD3Max)
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 
663  uint32 uIndex = DF_INOS_SPLINE_BINARY_SEARCH_INDEX;
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 :
730  uint32 auInterpolationPoints = DF_INOS_NURBSCURVE_INTERPOLATION_POINTS,
731  uint32 auLengthMask = 0xFFFFFFF8)
732  : D(auDegree), m_uLengthMask(auLengthMask),
733  m_uInterpolationPoints(auInterpolationPoints < 2 ? 2 : auInterpolationPoints),
734  m_UofPs(0)
735 
736  {
737  m_uNoLengthDims= 0;
738 
739  for(uint32 uD = 0; uD<N; uD++) {
740  if((m_uLengthMask&(1<<uD)) == 0) {
742  m_uNoLengthDims++;
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 
759  virtual ~CINOSNurbsCurve ()
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  {
794  double left[2*(DF_INOS_NURBSCURVE_MAX_DEGREE+1)];
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;
897  DersBasisFuns(du,u,span,nders) ;
898 
899  if(m_uFlags & eFlgCustomWeight) {
900  // Get the weighted derivatives (Aders) and weight derivatives (wders)
901  // needed for algorithm below
902  _array_vector Aders;
903  TINOSVector<N> wders;
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++) {
917  TINOSVector<N> v = Aders[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 =
966  (P[cnl.m_uSegment]-ovPos).GetMaskedLength2(m_uLengthMask);
967  } // end if
968  }
969  else {
970  // update begin in case of turn around.
971  cnl.m_dDistanceSegBeg =
972  (P[cnl.m_uSegment]-ovPos).GetMaskedLength2(m_uLengthMask);
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 =
982  (P[cnl.m_uSegment]-ovPos).GetMaskedLength2(m_uLengthMask);
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 
1039  uint8 m_uLengthDims[N];
1042 
1043 
1044  // Previous values cache for local get function
1047  uint32 m_uPSpan;
1051  uint32 m_uUSpan;
1053  uint32 m_uSegment;
1059  double m_dP;
1060 
1061 
1062  } m_sPreviousCache[eCnsMaxChannels];
1063 
1064  inos_std::vector<CINOSSpline*> m_UofPs;
1065 
1066  // dynamic object handling
1067  DECLARE_DYNAMIC_N(CINOSNurbsCurve, N);
1068 };
1069 
1071 
1072 //------------------------------------------------------------------------------
1073 // end of file
1074 //------------------------------------------------------------------------------
1075 
1076 #endif // INC_CINOSNURBSCURVE_H
CINOSNurbsCurve::GetLength
double GetLength()
get curve length
Definition: cinosnurbscurve.h:202
DF_INOS_NURBSCURVE_INTERPOLATION_POINTS
#define DF_INOS_NURBSCURVE_INTERPOLATION_POINTS
Definition: inosdefault.h:188
CINOSNurbsCurve::GetPositionU
void GetPositionU(double adU, TINOSVector< N > &ovPos)
get position at param 'adU' (The NURBS book, page 124, A4.1)
Definition: cinosnurbscurve.h:446
CINOSNurbsCurve::AddPoint
void AddPoint(CINOSNurbsPoint< N > &aPoint)
add control point to curve
Definition: cinosnurbscurve.h:77
CINOSNurbsCurve::GetD3max
virtual void GetD3max(TINOSVector< N > &ovD3Max)
get max. 3rd derivative over the whole curve
Definition: cinosnurbscurve.h:628
CINOSNurbsCurve::D
uint32 D
curve degree
Definition: cinosnurbscurve.h:1026
CINOSNurbsCurve::GetPosition
virtual void GetPosition(double adP, TINOSVector< N > &ovPos)
get position at 'adP'
Definition: cinosnurbscurve.h:384
CINOSNurbsCurve::GetPositionFirst
virtual void GetPositionFirst(TINOSVector< N > &ovPos)
get first position
Definition: cinosnurbscurve.h:404
CINOSNurbsCurve::CINOSNurbsCurve
CINOSNurbsCurve(uint32 auDegree=DF_INOS_NURBSCURVE_MAX_DEGREE, uint32 auInterpolationPoints=DF_INOS_NURBSCURVE_INTERPOLATION_POINTS, uint32 auLengthMask=0xFFFFFFF8)
constructor
Definition: cinosnurbscurve.h:729
CINOSNurbsCurve::AddPoint
void AddPoint(TINOSVector< N > &aPoint)
add control point to curve
Definition: cinosnurbscurve.h:96
CINOSNurbsCurve::GetLocalPositionU
void GetLocalPositionU(double adU, TINOSVector< N > &ovPos)
get position at param 'adU' (The NURBS book, page 124, A4.1)
Definition: cinosnurbscurve.h:418
CINOSNurbsCurve::m_uLengthDims
uint8 m_uLengthDims[N]
length relevant dimensions indices
Definition: cinosnurbscurve.h:1039
CINOSNurbsPoint::w
double w
point weight
Definition: cinosnurbspoint.h:71
CINOSNurbsCurve::P
inos_std::vector< CINOSNurbsPoint< N > > P
control points
Definition: cinosnurbscurve.h:1034
CINOSNurbsCurve::SPreviousCache::m_uPSpan
uint32 m_uPSpan
current span in Ps
Definition: cinosnurbscurve.h:1047
DF_INOS_NURBSCURVE_MAX_DEGREE
#define DF_INOS_NURBSCURVE_MAX_DEGREE
Definition: inosdefault.h:180
CINOSNurbsCurve
Definition: cinosnurbscurve.h:69
CINOSNurbsCurve::m_uNoLengthDims
uint8 m_uNoLengthDims
numeber of length relevant dimensions
Definition: cinosnurbscurve.h:1041
CINOSNurbsCurve::GetD2max
virtual void GetD2max(TINOSVector< N > &ovD2Max)
get max. second derivative over the whole curve
Definition: cinosnurbscurve.h:603
CINOSNurbsCurve::m_dLength
double m_dLength
curve length
Definition: cinosnurbscurve.h:1032
CINOSNurbsCurve::SPreviousCache::m_uUSpan
uint32 m_uUSpan
current span in Us
Definition: cinosnurbscurve.h:1051
CINOSNurbsCurve::SPreviousCache::m_uSegment
uint32 m_uSegment
current segment
Definition: cinosnurbscurve.h:1053
CINOSNurbsCurve::SetInterpolationPoints
void SetInterpolationPoints(uint32 auInterpolationPoints)
set number of interpolation points
Definition: cinosnurbscurve.h:134
CINOSNurbsCurve::DersBasisFuns
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
INOS_MOVEPATH_ERROR_NURBS_RELEVANT_LENGTH_ZERO
uint32 INOS_MOVEPATH_ERROR_NURBS_RELEVANT_LENGTH_ZERO
Definition: inoserror.h:1681
INOS_MOVEPATH_ERROR_NURBS_NUMBER_OF_KNOTS_INVALID
uint32 INOS_MOVEPATH_ERROR_NURBS_NUMBER_OF_KNOTS_INVALID
Definition: inoserror.h:1681
CINOSNurbsCurve::AddKnot
void AddKnot(double adKnot, uint32 auMultiplicity)
add knot to curve
Definition: cinosnurbscurve.h:108
IMPLEMENT_DYNAMIC_N
#define IMPLEMENT_DYNAMIC_N(aClass, aN)
Definition: cinospartitionmemory.h:373
CINOSNurbsCurve::m_uLengthMask
const uint32 m_uLengthMask
length mask (bit = 1 -> axis is not length relevant)
Definition: cinosnurbscurve.h:1028
INOS_OK
uint32 INOS_OK
Definition: inoserror.h:1681
CINOSNurbsCurve::FindSpan
uint32 FindSpan(double u) const
determine the knot span index (The NURBS book, page 68, A2.1)
Definition: cinosnurbscurve.h:772
INOS_MOVEPATH_ERROR_NURBS_NOT_ENOUGH_POINTS
uint32 INOS_MOVEPATH_ERROR_NURBS_NOT_ENOUGH_POINTS
Definition: inoserror.h:1681
CINOSNurbsCurve::SPreviousCache::m_uSplineIndex
uint32 m_uSplineIndex
current spline index
Definition: cinosnurbscurve.h:1049
INOS_MOVEPATH_ERROR_NURBS_DEGREE_INVALID
uint32 INOS_MOVEPATH_ERROR_NURBS_DEGREE_INVALID
Definition: inoserror.h:1681
CINOSNurbsCurve::SPreviousCache
Definition: cinosnurbscurve.h:1045
CINOSMovePath
Definition: cinosmovepath.h:565
CINOSNurbsPoint
Definition: cinosnurbspoint.h:46
CINOSNurbsCurve::GetPositionLast
virtual void GetPositionLast(TINOSVector< N > &ovPos)
get last position
Definition: cinosnurbscurve.h:411
CINOSNurbsCurve::SPreviousCache::m_dP
double m_dP
P value.
Definition: cinosnurbscurve.h:1059
CINOSNurbsCurve::GetPositionU
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
CINOSNurbsCurve::GetPoints
uint32 GetPoints()
get number of control points
Definition: cinosnurbscurve.h:127
INOS_MOVEPATH_ERROR_NURBS_ALL_WEIGHTS_ZERO
uint32 INOS_MOVEPATH_ERROR_NURBS_ALL_WEIGHTS_ZERO
Definition: inoserror.h:1681
CINOSNurbsCurve::Check
uint32 Check()
check curve
Definition: cinosnurbscurve.h:141
CINOSNurbsCurve::SetPoints
void SetPoints(uint32 auPoints)
set number of control points
Definition: cinosnurbscurve.h:120
CINOSNurbsCurve::SPreviousCache::m_dDistanceSegBeg
double m_dDistanceSegBeg
Distance to segment begin.
Definition: cinosnurbscurve.h:1055
CINOSNurbsCurve::CurveDerivs
void CurveDerivs(double u, uint32 d, _array_vector &ck)
compute curve derivatives (The NURBS book, page 93, A3.2)
Definition: cinosnurbscurve.h:889
CINOSNurbsCurve::m_uInterpolationPoints
uint32 m_uInterpolationPoints
curve interpolation points
Definition: cinosnurbscurve.h:1030
CINOSNurbsCurve::GetDerivativeEnd
virtual void GetDerivativeEnd(uint32 auLevel, TINOSVector< N > &ovDer)
get auLevel derivative at curve end
Definition: cinosnurbscurve.h:497
CINOSNurbsCurve::SPreviousCache::m_dDistanceSegEnd
double m_dDistanceSegEnd
Distance to segment end.
Definition: cinosnurbscurve.h:1057
CINOSNurbsCurve::U
inos_std::vector< double > U
knot vector
Definition: cinosnurbscurve.h:1036
CINOSNurbsCurve::GetPosition
virtual void GetPosition(double adP, TINOSVector< N > &ovPos, uint32 &auSegment)
get position at 'adP'
Definition: cinosnurbscurve.h:393
CINOSNurbsCurve::~CINOSNurbsCurve
virtual ~CINOSNurbsCurve()
destructor
Definition: cinosnurbscurve.h:759
CINOSNurbsCurve::BasisFuns
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
CINOSNurbsCurve::m_uFlags
uint32 m_uFlags
flags
Definition: cinosnurbscurve.h:1024
CINOSNurbsCurve::_array_vector
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
CINOSNurbsCurve::GetDerivativeBgn
virtual void GetDerivativeBgn(uint32 auLevel, TINOSVector< N > &ovDer)
get auLevel derivative at curve begin
Definition: cinosnurbscurve.h:490
CINOSNurbsCurve::GetGlobalU
double GetGlobalU(double adP)
approximately project P tu U
Definition: cinosnurbscurve.h:635
CINOSNurbsCurve::GetDerivative
virtual void GetDerivative(uint32 auLevel, double adP, TINOSVector< N > &ovDer)
get auLevel derivative at 'adP'
Definition: cinosnurbscurve.h:481
cinosnurbspoint.h
The CINOSNurbsPoint class.