qwt_spline_local.cpp
Go to the documentation of this file.
1 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
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_local.h"
12 #include <qmath.h>
13 
14 static inline bool qwtIsStrictlyMonotonic( double dy1, double dy2 )
15 {
16  if ( dy1 == 0.0 || dy2 == 0.0 )
17  return false;
18 
19  return ( dy1 > 0.0 ) == ( dy2 > 0.0 );
20 }
21 
22 static inline double qwtSlopeLine( const QPointF &p1, const QPointF &p2 )
23 {
24  // ???
25  const double dx = p2.x() - p1.x();
26  return dx ? ( p2.y() - p1.y() ) / dx : 0.0;
27 }
28 
29 static inline double qwtSlopeCardinal(
30  double dx1, double dy1, double s1, double dx2, double dy2, double s2 )
31 {
32  Q_UNUSED(s1)
33  Q_UNUSED(s2)
34 
35  return ( dy1 + dy2 ) / ( dx1 + dx2 );
36 }
37 
38 static inline double qwtSlopeParabolicBlending(
39  double dx1, double dy1, double s1, double dx2, double dy2, double s2 )
40 {
41  Q_UNUSED( dy1 )
42  Q_UNUSED( dy2 )
43 
44  return ( dx2 * s1 + dx1 * s2 ) / ( dx1 + dx2 );
45 }
46 
47 static inline double qwtSlopePChip(
48  double dx1, double dy1, double s1, double dx2, double dy2, double s2 )
49 {
50  if ( qwtIsStrictlyMonotonic( dy1, dy2 ) )
51  {
52 #if 0
53  // weighting the slopes by the dx1/dx2
54  const double w1 = ( 3 * dx1 + 3 * dx2 ) / ( 2 * dx1 + 4 * dx2 );
55  const double w2 = ( 3 * dx1 + 3 * dx2 ) / ( 4 * dx1 + 2 * dx2 );
56 
57  s1 *= w1;
58  s2 *= w2;
59 
60  // harmonic mean ( see https://en.wikipedia.org/wiki/Pythagorean_means )
61  return 2.0 / ( 1.0 / s1 + 1.0 / s2 );
62 #endif
63  // the same as above - but faster
64 
65  const double s12 = ( dy1 + dy2 ) / ( dx1 + dx2 );
66  return 3.0 * ( s1 * s2 ) / ( s1 + s2 + s12 );
67  }
68 
69  return 0.0;
70 }
71 
72 namespace QwtSplineLocalP
73 {
74  class PathStore
75  {
76  public:
77  inline void init( const QVector<QPointF> & )
78  {
79  }
80 
81  inline void start( const QPointF &p0, double )
82  {
83  path.moveTo( p0 );
84  }
85 
86  inline void addCubic( const QPointF &p1, double m1,
87  const QPointF &p2, double m2 )
88  {
89  const double dx3 = ( p2.x() - p1.x() ) / 3.0;
90 
91  path.cubicTo( p1.x() + dx3, p1.y() + m1 * dx3,
92  p2.x() - dx3, p2.y() - m2 * dx3,
93  p2.x(), p2.y() );
94  }
95 
96  QPainterPath path;
97  };
98 
100  {
101  public:
102  inline void init( const QVector<QPointF> &points )
103  {
104  if ( points.size() > 0 )
105  controlPoints.resize( points.size() - 1 );
106  d_cp = controlPoints.data();
107  }
108 
109  inline void start( const QPointF &, double )
110  {
111  }
112 
113  inline void addCubic( const QPointF &p1, double m1,
114  const QPointF &p2, double m2 )
115  {
116  const double dx3 = ( p2.x() - p1.x() ) / 3.0;
117 
118  QLineF &l = *d_cp++;
119  l.setLine( p1.x() + dx3, p1.y() + m1 * dx3,
120  p2.x() - dx3, p2.y() - m2 * dx3 );
121  }
122 
123  QVector<QLineF> controlPoints;
124 
125  private:
126  QLineF *d_cp;
127  };
128 
130  {
131  public:
132  void init( const QVector<QPointF> &points )
133  {
134  slopes.resize( points.size() );
135  d_m = slopes.data();
136  }
137 
138  inline void start( const QPointF &, double m0 )
139  {
140  *d_m++ = m0;
141  }
142 
143  inline void addCubic( const QPointF &, double,
144  const QPointF &, double m2 )
145  {
146  *d_m++ = m2;
147  }
148 
149  QVector<double> slopes;
150 
151  private:
152  double *d_m;
153  };
154 
156  {
157  static inline double value( double dx1, double dy1, double s1,
158  double dx2, double dy2, double s2 )
159  {
160  return qwtSlopeCardinal( dx1, dy1, s1, dx2, dy2, s2 );
161  }
162  };
163 
165  {
166  static inline double value( double dx1, double dy1, double s1,
167  double dx2, double dy2, double s2 )
168  {
169  return qwtSlopeParabolicBlending( dx1, dy1, s1, dx2, dy2, s2 );
170  }
171  };
172 
173  struct slopePChip
174  {
175  static inline double value( double dx1, double dy1, double s1,
176  double dx2, double dy2, double s2 )
177  {
178  return qwtSlopePChip( dx1, dy1, s1, dx2, dy2, s2 );
179  }
180  };
181 };
182 
183 template< class Slope >
184 static inline double qwtSlopeP3(
185  const QPointF &p1, const QPointF &p2, const QPointF &p3 )
186 {
187  const double dx1 = p2.x() - p1.x();
188  const double dy1 = p2.y() - p1.y();
189  const double dx2 = p3.x() - p2.x();
190  const double dy2 = p3.y() - p2.y();
191 
192  return Slope::value( dx1, dy1, dy1 / dx1, dx2, dy2, dy2 / dx2 );
193 }
194 
195 static inline double qwtSlopeAkima( double s1, double s2, double s3, double s4 )
196 {
197  if ( ( s1 == s2 ) && ( s3 == s4 ) )
198  {
199  return 0.5 * ( s2 + s3 );
200  }
201 
202  const double ds12 = qAbs( s2 - s1 );
203  const double ds34 = qAbs( s4 - s3 );
204 
205  return ( s2 * ds34 + s3 * ds12 ) / ( ds12 + ds34 );
206 }
207 
208 static inline double qwtSlopeAkima( const QPointF &p1, const QPointF &p2,
209  const QPointF &p3, const QPointF &p4, const QPointF &p5 )
210 {
211  const double s1 = qwtSlopeLine( p1, p2 );
212  const double s2 = qwtSlopeLine( p2, p3 );
213  const double s3 = qwtSlopeLine( p3, p4 );
214  const double s4 = qwtSlopeLine( p4, p5 );
215 
216  return qwtSlopeAkima( s1, s2, s3, s4 );
217 }
218 
219 template< class Slope >
221  const QwtSplineLocal *spline, const QVector<QPointF> &points,
222  double &slopeBegin, double &slopeEnd )
223 {
224  const int n = points.size();
225  const QPointF *p = points.constData();
226 
227  if ( ( spline->boundaryType() == QwtSpline::PeriodicPolygon )
228  || ( spline->boundaryType() == QwtSpline::ClosedPolygon ) )
229  {
230  const QPointF pn = p[0] - ( p[n-1] - p[n-2] );
231  slopeBegin = slopeEnd = qwtSlopeP3<Slope>( pn, p[0], p[1] );
232  }
233  else
234  {
235  const double m2 = qwtSlopeP3<Slope>( p[0], p[1], p[2] );
236  slopeBegin = spline->slopeAtBeginning( points, m2 );
237 
238  const double mn2 = qwtSlopeP3<Slope>( p[n-3], p[n-2], p[n-1] );
239  slopeEnd = spline->slopeAtEnd( points, mn2 );
240  }
241 }
242 
243 template< class SplineStore, class Slope >
244 static inline SplineStore qwtSplineL1(
245  const QwtSplineLocal *spline, const QVector<QPointF> &points )
246 {
247  const int size = points.size();
248  const QPointF *p = points.constData();
249 
250  double slopeBegin, slopeEnd;
251  qwtSplineBoundariesL1<Slope>( spline, points, slopeBegin, slopeEnd );
252 
253  double m1 = slopeBegin;
254 
255  SplineStore store;
256  store.init( points );
257  store.start( p[0], m1 );
258 
259  double dx1 = p[1].x() - p[0].x();
260  double dy1 = p[1].y() - p[0].y();
261  double s1 = dy1 / dx1;
262 
263  for ( int i = 1; i < size - 1; i++ )
264  {
265  const double dx2 = p[i+1].x() - p[i].x();
266  const double dy2 = p[i+1].y() - p[i].y() ;
267 
268  // cardinal spline doesn't need the line slopes, but
269  // the compiler will eliminate pointless calculations
270  const double s2 = dy2 / dx2;
271 
272  const double m2 = Slope::value( dx1, dy1, s1, dx2, dy2, s2 );
273 
274  store.addCubic( p[i-1], m1, p[i], m2 );
275 
276  dx1 = dx2;
277  dy1 = dy2;
278  s1 = s2;
279  m1 = m2;
280  }
281 
282  store.addCubic( p[size-2], m1, p[size-1], slopeEnd );
283 
284  return store;
285 }
286 
287 static inline void qwtSplineAkimaBoundaries(
288  const QwtSplineLocal *spline, const QVector<QPointF> &points,
289  double &slopeBegin, double &slopeEnd )
290 {
291  const int n = points.size();
292  const QPointF *p = points.constData();
293 
294  if ( ( spline->boundaryType() == QwtSpline::PeriodicPolygon )
295  || ( spline->boundaryType() == QwtSpline::ClosedPolygon ) )
296  {
297  const QPointF p2 = p[0] - ( p[n-1] - p[n-2] );
298  const QPointF p1 = p2 - ( p[n-2] - p[n-3] );
299 
300  slopeBegin = slopeEnd = qwtSlopeAkima( p1, p2, p[0], p[1], p[2] );
301 
302  return;
303  }
304 
307  {
308  slopeBegin = spline->boundaryValue( QwtSpline::AtBeginning);
309  slopeEnd = spline->boundaryValue( QwtSpline::AtEnd );
310 
311  return;
312  }
313 
314  if ( n == 3 )
315  {
316  const double s1 = qwtSlopeLine( p[0], p[1] );
317  const double s2 = qwtSlopeLine( p[1], p[2] );
318  const double m = qwtSlopeAkima( 0.5 * s1, s1, s2, 0.5 * s2 );
319 
320  slopeBegin = spline->slopeAtBeginning( points, m );
321  slopeEnd = spline->slopeAtEnd( points, m );
322  }
323  else
324  {
325  double s[3];
326 
327  s[0] = qwtSlopeLine( p[0], p[1] );
328  s[1] = qwtSlopeLine( p[1], p[2] );
329  s[2] = qwtSlopeLine( p[2], p[3] );
330 
331  const double m2 = qwtSlopeAkima( 0.5 * s[0], s[0], s[1], s[2] );
332 
333  slopeBegin = spline->slopeAtBeginning( points, m2 );
334 
335  s[0] = qwtSlopeLine( p[n-4], p[n-3] );
336  s[1] = qwtSlopeLine( p[n-3], p[n-2] );
337  s[2] = qwtSlopeLine( p[n-2], p[n-1] );
338 
339  const double mn2 = qwtSlopeAkima( s[0], s[1], s[2], 0.5 * s[2] );
340 
341  slopeEnd = spline->slopeAtEnd( points, mn2 );
342  }
343 }
344 
345 template< class SplineStore >
346 static inline SplineStore qwtSplineAkima(
347  const QwtSplineLocal *spline, const QVector<QPointF> &points )
348 {
349  const int size = points.size();
350  const QPointF *p = points.constData();
351 
352  double slopeBegin, slopeEnd;
353  qwtSplineAkimaBoundaries( spline, points, slopeBegin, slopeEnd );
354 
355  double m1 = slopeBegin;
356 
357  SplineStore store;
358  store.init( points );
359  store.start( p[0], m1 );
360 
361  double s2 = qwtSlopeLine( p[0], p[1] );
362  double s3 = qwtSlopeLine( p[1], p[2] );
363  double s1 = 0.5 * s2;
364 
365  for ( int i = 0; i < size - 3; i++ )
366  {
367  const double s4 = qwtSlopeLine( p[i+2], p[i+3] );
368 
369  const double m2 = qwtSlopeAkima( s1, s2, s3, s4 );
370  store.addCubic( p[i], m1, p[i+1], m2 );
371 
372  s1 = s2;
373  s2 = s3;
374  s3 = s4;
375 
376  m1 = m2;
377  }
378 
379  const double m2 = qwtSlopeAkima( s1, s2, s3, 0.5 * s3 );
380 
381  store.addCubic( p[size - 3], m1, p[size - 2], m2 );
382  store.addCubic( p[size - 2], m2, p[size - 1], slopeEnd );
383 
384  return store;
385 }
386 
387 template< class SplineStore >
388 static inline SplineStore qwtSplineLocal(
389  const QwtSplineLocal *spline, const QVector<QPointF> &points )
390 {
391  SplineStore store;
392 
393  const int size = points.size();
394  if ( size <= 1 )
395  return store;
396 
397  if ( size == 2 )
398  {
399  const double s0 = qwtSlopeLine( points[0], points[1] );
400  const double m1 = spline->slopeAtBeginning( points, s0 );
401  const double m2 = spline->slopeAtEnd( points, s0 );
402 
403  store.init( points );
404  store.start( points[0], m1 );
405  store.addCubic( points[0], m1, points[1], m2 );
406 
407  return store;
408  }
409 
410  switch( spline->type() )
411  {
413  {
414  using namespace QwtSplineLocalP;
415  store = qwtSplineL1<SplineStore, slopeCardinal>( spline, points );
416  break;
417  }
419  {
420  using namespace QwtSplineLocalP;
421  store = qwtSplineL1<SplineStore, slopeParabolicBlending>( spline, points );
422  break;
423  }
425  {
426  using namespace QwtSplineLocalP;
427  store = qwtSplineL1<SplineStore, slopePChip>( spline, points );
428  break;
429  }
431  {
432  store = qwtSplineAkima<SplineStore>( spline, points );
433  break;
434  }
435  default:
436  break;
437  }
438 
439  return store;
440 }
441 
449  d_type( type )
450 {
453 
456 }
457 
460 {
461 }
462 
467 {
468  return d_type;
469 }
470 
480 QPainterPath QwtSplineLocal::painterPath( const QPolygonF &points ) const
481 {
483  {
484  using namespace QwtSplineLocalP;
485  return qwtSplineLocal<PathStore>( this, points).path;
486  }
487 
488  return QwtSplineC1::painterPath( points );
489 }
490 
500 QVector<QLineF> QwtSplineLocal::bezierControlLines( const QPolygonF &points ) const
501 {
503  {
504  using namespace QwtSplineLocalP;
505  return qwtSplineLocal<ControlPointsStore>( this, points ).controlPoints;
506  }
507 
508  return QwtSplineC1::bezierControlLines( points );
509 }
510 
519 QVector<double> QwtSplineLocal::slopes( const QPolygonF &points ) const
520 {
521  using namespace QwtSplineLocalP;
522  return qwtSplineLocal<SlopeStore>( this, points ).slopes;
523 }
524 
535 QVector<QwtSplinePolynomial> QwtSplineLocal::polynomials( const QPolygonF &points ) const
536 {
537  // Polynomial store -> TODO
538  return QwtSplineC1::polynomials( points );
539 }
540 
551 {
552  switch ( d_type )
553  {
554  case Akima:
555  {
556  // polynoms: 2 left, 2 right
557  return 2;
558  }
559  case Cardinal:
560  case ParabolicBlending:
561  case PChip:
562  {
563  // polynoms: 1 left, 1 right
564  return 1;
565  }
566  }
567 
568  return QwtSplineC1::locality();
569 }
static double qwtSlopeLine(const QPointF &p1, const QPointF &p2)
static SplineStore qwtSplineL1(const QwtSplineLocal *spline, const QVector< QPointF > &points)
void addCubic(const QPointF &p1, double m1, const QPointF &p2, double m2)
virtual uint locality() const
Definition: qwt_spline.cpp:562
virtual uint locality() const
virtual QPainterPath painterPath(const QPolygonF &) const
Calculate an interpolated painter path.
static double qwtSlopeP3(const QPointF &p1, const QPointF &p2, const QPointF &p3)
static SplineStore qwtSplineAkima(const QwtSplineLocal *spline, const QVector< QPointF > &points)
virtual QVector< QLineF > bezierControlLines(const QPolygonF &) const
Interpolate a curve with Bezier curves.
static void qwtSplineBoundariesL1(const QwtSplineLocal *spline, const QVector< QPointF > &points, double &slopeBegin, double &slopeEnd)
virtual ~QwtSplineLocal()
Destructor.
XmlRpcServer s
const Type d_type
Type
Spline interpolation type.
virtual QPainterPath painterPath(const QPolygonF &) const
Interpolate a curve with Bezier curves.
void addCubic(const QPointF &, double, const QPointF &, double m2)
static double qwtSlopeAkima(double s1, double s2, double s3, double s4)
const QwtSplineParametrization * parametrization() const
Definition: qwt_spline.cpp:603
the condiation is at the end of the polynomial
Definition: qwt_spline.h:101
static double qwtSlopePChip(double dx1, double dy1, double s1, double dx2, double dy2, double s2)
void setBoundaryCondition(BoundaryPosition, int condition)
Define the condition for an endpoint of the spline.
Definition: qwt_spline.cpp:637
void init(const QVector< QPointF > &points)
static double value(double dx1, double dy1, double s1, double dx2, double dy2, double s2)
static bool qwtIsStrictlyMonotonic(double dy1, double dy2)
the condiation is at the beginning of the polynomial
Definition: qwt_spline.h:98
GraphId path[kMaxDeadlockPathLen]
void init(const QVector< QPointF > &points)
static double qwtSlopeCardinal(double dx1, double dy1, double s1, double dx2, double dy2, double s2)
virtual QVector< double > slopes(const QPolygonF &) const
Find the first derivative at the control points.
virtual QVector< QwtSplinePolynomial > polynomials(const QPolygonF &) const
Calculate the interpolating polynomials for a non parametric spline.
void setBoundaryValue(BoundaryPosition, double value)
Define the boundary value.
Definition: qwt_spline.cpp:668
void addCubic(const QPointF &p1, double m1, const QPointF &p2, double m2)
int boundaryCondition(BoundaryPosition) const
Definition: qwt_spline.cpp:649
void start(const QPointF &, double m0)
void start(const QPointF &p0, double)
static void qwtSplineAkimaBoundaries(const QwtSplineLocal *spline, const QVector< QPointF > &points, double &slopeBegin, double &slopeEnd)
uintptr_t size
void init(const QVector< QPointF > &)
static double value(double dx1, double dy1, double s1, double dx2, double dy2, double s2)
static double value(double dx1, double dy1, double s1, double dx2, double dy2, double s2)
virtual double slopeAtBeginning(const QPolygonF &, double slopeNext) const
Definition: qwt_spline.cpp:977
static SplineStore qwtSplineLocal(const QwtSplineLocal *spline, const QVector< QPointF > &points)
virtual QVector< QwtSplinePolynomial > polynomials(const QPolygonF &) const
Calculate the interpolating polynomials for a non parametric spline.
void start(const QPointF &, double)
virtual QVector< QLineF > bezierControlLines(const QPolygonF &) const
Interpolate a curve with Bezier curves.
virtual double slopeAtEnd(const QPolygonF &, double slopeBefore) const
Definition: qwt_spline.cpp:995
BoundaryType boundaryType() const
Definition: qwt_spline.cpp:624
int i
double boundaryValue(BoundaryPosition) const
Definition: qwt_spline.cpp:680
static double qwtSlopeParabolicBlending(double dx1, double dy1, double s1, double dx2, double dy2, double s2)
A spline with C1 continuity.
int n
QwtSplineLocal(Type type)
Constructor.
Type type() const


plotjuggler
Author(s): Davide Faconti
autogenerated on Sat Jul 6 2019 03:44:18