##// END OF EJS Templates
Fixed broken spline series
Marek Rosa -
r992:e111c2594d21
parent child
Show More
@@ -1,205 +1,211
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2012 Digia Plc
3 ** Copyright (C) 2012 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "qsplineseries.h"
21 #include "qsplineseries.h"
22 #include "qsplineseries_p.h"
22 #include "qsplineseries_p.h"
23 #include "splinechartitem_p.h"
23 #include "splinechartitem_p.h"
24 #include "chartdataset_p.h"
24 #include "chartdataset_p.h"
25 #include "charttheme_p.h"
25 #include "charttheme_p.h"
26 #include "chartanimator_p.h"
26 #include "chartanimator_p.h"
27
27
28 /*!
28 /*!
29 \class QSplineSeries
29 \class QSplineSeries
30 \brief Series type used to store data needed to draw a spline.
30 \brief Series type used to store data needed to draw a spline.
31
31
32 QSplineSeries stores the data points along with the segment control points needed by QPainterPath to draw spline
32 QSplineSeries stores the data points along with the segment control points needed by QPainterPath to draw spline
33 Control points are automatically calculated when data changes. The algorithm computes the points so that the normal spline can be drawn.
33 Control points are automatically calculated when data changes. The algorithm computes the points so that the normal spline can be drawn.
34 */
34 */
35
35
36 /*!
36 /*!
37 \fn QSeriesType QSplineSeries::type() const
37 \fn QSeriesType QSplineSeries::type() const
38 Returns the type of the series
38 Returns the type of the series
39 */
39 */
40
40
41 /*!
41 /*!
42 \fn QSeriesType QSplineSeries::controlPoint(int index) const
42 \fn QSeriesType QSplineSeries::controlPoint(int index) const
43 Returns the control point specified by \a index
43 Returns the control point specified by \a index
44 */
44 */
45
45
46 QTCOMMERCIALCHART_BEGIN_NAMESPACE
46 QTCOMMERCIALCHART_BEGIN_NAMESPACE
47
47
48 /*!
48 /*!
49 Constructs empty series object which is a child of \a parent.
49 Constructs empty series object which is a child of \a parent.
50 When series object is added to QChartView or QChart instance then the ownerships is transferred.
50 When series object is added to QChartView or QChart instance then the ownerships is transferred.
51 */
51 */
52
52
53 QSplineSeries::QSplineSeries(QObject *parent) :
53 QSplineSeries::QSplineSeries(QObject *parent) :
54 QLineSeries(*new QSplineSeriesPrivate(this),parent)
54 QLineSeries(*new QSplineSeriesPrivate(this),parent)
55 {
55 {
56 }
56 }
57
57
58 QAbstractSeries::QSeriesType QSplineSeries::type() const
58 QAbstractSeries::QSeriesType QSplineSeries::type() const
59 {
59 {
60 return QAbstractSeries::SeriesTypeSpline;
60 return QAbstractSeries::SeriesTypeSpline;
61 }
61 }
62
62
63 QPointF QSplineSeries::controlPoint(int index) const
63 QPointF QSplineSeries::controlPoint(int index) const
64 {
64 {
65 Q_D(const QSplineSeries);
65 Q_D(const QSplineSeries);
66 return d->m_controlPoints[index];
66 return d->m_controlPoints[index];
67 }
67 }
68
68
69 /*!
70 \fn bool QSplineSeries::setModelMappingRange(int first, int count)
71 Allows limiting the model mapping.
72 Parameter \a first specifies which element of the model should be used as a first one of the series.
73 Parameter \a count specifies how many elements should be mapped. If count is not specified (defaults to -1)
74 then all the items following \a first item in a model are used.
75 \sa setModel(), setModelMapping()
76 */
77 void QSplineSeries::setModelMapping(int modelX, int modelY, Qt::Orientation orientation)
78 {
79 Q_D(QSplineSeries);
80 QXYSeries::setModelMapping(modelX, modelY, orientation);
81 d->calculateControlPoints();
82 }
83
69 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
84 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
70
85
71 QSplineSeriesPrivate::QSplineSeriesPrivate(QSplineSeries* q):QLineSeriesPrivate(q)
86 QSplineSeriesPrivate::QSplineSeriesPrivate(QSplineSeries* q):QLineSeriesPrivate(q)
72 {
87 {
73 QObject::connect(this,SIGNAL(pointAdded(int)), this, SLOT(updateControlPoints()));
88 QObject::connect(this,SIGNAL(pointAdded(int)), this, SLOT(updateControlPoints()));
74 QObject::connect(this,SIGNAL(pointRemoved(int)), this, SLOT(updateControlPoints()));
89 QObject::connect(this,SIGNAL(pointRemoved(int)), this, SLOT(updateControlPoints()));
75 QObject::connect(this,SIGNAL(pointReplaced(int)), this, SLOT(updateControlPoints()));
90 QObject::connect(this,SIGNAL(pointReplaced(int)), this, SLOT(updateControlPoints()));
76 };
91 };
77
92
78 /*!
93 /*!
79 \internal
94 \internal
80 Calculates control points which are needed by QPainterPath.cubicTo function to draw the cubic Bezier cureve between two points.
95 Calculates control points which are needed by QPainterPath.cubicTo function to draw the cubic Bezier cureve between two points.
81 */
96 */
82 void QSplineSeriesPrivate::calculateControlPoints()
97 void QSplineSeriesPrivate::calculateControlPoints()
83 {
98 {
84
99
85 Q_Q(QSplineSeries);
100 Q_Q(QSplineSeries);
86 // Based on http://www.codeproject.com/Articles/31859/Draw-a-Smooth-Curve-through-a-Set-of-2D-Points-wit
101 // Based on http://www.codeproject.com/Articles/31859/Draw-a-Smooth-Curve-through-a-Set-of-2D-Points-wit
87 // CPOL License
102 // CPOL License
88
103
89 int n = q->count() - 1;
104 int n = q->count() - 1;
90 if (n == 1)
105 if (n == 1)
91 { // Special case: Bezier curve should be a straight line.
106 { // Special case: Bezier curve should be a straight line.
92 // firstControlPoints = new Point[1];
107 // firstControlPoints = new Point[1];
93 // 3P1 = 2P0 + P3
108 // 3P1 = 2P0 + P3
94 m_controlPoints.append(QPointF((2 * q->x(0) + q->x(1)) / 3, (2 * q->y(0) + q->y(1)) / 3));
109 m_controlPoints.append(QPointF((2 * q->x(0) + q->x(1)) / 3, (2 * q->y(0) + q->y(1)) / 3));
95
110
96 // P2 = 2P1 P0
111 // P2 = 2P1 P0
97 m_controlPoints.append(QPointF(2 * m_controlPoints[0].x() - q->x(0), 2 * m_controlPoints[0].y() - q->y(0)));
112 m_controlPoints.append(QPointF(2 * m_controlPoints[0].x() - q->x(0), 2 * m_controlPoints[0].y() - q->y(0)));
98 return;
113 return;
99 }
114 }
100
115
101 // Calculate first Bezier control points
116 // Calculate first Bezier control points
102 // Right hand side vector
117 // Right hand side vector
103 // Set of equations for P0 to Pn points.
118 // Set of equations for P0 to Pn points.
104 //
119 //
105 // | 2 1 0 0 ... 0 0 0 ... 0 0 0 | | P1_1 | | P0 + 2 * P1 |
120 // | 2 1 0 0 ... 0 0 0 ... 0 0 0 | | P1_1 | | P0 + 2 * P1 |
106 // | 1 4 1 0 ... 0 0 0 ... 0 0 0 | | P1_2 | | 4 * P1 + 2 * P2 |
121 // | 1 4 1 0 ... 0 0 0 ... 0 0 0 | | P1_2 | | 4 * P1 + 2 * P2 |
107 // | 0 1 4 1 ... 0 0 0 ... 0 0 0 | | P1_3 | | 4 * P2 + 2 * P3 |
122 // | 0 1 4 1 ... 0 0 0 ... 0 0 0 | | P1_3 | | 4 * P2 + 2 * P3 |
108 // | . . . . . . . . . . . . | | ... | | ... |
123 // | . . . . . . . . . . . . | | ... | | ... |
109 // | 0 0 0 0 ... 1 4 1 ... 0 0 0 | * | P1_i | = | 4 * P(i-1) + 2 * Pi |
124 // | 0 0 0 0 ... 1 4 1 ... 0 0 0 | * | P1_i | = | 4 * P(i-1) + 2 * Pi |
110 // | . . . . . . . . . . . . | | ... | | ... |
125 // | . . . . . . . . . . . . | | ... | | ... |
111 // | 0 0 0 0 0 0 0 0 ... 1 4 1 | | P1_(n-1)| | 4 * P(n-2) + 2 * P(n-1) |
126 // | 0 0 0 0 0 0 0 0 ... 1 4 1 | | P1_(n-1)| | 4 * P(n-2) + 2 * P(n-1) |
112 // | 0 0 0 0 0 0 0 0 ... 0 2 7 | | P1_n | | 8 * P(n-1) + Pn |
127 // | 0 0 0 0 0 0 0 0 ... 0 2 7 | | P1_n | | 8 * P(n-1) + Pn |
113 //
128 //
114 QList<qreal> rhs;
129 QList<qreal> rhs;
115 rhs.append(q->x(0) + 2 * q->x(1));
130 rhs.append(q->x(0) + 2 * q->x(1));
116
131
117 // Set right hand side X values
132 // Set right hand side X values
118 for (int i = 1; i < n - 1; ++i)
133 for (int i = 1; i < n - 1; ++i)
119 rhs.append(4 * q->x(i) + 2 * q->x(i + 1));
134 rhs.append(4 * q->x(i) + 2 * q->x(i + 1));
120
135
121 rhs.append((8 * q->x(n - 1) + q->x(n)) / 2.0);
136 rhs.append((8 * q->x(n - 1) + q->x(n)) / 2.0);
122 // Get first control points X-values
137 // Get first control points X-values
123 QList<qreal> xControl = getFirstControlPoints(rhs);
138 QList<qreal> xControl = getFirstControlPoints(rhs);
124 rhs[0] = q->y(0) + 2 * q->y(1);
139 rhs[0] = q->y(0) + 2 * q->y(1);
125
140
126 // Set right hand side Y values
141 // Set right hand side Y values
127 for (int i = 1; i < n - 1; ++i)
142 for (int i = 1; i < n - 1; ++i)
128 rhs[i] = 4 * q->y(i) + 2 * q->y(i + 1);
143 rhs[i] = 4 * q->y(i) + 2 * q->y(i + 1);
129
144
130 rhs[n - 1] = (8 * q->y(n - 1) + q->y(n)) / 2.0;
145 rhs[n - 1] = (8 * q->y(n - 1) + q->y(n)) / 2.0;
131 // Get first control points Y-values
146 // Get first control points Y-values
132 QList<qreal> yControl = getFirstControlPoints(rhs);
147 QList<qreal> yControl = getFirstControlPoints(rhs);
133
148
134 // Fill output arrays.
149 // Fill output arrays.
135 for (int i = 0; i < n; ++i) {
150 for (int i = 0; i < n; ++i) {
136 // First control point
151 // First control point
137 m_controlPoints.append(QPointF(xControl[i], yControl[i]));
152 m_controlPoints.append(QPointF(xControl[i], yControl[i]));
138 // Second control point
153 // Second control point
139 if (i < n - 1)
154 if (i < n - 1)
140 m_controlPoints.append(QPointF(2 * q->x(i + 1) - xControl[i + 1], 2 * q->y(i + 1) - yControl[i + 1]));
155 m_controlPoints.append(QPointF(2 * q->x(i + 1) - xControl[i + 1], 2 * q->y(i + 1) - yControl[i + 1]));
141 else
156 else
142 m_controlPoints.append(QPointF((q->x(n) + xControl[n - 1]) / 2, (q->y(n) + yControl[n - 1]) / 2));
157 m_controlPoints.append(QPointF((q->x(n) + xControl[n - 1]) / 2, (q->y(n) + yControl[n - 1]) / 2));
143 }
158 }
144 }
159 }
145
160
146 /*!
161 /*!
147 \internal
162 \internal
148 */
163 */
149 QList<qreal> QSplineSeriesPrivate::getFirstControlPoints(QList<qreal> rhs)
164 QList<qreal> QSplineSeriesPrivate::getFirstControlPoints(QList<qreal> rhs)
150 {
165 {
151 QList<qreal> x; // Solution vector.
166 QList<qreal> x; // Solution vector.
152 QList<qreal> tmp; // Temp workspace.
167 QList<qreal> tmp; // Temp workspace.
153
168
154 qreal b = 2.0;
169 qreal b = 2.0;
155 x.append(rhs[0] / b);
170 x.append(rhs[0] / b);
156 tmp.append(0);
171 tmp.append(0);
157 for (int i = 1; i < rhs.size(); i++) {
172 for (int i = 1; i < rhs.size(); i++) {
158 // Decomposition and forward substitution.
173 // Decomposition and forward substitution.
159 tmp.append(1 / b);
174 tmp.append(1 / b);
160 b = (i < rhs.size() - 1 ? 4.0 : 3.5) - tmp[i];
175 b = (i < rhs.size() - 1 ? 4.0 : 3.5) - tmp[i];
161 x.append((rhs[i] - x[i - 1]) / b);
176 x.append((rhs[i] - x[i - 1]) / b);
162 }
177 }
163 for (int i = 1; i < rhs.size(); i++)
178 for (int i = 1; i < rhs.size(); i++)
164 x[rhs.size() - i - 1] -= tmp[rhs.size() - i] * x[rhs.size() - i]; // Backsubstitution.
179 x[rhs.size() - i - 1] -= tmp[rhs.size() - i] * x[rhs.size() - i]; // Backsubstitution.
165
180
166 return x;
181 return x;
167 }
182 }
168
183
169 /*!
184 /*!
170 \internal
185 \internal
171 Updates the control points, besed on currently avaiable knots.
186 Updates the control points, besed on currently avaiable knots.
172 */
187 */
173 void QSplineSeriesPrivate::updateControlPoints()
188 void QSplineSeriesPrivate::updateControlPoints()
174 {
189 {
175 Q_Q(QSplineSeries);
190 Q_Q(QSplineSeries);
176 if (q->count() > 1) {
191 if (q->count() > 1) {
177 m_controlPoints.clear();
192 m_controlPoints.clear();
178 calculateControlPoints();
193 calculateControlPoints();
179 }
194 }
180 }
195 }
181
196
182 /*!
183 \fn bool QSplineSeries::setModelMappingRange(int first, int count)
184 Allows limiting the model mapping.
185 Parameter \a first specifies which element of the model should be used as a first one of the series.
186 Parameter \a count specifies how many elements should be mapped. If count is not specified (defaults to -1)
187 then all the items following \a first item in a model are used.
188 \sa setModel(), setModelMapping()
189 */
190
191 Chart* QSplineSeriesPrivate::createGraphics(ChartPresenter* presenter)
197 Chart* QSplineSeriesPrivate::createGraphics(ChartPresenter* presenter)
192 {
198 {
193 Q_Q(QSplineSeries);
199 Q_Q(QSplineSeries);
194 SplineChartItem* spline = new SplineChartItem(q,presenter);
200 SplineChartItem* spline = new SplineChartItem(q,presenter);
195 if(presenter->animationOptions().testFlag(QChart::SeriesAnimations)) {
201 if(presenter->animationOptions().testFlag(QChart::SeriesAnimations)) {
196 presenter->animator()->addAnimation(spline);
202 presenter->animator()->addAnimation(spline);
197 }
203 }
198 presenter->chartTheme()->decorate(q, presenter->dataSet()->seriesIndex(q));
204 presenter->chartTheme()->decorate(q, presenter->dataSet()->seriesIndex(q));
199 return spline;
205 return spline;
200 }
206 }
201
207
202 #include "moc_qsplineseries.cpp"
208 #include "moc_qsplineseries.cpp"
203 #include "moc_qsplineseries_p.cpp"
209 #include "moc_qsplineseries_p.cpp"
204
210
205 QTCOMMERCIALCHART_END_NAMESPACE
211 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,52 +1,54
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2012 Digia Plc
3 ** Copyright (C) 2012 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #ifndef QSPLINESERIES_H
21 #ifndef QSPLINESERIES_H
22 #define QSPLINESERIES_H
22 #define QSPLINESERIES_H
23
23
24 #include <qchartglobal.h>
24 #include <qchartglobal.h>
25 #include <qlineseries.h>
25 #include <qlineseries.h>
26 #include <QList>
26 #include <QList>
27 #include <QPointF>
27 #include <QPointF>
28 #include <QtGlobal>
28 #include <QtGlobal>
29
29
30 QTCOMMERCIALCHART_BEGIN_NAMESPACE
30 QTCOMMERCIALCHART_BEGIN_NAMESPACE
31
31
32 class QSplineSeriesPrivate;
32 class QSplineSeriesPrivate;
33
33
34 class QTCOMMERCIALCHART_EXPORT QSplineSeries : public QLineSeries
34 class QTCOMMERCIALCHART_EXPORT QSplineSeries : public QLineSeries
35 {
35 {
36 Q_OBJECT
36 Q_OBJECT
37 public:
37 public:
38
38
39 explicit QSplineSeries(QObject *parent = 0);
39 explicit QSplineSeries(QObject *parent = 0);
40 QAbstractSeries::QSeriesType type() const;
40 QAbstractSeries::QSeriesType type() const;
41
41
42 QPointF controlPoint(int index) const;
42 QPointF controlPoint(int index) const;
43
43
44 void setModelMapping(int modelX, int modelY, Qt::Orientation orientation = Qt::Vertical);
45
44 private:
46 private:
45 Q_DECLARE_PRIVATE(QSplineSeries);
47 Q_DECLARE_PRIVATE(QSplineSeries);
46 Q_DISABLE_COPY(QSplineSeries);
48 Q_DISABLE_COPY(QSplineSeries);
47 friend class SplineChartItem;
49 friend class SplineChartItem;
48 };
50 };
49
51
50 QTCOMMERCIALCHART_END_NAMESPACE
52 QTCOMMERCIALCHART_END_NAMESPACE
51
53
52 #endif // QSPLINESERIES_H
54 #endif // QSPLINESERIES_H
General Comments 0
You need to be logged in to leave comments. Login now