qwt_spline_cubic.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  * Qwt Widget Library
3  * Copyright (C) 1997 Josef Wilgen
4  * Copyright (C) 2002 Uwe Rathmann
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the Qwt License, Version 1.0
8  *****************************************************************************/
9 
10 #include "qwt_spline_cubic.h"
11 #include "qwt_spline_polynomial.h"
12 
13 #include <qpolygon.h>
14 #include <qpainterpath.h>
15 
16 #define SLOPES_INCREMENTAL 0
17 #define KAHAN 0
18 
19 namespace QwtSplineCubicP
20 {
21  class KahanSum
22  {
23  public:
24  inline KahanSum( double value = 0.0 ):
25  m_sum( value ),
26  m_carry( 0.0 )
27  {
28  }
29 
30  inline void reset()
31  {
32  m_sum = m_carry = 0.0;
33  }
34 
35  inline double value() const
36  {
37  return m_sum;
38  }
39 
40  inline void add( double value )
41  {
42  const double y = value - m_carry;
43  const double t = m_sum + y;
44 
45  m_carry = ( t - m_sum ) - y;
46  m_sum = t;
47  }
48 
49  static inline double sum3( double d1, double d2, double d3 )
50  {
51  KahanSum sum( d1 );
52  sum.add( d2 );
53  sum.add( d3 );
54 
55  return sum.value();
56  }
57 
58  static inline double sum4( double d1, double d2, double d3, double d4 )
59  {
60  KahanSum sum( d1 );
61  sum.add( d2 );
62  sum.add( d3 );
63  sum.add( d4 );
64 
65  return sum.value();
66  }
67 
68 
69  private:
70  double m_sum;
71  double m_carry; // The carry from the previous operation
72  };
73 
75  {
76  public:
77  inline void setup( int size )
78  {
79  m_curvatures.resize( size );
80  m_cv = m_curvatures.data();
81  }
82 
83  inline void storeFirst( double,
84  const QPointF&, const QPointF&, double b1, double )
85  {
86  m_cv[0] = 2.0 * b1;
87  }
88 
89  inline void storeNext( int index, double,
90  const QPointF&, const QPointF&, double, double b2 )
91  {
92  m_cv[index] = 2.0 * b2;
93  }
94 
95  inline void storeLast( double,
96  const QPointF&, const QPointF&, double, double b2 )
97  {
98  m_cv[m_curvatures.size() - 1] = 2.0 * b2;
99  }
100 
101  inline void storePrevious( int index, double,
102  const QPointF&, const QPointF&, double b1, double )
103  {
104  m_cv[index] = 2.0 * b1;
105  }
106 
107  inline void closeR()
108  {
109  m_cv[0] = m_cv[m_curvatures.size() - 1];
110  }
111 
113 
114  private:
116  double* m_cv;
117  };
118 
120  {
121  public:
122  inline void setup( int size )
123  {
124  m_slopes.resize( size );
125  m_m = m_slopes.data();
126  }
127 
128  inline void storeFirst( double h,
129  const QPointF& p1, const QPointF& p2, double b1, double b2 )
130  {
131  const double s = ( p2.y() - p1.y() ) / h;
132  m_m[0] = s - h * ( 2.0 * b1 + b2 ) / 3.0;
133 #if KAHAN
134  m_sum.add( m_m[0] );
135 #endif
136  }
137 
138  inline void storeNext( int index, double h,
139  const QPointF& p1, const QPointF& p2, double b1, double b2 )
140  {
141 #if SLOPES_INCREMENTAL
142  Q_UNUSED( p1 )
143  Q_UNUSED( p2 )
144 #if KAHAN
145  m_sum.add( ( b1 + b2 ) * h );
146  m_m[index] = m_sum.value();
147 #else
148  m_m[index] = m_m[index - 1] + ( b1 + b2 ) * h;
149 #endif
150 #else
151  const double s = ( p2.y() - p1.y() ) / h;
152  m_m[index] = s + h * ( b1 + 2.0 * b2 ) / 3.0;
153 #endif
154  }
155 
156  inline void storeLast( double h,
157  const QPointF& p1, const QPointF& p2, double b1, double b2 )
158  {
159  const double s = ( p2.y() - p1.y() ) / h;
160  m_m[m_slopes.size() - 1] = s + h * ( b1 + 2.0 * b2 ) / 3.0;
161 #if KAHAN
162  m_sum.add( m_m[m_slopes.size() - 1] );
163 #endif
164  }
165 
166  inline void storePrevious( int index, double h,
167  const QPointF& p1, const QPointF& p2, double b1, double b2 )
168  {
169 #if SLOPES_INCREMENTAL
170  Q_UNUSED( p1 )
171  Q_UNUSED( p2 )
172 #if KAHAN
173  m_sum.add( -( b1 + b2 ) * h );
174  m_m[index] = m_sum.value();
175 #else
176  m_m[index] = m_m[index + 1] - ( b1 + b2 ) * h;
177 #endif
178 
179 #else
180  const double s = ( p2.y() - p1.y() ) / h;
181  m_m[index] = s - h * ( 2.0 * b1 + b2 ) / 3.0;
182 #endif
183  }
184 
185  inline void closeR()
186  {
187  m_m[0] = m_m[m_slopes.size() - 1];
188  }
189 
190  QVector< double > slopes() const { return m_slopes; }
191 
192  private:
194  double* m_m;
195 #if SLOPES_INCREMENTAL
196  KahanSum m_sum;
197 #endif
198  };
199 }
200 
201 namespace QwtSplineCubicP
202 {
203  class Equation2
204  {
205  public:
206  inline Equation2()
207  {
208  }
209 
210  inline Equation2( double p0, double q0, double r0 ):
211  p( p0 ),
212  q( q0 ),
213  r( r0 )
214  {
215  }
216 
217  inline void setup( double p0, double q0, double r0 )
218  {
219  p = p0;
220  q = q0;
221  r = r0;
222  }
223 
224  inline Equation2 normalized() const
225  {
226  Equation2 c;
227  c.p = 1.0;
228  c.q = q / p;
229  c.r = r / p;
230 
231  return c;
232  }
233 
234  inline double resolved1( double x2 ) const
235  {
236  return ( r - q * x2 ) / p;
237  }
238 
239  inline double resolved2( double x1 ) const
240  {
241  return ( r - p * x1 ) / q;
242  }
243 
244  inline double resolved1( const Equation2& eq ) const
245  {
246  // find x1
247  double k = q / eq.q;
248  return ( r - k * eq.r ) / ( p - k * eq.p );
249  }
250 
251  inline double resolved2( const Equation2& eq ) const
252  {
253  // find x2
254  const double k = p / eq.p;
255  return ( r - k * eq.r ) / ( q - k * eq.q );
256  }
257 
258  // p * x1 + q * x2 = r
259  double p, q, r;
260  };
261 
262  class Equation3
263  {
264  public:
265  inline Equation3()
266  {
267  }
268 
269  inline Equation3( const QPointF& p1, const QPointF& p2, const QPointF& p3 )
270  {
271  const double h1 = p2.x() - p1.x();
272  const double s1 = ( p2.y() - p1.y() ) / h1;
273 
274  const double h2 = p3.x() - p2.x();
275  const double s2 = ( p3.y() - p2.y() ) / h2;
276 
277  p = h1;
278  q = 2 * ( h1 + h2 );
279  u = h2;
280  r = 3 * ( s2 - s1 );
281  }
282 
283  inline Equation3( double cp, double cq, double du, double dr ):
284  p( cp ),
285  q( cq ),
286  u( du ),
287  r( dr )
288  {
289  }
290 
291  inline bool operator==( const Equation3& c ) const
292  {
293  return ( p == c.p ) && ( q == c.q ) &&
294  ( u == c.u ) && ( r == c.r );
295  }
296 
297  inline void setup( double cp, double cq, double du, double dr )
298  {
299  p = cp;
300  q = cq;
301  u = du;
302  r = dr;
303  }
304 
305  inline Equation3 normalized() const
306  {
307  Equation3 c;
308  c.p = 1.0;
309  c.q = q / p;
310  c.u = u / p;
311  c.r = r / p;
312 
313  return c;
314  }
315 
316  inline Equation2 substituted1( const Equation3& eq ) const
317  {
318  // eliminate x1
319  const double k = p / eq.p;
320  return Equation2( q - k * eq.q, u - k * eq.u, r - k * eq.r );
321  }
322 
323  inline Equation2 substituted2( const Equation3& eq ) const
324  {
325  // eliminate x2
326 
327  const double k = q / eq.q;
328  return Equation2( p - k * eq.p, u - k * eq.u, r - k * eq.r );
329  }
330 
331  inline Equation2 substituted3( const Equation3& eq ) const
332  {
333  // eliminate x3
334 
335  const double k = u / eq.u;
336  return Equation2( p - k * eq.p, q - k * eq.q, r - k * eq.r );
337  }
338 
339  inline Equation2 substituted1( const Equation2& eq ) const
340  {
341  // eliminate x1
342  const double k = p / eq.p;
343  return Equation2( q - k * eq.q, u, r - k * eq.r );
344  }
345 
346  inline Equation2 substituted3( const Equation2& eq ) const
347  {
348  // eliminate x3
349 
350  const double k = u / eq.q;
351  return Equation2( p, q - k * eq.p, r - k * eq.r );
352  }
353 
354 
355  inline double resolved1( double x2, double x3 ) const
356  {
357  return ( r - q * x2 - u * x3 ) / p;
358  }
359 
360  inline double resolved2( double x1, double x3 ) const
361  {
362  return ( r - u * x3 - p * x1 ) / q;
363  }
364 
365  inline double resolved3( double x1, double x2 ) const
366  {
367  return ( r - p * x1 - q * x2 ) / u;
368  }
369 
370  // p * x1 + q * x2 + u * x3 = r
371  double p, q, u, r;
372  };
373 }
374 
375 #if 0
376 static QDebug operator<<( QDebug debug, const QwtSplineCubicP::Equation2& eq )
377 {
378  debug.nospace() << "EQ2(" << eq.p << ", " << eq.q << ", " << eq.r << ")";
379  return debug.space();
380 }
381 
382 static QDebug operator<<( QDebug debug, const QwtSplineCubicP::Equation3& eq )
383 {
384  debug.nospace() << "EQ3(" << eq.p << ", "
385  << eq.q << ", " << eq.u << ", " << eq.r << ")";
386  return debug.space();
387 }
388 #endif
389 
390 namespace QwtSplineCubicP
391 {
392  template< class T >
394  {
395  public:
396  void setStartCondition( double p, double q, double u, double r )
397  {
398  m_conditionsEQ[0].setup( p, q, u, r );
399  }
400 
401  void setEndCondition( double p, double q, double u, double r )
402  {
403  m_conditionsEQ[1].setup( p, q, u, r );
404  }
405 
406  const T& store() const
407  {
408  return m_store;
409  }
410 
411  void resolve( const QPolygonF& p )
412  {
413  const int n = p.size();
414  if ( n < 3 )
415  return;
416 
417  if ( m_conditionsEQ[0].p == 0.0 ||
418  ( m_conditionsEQ[0].q == 0.0 && m_conditionsEQ[0].u != 0.0 ) )
419  {
420  return;
421  }
422 
423  if ( m_conditionsEQ[1].u == 0.0 ||
424  ( m_conditionsEQ[1].q == 0.0 && m_conditionsEQ[1].p != 0.0 ) )
425  {
426  return;
427  }
428 
429  const double h0 = p[1].x() - p[0].x();
430  const double h1 = p[2].x() - p[1].x();
431  const double hn = p[n - 1].x() - p[n - 2].x();
432 
433  m_store.setup( n );
434 
435 
436  if ( n == 3 )
437  {
438  // For certain conditions the first/last point does not
439  // necessarily meet the spline equation and we would
440  // have many solutions. In this case we resolve using
441  // the spline equation - as for all other conditions.
442 
443  const Equation3 eqSpline0( p[0], p[1], p[2] ); // ???
444  const Equation2 eq0 = m_conditionsEQ[0].substituted1( eqSpline0 );
445 
446  // The equation system can be solved without substitution
447  // from the start/end conditions and eqSpline0 ( = eqSplineN ).
448 
449  double b1;
450 
451  if ( m_conditionsEQ[0].normalized() == m_conditionsEQ[1].normalized() )
452  {
453  // When we have 3 points only and start/end conditions
454  // for 3 points mean the same condition the system
455  // is under-determined and has many solutions.
456  // We chose b1 = 0.0
457 
458  b1 = 0.0;
459  }
460  else
461  {
462  const Equation2 eq = m_conditionsEQ[1].substituted1( eqSpline0 );
463  b1 = eq0.resolved1( eq );
464  }
465 
466  const double b2 = eq0.resolved2( b1 );
467  const double b0 = eqSpline0.resolved1( b1, b2 );
468 
469  m_store.storeFirst( h0, p[0], p[1], b0, b1 );
470  m_store.storeNext( 1, h0, p[0], p[1], b0, b1 );
471  m_store.storeNext( 2, h1, p[1], p[2], b1, b2 );
472 
473  return;
474  }
475 
476  const Equation3 eqSplineN( p[n - 3], p[n - 2], p[n - 1] );
477  const Equation2 eqN = m_conditionsEQ[1].substituted3( eqSplineN );
478 
479  Equation2 eq = eqN;
480  if ( n > 4 )
481  {
482  const Equation3 eqSplineR( p[n - 4], p[n - 3], p[n - 2] );
483  eq = eqSplineR.substituted3( eq );
484  eq = substituteSpline( p, eq );
485  }
486 
487  const Equation3 eqSpline0( p[0], p[1], p[2] );
488 
489  double b0, b1;
490  if ( m_conditionsEQ[0].u == 0.0 )
491  {
492  eq = eqSpline0.substituted3( eq );
493 
494  const Equation3& eq0 = m_conditionsEQ[0];
495  b0 = Equation2( eq0.p, eq0.q, eq0.r ).resolved1( eq );
496  b1 = eq.resolved2( b0 );
497  }
498  else
499  {
500  const Equation2 eqX = m_conditionsEQ[0].substituted3( eq );
501  const Equation2 eqY = eqSpline0.substituted3( eq );
502 
503  b0 = eqY.resolved1( eqX );
504  b1 = eqY.resolved2( b0 );
505  }
506 
507  m_store.storeFirst( h0, p[0], p[1], b0, b1 );
508  m_store.storeNext( 1, h0, p[0], p[1], b0, b1 );
509 
510  const double bn2 = resolveSpline( p, b1 );
511 
512  const double bn1 = eqN.resolved2( bn2 );
513  const double bn0 = m_conditionsEQ[1].resolved3( bn2, bn1 );
514 
515  const double hx = p[n - 2].x() - p[n - 3].x();
516  m_store.storeNext( n - 2, hx, p[n - 3], p[n - 2], bn2, bn1 );
517  m_store.storeNext( n - 1, hn, p[n - 2], p[n - 1], bn1, bn0 );
518  }
519 
520  private:
521  Equation2 substituteSpline( const QPolygonF& points, const Equation2& eq )
522  {
523  const int n = points.size();
524 
525  m_eq.resize( n - 2 );
526  m_eq[n - 3] = eq;
527 
528  // eq[i].resolved2( b[i-1] ) => b[i]
529 
530  double slope2 = ( points[n - 3].y() - points[n - 4].y() ) / eq.p;
531 
532  for ( int i = n - 4; i > 1; i-- )
533  {
534  const Equation2& eq2 = m_eq[i + 1];
535  Equation2& eq1 = m_eq[i];
536 
537  eq1.p = points[i].x() - points[i - 1].x();
538  const double slope1 = ( points[i].y() - points[i - 1].y() ) / eq1.p;
539 
540  const double v = eq2.p / eq2.q;
541 
542  eq1.q = 2.0 * ( eq1.p + eq2.p ) - v * eq2.p;
543  eq1.r = 3.0 * ( slope2 - slope1 ) - v * eq2.r;
544 
545  slope2 = slope1;
546  }
547 
548  return m_eq[2];
549  }
550 
551  double resolveSpline( const QPolygonF& points, double b1 )
552  {
553  const int n = points.size();
554  const QPointF* p = points.constData();
555 
556  for ( int i = 2; i < n - 2; i++ )
557  {
558  // eq[i].resolved2( b[i-1] ) => b[i]
559  const double b2 = m_eq[i].resolved2( b1 );
560  m_store.storeNext( i, m_eq[i].p, p[i - 1], p[i], b1, b2 );
561 
562  b1 = b2;
563  }
564 
565  return b1;
566  }
567 
568  private:
572  };
573 
574  template< class T >
576  {
577  public:
578  const T& store() const
579  {
580  return m_store;
581  }
582 
583  void resolve( const QPolygonF& p )
584  {
585  const int n = p.size();
586 
587  if ( p[n - 1].y() != p[0].y() )
588  {
589  // TODO ???
590  }
591 
592  const double h0 = p[1].x() - p[0].x();
593  const double s0 = ( p[1].y() - p[0].y() ) / h0;
594 
595  if ( n == 3 )
596  {
597  const double h1 = p[2].x() - p[1].x();
598  const double s1 = ( p[2].y() - p[1].y() ) / h1;
599 
600  const double b = 3.0 * ( s0 - s1 ) / ( h0 + h1 );
601 
602  m_store.setup( 3 );
603  m_store.storeLast( h1, p[1], p[2], -b, b );
604  m_store.storePrevious( 1, h1, p[1], p[2], -b, b );
605  m_store.closeR();
606 
607  return;
608  }
609 
610  const double hn = p[n - 1].x() - p[n - 2].x();
611 
612  Equation2 eqn, eqX;
613  substitute( p, eqn, eqX );
614 
615  const double b0 = eqn.resolved2( eqX );
616  const double bn = eqn.resolved1( b0 );
617 
618  m_store.setup( n );
619  m_store.storeLast( hn, p[n - 2], p[n - 1], bn, b0 );
620  m_store.storePrevious( n - 2, hn, p[n - 2], p[n - 1], bn, b0 );
621 
622  resolveSpline( p, b0, bn );
623 
624  m_store.closeR();
625  }
626 
627  private:
628 
629  void substitute( const QPolygonF& points, Equation2& eqn, Equation2& eqX )
630  {
631  const int n = points.size();
632 
633  const double hn = points[n - 1].x() - points[n - 2].x();
634 
635  const Equation3 eqSpline0( points[0], points[1], points[2] );
636  const Equation3 eqSplineN(
637  QPointF( points[0].x() - hn, points[n - 2].y() ), points[0], points[1] );
638 
639  m_eq.resize( n - 1 );
640 
641  double dq = 0;
642  double dr = 0;
643 
644  m_eq[1] = eqSpline0;
645 
646  double slope1 = ( points[2].y() - points[1].y() ) / m_eq[1].u;
647 
648  // a) p1 * b[0] + q1 * b[1] + u1 * b[2] = r1
649  // b) p2 * b[n-2] + q2 * b[0] + u2 * b[1] = r2
650  // c) pi * b[i-1] + qi * b[i] + ui * b[i+1] = ri
651  //
652  // Using c) we can substitute b[i] ( starting from 2 ) by b[i+1]
653  // until we reach n-1. As we know, that b[0] == b[n-1] we found
654  // an equation where only 2 coefficients ( for b[n-2], b[0] ) are left unknown.
655  // Each step we have an equation that depends on b[0], b[i] and b[i+1]
656  // that can also be used to substitute b[i] in b). Ding so we end up with another
657  // equation depending on b[n-2], b[0] only.
658  // Finally 2 equations with 2 coefficients can be solved.
659 
660  for ( int i = 2; i < n - 1; i++ )
661  {
662  const Equation3& eq1 = m_eq[i - 1];
663  Equation3& eq2 = m_eq[i];
664 
665  dq += eq1.p * eq1.p / eq1.q;
666  dr += eq1.p * eq1.r / eq1.q;
667 
668  eq2.u = points[i + 1].x() - points[i].x();
669  const double slope2 = ( points[i + 1].y() - points[i].y() ) / eq2.u;
670 
671  const double k = eq1.u / eq1.q;
672 
673  eq2.p = -eq1.p * k;
674  eq2.q = 2.0 * ( eq1.u + eq2.u ) - eq1.u * k;
675  eq2.r = 3.0 * ( slope2 - slope1 ) - eq1.r * k;
676 
677  slope1 = slope2;
678  }
679 
680 
681  // b[0] * m_p[n-2] + b[n-2] * m_q[n-2] + b[n-1] * pN = m_r[n-2]
682  eqn.setup( m_eq[n - 2].q, m_eq[n - 2].p + eqSplineN.p, m_eq[n - 2].r );
683 
684  // b[n-2] * pN + b[0] * ( qN - dq ) + b[n-2] * m_p[n-2] = rN - dr
685  eqX.setup( m_eq[n - 2].p + eqSplineN.p, eqSplineN.q - dq, eqSplineN.r - dr );
686  }
687 
688  void resolveSpline( const QPolygonF& points, double b0, double bi )
689  {
690  const int n = points.size();
691 
692  for ( int i = n - 3; i >= 1; i-- )
693  {
694  const Equation3& eq = m_eq[i];
695 
696  const double b = eq.resolved2( b0, bi );
697  m_store.storePrevious( i, eq.u, points[i], points[i + 1], b, bi );
698 
699  bi = b;
700  }
701  }
702 
703  void resolveSpline2( const QPolygonF& points,
704  double b0, double bi, QVector< double >& m )
705  {
706  const int n = points.size();
707 
708  bi = m_eq[0].resolved3( b0, bi );
709 
710  for ( int i = 1; i < n - 2; i++ )
711  {
712  const Equation3& eq = m_eq[i];
713 
714  const double b = eq.resolved3( b0, bi );
715  m[i + 1] = m[i] + ( b + bi ) * m_eq[i].u;
716 
717  bi = b;
718  }
719  }
720 
721  void resolveSpline3( const QPolygonF& points,
722  double b0, double b1, QVector< double >& m )
723  {
724  const int n = points.size();
725 
726  double h0 = ( points[1].x() - points[0].x() );
727  double s0 = ( points[1].y() - points[0].y() ) / h0;
728 
729  m[1] = m[0] + ( b0 + b1 ) * h0;
730 
731  for ( int i = 1; i < n - 1; i++ )
732  {
733  const double h1 = ( points[i + 1].x() - points[i].x() );
734  const double s1 = ( points[i + 1].y() - points[i].y() ) / h1;
735 
736  const double r = 3.0 * ( s1 - s0 );
737 
738  const double b2 = ( r - h0 * b0 - 2.0 * ( h0 + h1 ) * b1 ) / h1;
739  m[i + 1] = m[i] + ( b1 + b2 ) * h1;
740 
741  h0 = h1;
742  s0 = s1;
743  b0 = b1;
744  b1 = b2;
745  }
746  }
747 
748  void resolveSpline4( const QPolygonF& points,
749  double b2, double b1, QVector< double >& m )
750  {
751  const int n = points.size();
752 
753  double h2 = ( points[n - 1].x() - points[n - 2].x() );
754  double s2 = ( points[n - 1].y() - points[n - 2].y() ) / h2;
755 
756  for ( int i = n - 2; i > 1; i-- )
757  {
758  const double h1 = ( points[i].x() - points[i - 1].x() );
759  const double s1 = ( points[i].y() - points[i - 1].y() ) / h1;
760 
761  const double r = 3.0 * ( s2 - s1 );
762  const double k = 2.0 * ( h1 + h2 );
763 
764  const double b0 = ( r - h2 * b2 - k * b1 ) / h1;
765 
766  m[i - 1] = m[i] - ( b0 + b1 ) * h1;
767 
768  h2 = h1;
769  s2 = s1;
770  b2 = b1;
771  b1 = b0;
772  }
773  }
774 
775  public:
778  };
779 }
780 
782  int conditionBegin, double valueBegin, int conditionEnd, double valueEnd,
783  const QPolygonF& points, QwtSplineCubicP::Equation3 eq[2] )
784 {
785  const int n = points.size();
786 
787  const double h0 = points[1].x() - points[0].x();
788  const double s0 = ( points[1].y() - points[0].y() ) / h0;
789 
790  const double hn = ( points[n - 1].x() - points[n - 2].x() );
791  const double sn = ( points[n - 1].y() - points[n - 2].y() ) / hn;
792 
793  switch( conditionBegin )
794  {
795  case QwtSpline::Clamped1:
796  {
797  // first derivative at end points given
798 
799  // 3 * a1 * h + b1 = b2
800  // a1 * h * h + b1 * h + c1 = s
801 
802  // c1 = slopeBegin
803  // => b1 * ( 2 * h / 3.0 ) + b2 * ( h / 3.0 ) = s - slopeBegin
804 
805  // c2 = slopeEnd
806  // => b1 * ( 1.0 / 3.0 ) + b2 * ( 2.0 / 3.0 ) = ( slopeEnd - s ) / h;
807 
808  eq[0].setup( 2 * h0 / 3.0, h0 / 3.0, 0.0, s0 - valueBegin );
809  break;
810  }
811  case QwtSpline::Clamped2:
812  {
813  // second derivative at end points given
814 
815  // b0 = 0.5 * cvStart
816  // => b0 * 1.0 + b1 * 0.0 = 0.5 * cvStart
817 
818  // b1 = 0.5 * cvEnd
819  // => b0 * 0.0 + b1 * 1.0 = 0.5 * cvEnd
820 
821  eq[0].setup( 1.0, 0.0, 0.0, 0.5 * valueBegin );
822  break;
823  }
824  case QwtSpline::Clamped3:
825  {
826  // third derivative at end point given
827 
828  // 3 * a * h0 + b[0] = b[1]
829 
830  // a = marg_0 / 6.0
831  // => b[0] * 1.0 + b[1] * ( -1.0 ) = -0.5 * v0 * h0
832 
833  // a = marg_n / 6.0
834  // => b[n-2] * 1.0 + b[n-1] * ( -1.0 ) = -0.5 * v1 * h5
835 
836  eq[0].setup( 1.0, -1.0, 0.0, -0.5 * valueBegin * h0 );
837 
838  break;
839  }
841  {
842  const double r0 = qBound( 0.0, valueBegin, 1.0 );
843  if ( r0 == 0.0 )
844  {
845  // clamping s0
846  eq[0].setup( 2 * h0 / 3.0, h0 / 3.0, 0.0, 0.0 );
847  }
848  else
849  {
850  eq[0].setup( 1.0 + 2.0 / r0, 2.0 + 1.0 / r0, 0.0, 0.0 );
851  }
852  break;
853  }
856  {
857  // building one cubic curve from 3 points
858 
859  double v0;
860 
861  if ( conditionBegin == QwtSplineC2::CubicRunout )
862  {
863  // first/last point are the endpoints of the curve
864 
865  // b0 = 2 * b1 - b2
866  // => 1.0 * b0 - 2 * b1 + 1.0 * b2 = 0.0
867 
868  v0 = 1.0;
869  }
870  else
871  {
872  // first/last points are on the curve,
873  // the imaginary endpoints have the same distance as h0/hn
874 
875  v0 = h0 / ( points[2].x() - points[1].x() );
876  }
877 
878  eq[0].setup( 1.0, -( 1.0 + v0 ), v0, 0.0 );
879  break;
880  }
881  default:
882  {
883  // a natural spline, where the
884  // second derivative at end points set to 0.0
885  eq[0].setup( 1.0, 0.0, 0.0, 0.0 );
886  break;
887  }
888  }
889 
890  switch( conditionEnd )
891  {
892  case QwtSpline::Clamped1:
893  {
894  // first derivative at end points given
895  eq[1].setup( 0.0, 1.0 / 3.0 * hn, 2.0 / 3.0 * hn, valueEnd - sn );
896  break;
897  }
898  case QwtSpline::Clamped2:
899  {
900  // second derivative at end points given
901  eq[1].setup( 0.0, 0.0, 1.0, 0.5 * valueEnd );
902  break;
903  }
904  case QwtSpline::Clamped3:
905  {
906  // third derivative at end point given
907  eq[1].setup( 0.0, 1.0, -1.0, -0.5 * valueEnd * hn );
908  break;
909  }
911  {
912  const double rn = qBound( 0.0, valueEnd, 1.0 );
913  if ( rn == 0.0 )
914  {
915  // clamping sn
916  eq[1].setup( 0.0, 1.0 / 3.0 * hn, 2.0 / 3.0 * hn, 0.0 );
917  }
918  else
919  {
920  eq[1].setup( 0.0, 2.0 + 1.0 / rn, 1.0 + 2.0 / rn, 0.0 );
921  }
922 
923  break;
924  }
927  {
928  // building one cubic curve from 3 points
929 
930  double vn;
931 
932  if ( conditionEnd == QwtSplineC2::CubicRunout )
933  {
934  // last point is the endpoints of the curve
935  vn = 1.0;
936  }
937  else
938  {
939  // last points on the curve,
940  // the imaginary endpoints have the same distance as hn
941 
942  vn = hn / ( points[n - 2].x() - points[n - 3].x() );
943  }
944 
945  eq[1].setup( vn, -( 1.0 + vn ), 1.0, 0.0 );
946  break;
947  }
948  default:
949  {
950  // a natural spline, where the
951  // second derivative at end points set to 0.0
952  eq[1].setup( 0.0, 0.0, 1.0, 0.0 );
953  break;
954  }
955  }
956 }
957 
959 {
960 };
961 
967  : m_data( nullptr )
968 {
969  // a natural spline
970 
973 
976 }
977 
980 {
981 }
982 
990 {
991  return 0;
992 }
993 
1006 QVector< double > QwtSplineCubic::slopes( const QPolygonF& points ) const
1007 {
1008  using namespace QwtSplineCubicP;
1009 
1010  if ( points.size() <= 2 )
1011  return QVector< double >();
1012 
1015  {
1017  eqs.resolve( points );
1018 
1019  return eqs.store().slopes();
1020  }
1021 
1022  if ( points.size() == 3 )
1023  {
1026  {
1027 #if 0
1028  const double h0 = points[1].x() - points[0].x();
1029  const double h1 = points[2].x() - points[1].x();
1030 
1031  const double s0 = ( points[1].y() - points[0].y() ) / h0;
1032  const double s1 = ( points[2].y() - points[1].y() ) / h1;
1033 
1034  /*
1035  the system is under-determined and we only
1036  compute a quadratic spline.
1037  */
1038 
1039  const double b = ( s1 - s0 ) / ( h0 + h1 );
1040 
1041  QVector< double > m( 3 );
1042  m[0] = s0 - h0 * b;
1043  m[1] = s1 - h1 * b;
1044  m[2] = s1 + h1 * b;
1045 
1046  return m;
1047 #else
1048  return QVector< double >();
1049 #endif
1050  }
1051  }
1052 
1053  Equation3 eq[2];
1059  points, eq );
1060 
1062  eqs.setStartCondition( eq[0].p, eq[0].q, eq[0].u, eq[0].r );
1063  eqs.setEndCondition( eq[1].p, eq[1].q, eq[1].u, eq[1].r );
1064  eqs.resolve( points );
1065 
1066  return eqs.store().slopes();
1067 }
1068 
1078 QVector< double > QwtSplineCubic::curvatures( const QPolygonF& points ) const
1079 {
1080  using namespace QwtSplineCubicP;
1081 
1082  if ( points.size() <= 2 )
1083  return QVector< double >();
1084 
1087  {
1089  eqs.resolve( points );
1090 
1091  return eqs.store().curvatures();
1092  }
1093 
1094  if ( points.size() == 3 )
1095  {
1098  {
1099  return QVector< double >();
1100  }
1101  }
1102 
1103  Equation3 eq[2];
1109  points, eq );
1110 
1112  eqs.setStartCondition( eq[0].p, eq[0].q, eq[0].u, eq[0].r );
1113  eqs.setEndCondition( eq[1].p, eq[1].q, eq[1].u, eq[1].r );
1114  eqs.resolve( points );
1115 
1116  return eqs.store().curvatures();
1117 }
1118 
1130 QPainterPath QwtSplineCubic::painterPath( const QPolygonF& points ) const
1131 {
1132  // as QwtSplineCubic can calculate slopes directly we can
1133  // use the implementation of QwtSplineC1 without any performance loss.
1134 
1135  return QwtSplineC1::painterPath( points );
1136 }
1137 
1150 {
1151  // as QwtSplineCubic can calculate slopes directly we can
1152  // use the implementation of QwtSplineC1 without any performance loss.
1153 
1154  return QwtSplineC1::bezierControlLines( points );
1155 }
1156 
1168 {
1169  return QwtSplineC2::polynomials( points );
1170 }
1171 
QwtSpline::boundaryType
BoundaryType boundaryType() const
Definition: qwt_spline.cpp:626
QwtSplineCubicP::KahanSum::sum3
static double sum3(double d1, double d2, double d3)
Definition: qwt_spline_cubic.cpp:49
QwtSplineCubicP::Equation3::substituted1
Equation2 substituted1(const Equation3 &eq) const
Definition: qwt_spline_cubic.cpp:316
QwtSplineCubicP::CurvatureStore::storeFirst
void storeFirst(double, const QPointF &, const QPointF &, double b1, double)
Definition: qwt_spline_cubic.cpp:83
QwtSplineCubicP::CurvatureStore
Definition: qwt_spline_cubic.cpp:74
QwtSplineCubicP::SlopeStore::closeR
void closeR()
Definition: qwt_spline_cubic.cpp:185
QwtSplineCubicP::Equation3::substituted3
Equation2 substituted3(const Equation3 &eq) const
Definition: qwt_spline_cubic.cpp:331
QwtSplineCubicP::Equation2::Equation2
Equation2(double p0, double q0, double r0)
Definition: qwt_spline_cubic.cpp:210
QwtSplineCubic::slopes
virtual QVector< double > slopes(const QPolygonF &) const QWT_OVERRIDE
Find the first derivative at the control points.
Definition: qwt_spline_cubic.cpp:1006
QwtSplineCubicP::EquationSystem::resolveSpline
double resolveSpline(const QPolygonF &points, double b1)
Definition: qwt_spline_cubic.cpp:551
QwtSplineCubicP::EquationSystem2::store
const T & store() const
Definition: qwt_spline_cubic.cpp:578
QwtSplineCubicP::Equation3::normalized
Equation3 normalized() const
Definition: qwt_spline_cubic.cpp:305
QwtSplineCubicP::EquationSystem2::resolveSpline2
void resolveSpline2(const QPolygonF &points, double b0, double bi, QVector< double > &m)
Definition: qwt_spline_cubic.cpp:703
QwtSplineCubicP::SlopeStore::m_m
double * m_m
Definition: qwt_spline_cubic.cpp:194
QwtSplineCubicP::EquationSystem2::resolve
void resolve(const QPolygonF &p)
Definition: qwt_spline_cubic.cpp:583
QwtSplineC2::polynomials
virtual QVector< QwtSplinePolynomial > polynomials(const QPolygonF &) const QWT_OVERRIDE
Calculate the interpolating polynomials for a non parametric spline.
Definition: qwt_spline.cpp:1381
QwtSpline::AtEnd
@ AtEnd
the condition is at the end of the polynomial
Definition: qwt_spline.h:105
qwt_spline_polynomial.h
QwtSplineCubicP::KahanSum::KahanSum
KahanSum(double value=0.0)
Definition: qwt_spline_cubic.cpp:24
QwtSpline::boundaryCondition
int boundaryCondition(BoundaryPosition) const
Definition: qwt_spline.cpp:651
qwt_spline_cubic.h
QwtSplineCubicP::Equation2::resolved1
double resolved1(const Equation2 &eq) const
Definition: qwt_spline_cubic.cpp:244
s
XmlRpcServer s
QwtSplineCubicP::Equation3::substituted2
Equation2 substituted2(const Equation3 &eq) const
Definition: qwt_spline_cubic.cpp:323
QwtSplineCubicP::Equation3::substituted3
Equation2 substituted3(const Equation2 &eq) const
Definition: qwt_spline_cubic.cpp:346
QwtSplineCubicP::SlopeStore::storeFirst
void storeFirst(double h, const QPointF &p1, const QPointF &p2, double b1, double b2)
Definition: qwt_spline_cubic.cpp:128
QwtSpline::LinearRunout
@ LinearRunout
Definition: qwt_spline.h:153
QwtSplineCubic::bezierControlLines
virtual QVector< QLineF > bezierControlLines(const QPolygonF &points) const QWT_OVERRIDE
Interpolate a curve with Bezier curves.
Definition: qwt_spline_cubic.cpp:1149
QwtSplineCubicP::KahanSum::m_carry
double m_carry
Definition: qwt_spline_cubic.cpp:71
QwtSplineC1::bezierControlLines
virtual QVector< QLineF > bezierControlLines(const QPolygonF &) const QWT_OVERRIDE
Interpolate a curve with Bezier curves.
Definition: qwt_spline.cpp:1101
QwtSplineCubicP::Equation2::normalized
Equation2 normalized() const
Definition: qwt_spline_cubic.cpp:224
QVector< double >
QwtSplineCubicP::EquationSystem::m_store
T m_store
Definition: qwt_spline_cubic.cpp:571
QwtSplineCubic::painterPath
virtual QPainterPath painterPath(const QPolygonF &) const QWT_OVERRIDE
Interpolate a curve with Bezier curves.
Definition: qwt_spline_cubic.cpp:1130
QwtSplineCubicP::EquationSystem::store
const T & store() const
Definition: qwt_spline_cubic.cpp:406
QwtSplineCubicP::Equation2
Definition: qwt_spline_cubic.cpp:203
mqtt_test_proto.x
x
Definition: mqtt_test_proto.py:34
QwtSplineCubicP::Equation3::u
double u
Definition: qwt_spline_cubic.cpp:371
QwtSplineCubicP::CurvatureStore::closeR
void closeR()
Definition: qwt_spline_cubic.cpp:107
QwtSplineC2::NotAKnot
@ NotAKnot
Definition: qwt_spline.h:292
QwtSplineCubicP::EquationSystem::m_eq
QVector< Equation2 > m_eq
Definition: qwt_spline_cubic.cpp:570
QwtSplineCubicP::Equation2::Equation2
Equation2()
Definition: qwt_spline_cubic.cpp:206
mqtt_test_proto.y
y
Definition: mqtt_test_proto.py:35
QwtSpline::ClosedPolygon
@ ClosedPolygon
Definition: qwt_spline.h:92
QwtSplineCubicP::SlopeStore::m_slopes
QVector< double > m_slopes
Definition: qwt_spline_cubic.cpp:193
QwtSplineCubicP::Equation2::resolved2
double resolved2(double x1) const
Definition: qwt_spline_cubic.cpp:239
QwtSplineC1::painterPath
virtual QPainterPath painterPath(const QPolygonF &) const QWT_OVERRIDE
Calculate an interpolated painter path.
Definition: qwt_spline.cpp:1043
QwtSpline::Clamped3
@ Clamped3
Definition: qwt_spline.h:143
QwtSplineCubicP::SlopeStore::storeNext
void storeNext(int index, double h, const QPointF &p1, const QPointF &p2, double b1, double b2)
Definition: qwt_spline_cubic.cpp:138
QwtSplineCubic::polynomials
virtual QVector< QwtSplinePolynomial > polynomials(const QPolygonF &) const QWT_OVERRIDE
Calculate the interpolating polynomials for a non parametric spline.
Definition: qwt_spline_cubic.cpp:1167
QwtSplineCubicP::Equation3::Equation3
Equation3(const QPointF &p1, const QPointF &p2, const QPointF &p3)
Definition: qwt_spline_cubic.cpp:269
nonstd::span_lite::size
span_constexpr std::size_t size(span< T, Extent > const &spn)
Definition: span.hpp:1554
QwtSplineCubicP::Equation3::resolved1
double resolved1(double x2, double x3) const
Definition: qwt_spline_cubic.cpp:355
QwtSpline::Clamped1
@ Clamped1
Definition: qwt_spline.h:125
QwtSplineCubicP::Equation3::substituted1
Equation2 substituted1(const Equation2 &eq) const
Definition: qwt_spline_cubic.cpp:339
QwtSplineCubicP::KahanSum::sum4
static double sum4(double d1, double d2, double d3, double d4)
Definition: qwt_spline_cubic.cpp:58
QwtSplineCubic::locality
virtual uint locality() const QWT_OVERRIDE
Definition: qwt_spline_cubic.cpp:989
QwtSplineCubicP::Equation2::resolved2
double resolved2(const Equation2 &eq) const
Definition: qwt_spline_cubic.cpp:251
QwtSpline::setBoundaryValue
void setBoundaryValue(BoundaryPosition, double value)
Define the boundary value.
Definition: qwt_spline.cpp:670
QwtSplineCubicP::KahanSum::m_sum
double m_sum
Definition: qwt_spline_cubic.cpp:70
QwtSplineCubicP::CurvatureStore::setup
void setup(int size)
Definition: qwt_spline_cubic.cpp:77
QwtSplineCubicP::EquationSystem2
Definition: qwt_spline_cubic.cpp:575
QwtSplineCubicP::EquationSystem2::m_eq
QVector< Equation3 > m_eq
Definition: qwt_spline_cubic.cpp:776
QwtSplineCubicP::Equation2::r
double r
Definition: qwt_spline_cubic.cpp:259
QwtSplineCubicP
Definition: qwt_spline_cubic.cpp:19
QwtSplineCubicP::SlopeStore
Definition: qwt_spline_cubic.cpp:119
QwtSplineCubicP::EquationSystem::resolve
void resolve(const QPolygonF &p)
Definition: qwt_spline_cubic.cpp:411
QwtSplineCubicP::Equation3::Equation3
Equation3(double cp, double cq, double du, double dr)
Definition: qwt_spline_cubic.cpp:283
QwtSplineCubicP::EquationSystem::m_conditionsEQ
Equation3 m_conditionsEQ[2]
Definition: qwt_spline_cubic.cpp:569
QwtSplineCubic::~QwtSplineCubic
virtual ~QwtSplineCubic()
Destructor.
Definition: qwt_spline_cubic.cpp:979
QwtSplineCubicP::Equation3
Definition: qwt_spline_cubic.cpp:262
QwtSplineCubicP::EquationSystem::setStartCondition
void setStartCondition(double p, double q, double u, double r)
Definition: qwt_spline_cubic.cpp:396
QwtSplineCubicP::KahanSum::add
void add(double value)
Definition: qwt_spline_cubic.cpp:40
QwtSplineCubicP::CurvatureStore::storeLast
void storeLast(double, const QPointF &, const QPointF &, double, double b2)
Definition: qwt_spline_cubic.cpp:95
debug
#define debug()
Definition: mqtt_client.cpp:14
QwtSplineCubicP::CurvatureStore::curvatures
QVector< double > curvatures() const
Definition: qwt_spline_cubic.cpp:112
QwtSplineCubicP::CurvatureStore::m_cv
double * m_cv
Definition: qwt_spline_cubic.cpp:116
QwtSplineCubicP::SlopeStore::storePrevious
void storePrevious(int index, double h, const QPointF &p1, const QPointF &p2, double b1, double b2)
Definition: qwt_spline_cubic.cpp:166
QwtSplineCubicP::Equation3::q
double q
Definition: qwt_spline_cubic.cpp:371
QwtSplineCubicP::CurvatureStore::storePrevious
void storePrevious(int index, double, const QPointF &, const QPointF &, double b1, double)
Definition: qwt_spline_cubic.cpp:101
QwtSpline::PeriodicPolygon
@ PeriodicPolygon
Definition: qwt_spline.h:79
QwtSplineCubicP::Equation2::q
double q
Definition: qwt_spline_cubic.cpp:259
QwtSplineCubicP::EquationSystem2::substitute
void substitute(const QPolygonF &points, Equation2 &eqn, Equation2 &eqX)
Definition: qwt_spline_cubic.cpp:629
QwtSplineCubicP::CurvatureStore::m_curvatures
QVector< double > m_curvatures
Definition: qwt_spline_cubic.cpp:115
QwtSplineCubicP::Equation2::resolved1
double resolved1(double x2) const
Definition: qwt_spline_cubic.cpp:234
mcap::internal::operator<<
std::ostream & operator<<(std::ostream &out, const Interval< Scalar, Value > &i)
Definition: intervaltree.hpp:37
QwtSplineCubicP::EquationSystem2::resolveSpline4
void resolveSpline4(const QPolygonF &points, double b2, double b1, QVector< double > &m)
Definition: qwt_spline_cubic.cpp:748
qwtSetupEndEquations
static void qwtSetupEndEquations(int conditionBegin, double valueBegin, int conditionEnd, double valueEnd, const QPolygonF &points, QwtSplineCubicP::Equation3 eq[2])
Definition: qwt_spline_cubic.cpp:781
QwtSplineCubicP::EquationSystem
Definition: qwt_spline_cubic.cpp:393
QwtSplineCubicP::Equation3::Equation3
Equation3()
Definition: qwt_spline_cubic.cpp:265
QwtSplineCubic::curvatures
virtual QVector< double > curvatures(const QPolygonF &) const QWT_OVERRIDE
Find the second derivative at the control points.
Definition: qwt_spline_cubic.cpp:1078
QwtSplineCubicP::Equation2::setup
void setup(double p0, double q0, double r0)
Definition: qwt_spline_cubic.cpp:217
QwtSplineCubicP::CurvatureStore::storeNext
void storeNext(int index, double, const QPointF &, const QPointF &, double, double b2)
Definition: qwt_spline_cubic.cpp:89
QwtSplineCubicP::Equation3::setup
void setup(double cp, double cq, double du, double dr)
Definition: qwt_spline_cubic.cpp:297
QwtSplineCubicP::EquationSystem2::resolveSpline3
void resolveSpline3(const QPolygonF &points, double b0, double b1, QVector< double > &m)
Definition: qwt_spline_cubic.cpp:721
QwtSplineCubicP::SlopeStore::slopes
QVector< double > slopes() const
Definition: qwt_spline_cubic.cpp:190
QwtSplineCubicP::KahanSum
Definition: qwt_spline_cubic.cpp:21
QwtSplineCubicP::Equation3::r
double r
Definition: qwt_spline_cubic.cpp:371
QwtSplineCubicP::SlopeStore::storeLast
void storeLast(double h, const QPointF &p1, const QPointF &p2, double b1, double b2)
Definition: qwt_spline_cubic.cpp:156
QwtSplineCubic::QwtSplineCubic
QwtSplineCubic()
Constructor The default setting is a non closing natural spline with no parametrization.
Definition: qwt_spline_cubic.cpp:966
QwtSplineCubicP::EquationSystem::substituteSpline
Equation2 substituteSpline(const QPolygonF &points, const Equation2 &eq)
Definition: qwt_spline_cubic.cpp:521
QwtSpline::Clamped2
@ Clamped2
Definition: qwt_spline.h:134
QwtSpline::setBoundaryCondition
void setBoundaryCondition(BoundaryPosition, int condition)
Define the condition for an endpoint of the spline.
Definition: qwt_spline.cpp:639
QwtSplineCubicP::Equation3::operator==
bool operator==(const Equation3 &c) const
Definition: qwt_spline_cubic.cpp:291
QwtSpline::boundaryValue
double boundaryValue(BoundaryPosition) const
Definition: qwt_spline.cpp:682
QwtSplineCubicP::KahanSum::reset
void reset()
Definition: qwt_spline_cubic.cpp:30
QwtSplineCubicP::EquationSystem2::resolveSpline
void resolveSpline(const QPolygonF &points, double b0, double bi)
Definition: qwt_spline_cubic.cpp:688
QwtSplineCubicP::Equation2::p
double p
Definition: qwt_spline_cubic.cpp:259
QwtSplineCubic::PrivateData
Definition: qwt_spline_cubic.cpp:958
QwtSpline::AtBeginning
@ AtBeginning
the condition is at the beginning of the polynomial
Definition: qwt_spline.h:102
QwtSplineC2::CubicRunout
@ CubicRunout
Definition: qwt_spline.h:283
nullptr
#define nullptr
Definition: backward.hpp:386
QwtSplineCubicP::Equation3::resolved3
double resolved3(double x1, double x2) const
Definition: qwt_spline_cubic.cpp:365
QwtSplineCubicP::SlopeStore::setup
void setup(int size)
Definition: qwt_spline_cubic.cpp:122
QwtSplineCubicP::EquationSystem::setEndCondition
void setEndCondition(double p, double q, double u, double r)
Definition: qwt_spline_cubic.cpp:401
QwtSplineCubicP::Equation3::resolved2
double resolved2(double x1, double x3) const
Definition: qwt_spline_cubic.cpp:360
QwtSplineCubicP::EquationSystem2::m_store
T m_store
Definition: qwt_spline_cubic.cpp:777
QwtSplineCubicP::Equation3::p
double p
Definition: qwt_spline_cubic.cpp:371
QwtSplineCubicP::KahanSum::value
double value() const
Definition: qwt_spline_cubic.cpp:35


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Nov 11 2024 03:23:46