@@ -1,13 +1,100 | |||
|
1 | 1 | #include "qsplineseries.h" |
|
2 | 2 | |
|
3 | 3 | QSplineSeries::QSplineSeries(QObject *parent) : |
|
4 | 4 | QObject(parent) |
|
5 | 5 | { |
|
6 | 6 | } |
|
7 | 7 | |
|
8 | 8 | QSplineSeries& QSplineSeries::operator << (const QPointF &value) |
|
9 | 9 | { |
|
10 | 10 | d->m_data.append(value); |
|
11 | 11 | emit changed(); |
|
12 | 12 | return *this; |
|
13 | 13 | } |
|
14 | ||
|
15 | void QSplineSeries::GetCurveControlPoints() | |
|
16 | { | |
|
17 | int n = m_data.size() - 1; | |
|
18 | if (n < 1) | |
|
19 | throw new ArgumentException | |
|
20 | ("At least two knot points required", "knots"); | |
|
21 | if (n == 1) | |
|
22 | { // Special case: Bezier curve should be a straight line. | |
|
23 | firstControlPoints = new Point[1]; | |
|
24 | // 3P1 = 2P0 + P3 | |
|
25 | firstControlPoints[0].X = (2 * knots[0].X + knots[1].X) / 3; | |
|
26 | firstControlPoints[0].Y = (2 * knots[0].Y + knots[1].Y) / 3; | |
|
27 | ||
|
28 | secondControlPoints = new Point[1]; | |
|
29 | // P2 = 2P1 P0 | |
|
30 | secondControlPoints[0].X = 2 * | |
|
31 | firstControlPoints[0].X - knots[0].X; | |
|
32 | secondControlPoints[0].Y = 2 * | |
|
33 | firstControlPoints[0].Y - knots[0].Y; | |
|
34 | return; | |
|
35 | } | |
|
36 | ||
|
37 | // Calculate first Bezier control points | |
|
38 | // Right hand side vector | |
|
39 | double[] rhs = new double[n]; | |
|
40 | ||
|
41 | // Set right hand side X values | |
|
42 | for (int i = 1; i < n - 1; ++i) | |
|
43 | rhs[i] = 4 * knots[i].X + 2 * knots[i + 1].X; | |
|
44 | rhs[0] = knots[0].X + 2 * knots[1].X; | |
|
45 | rhs[n - 1] = (8 * knots[n - 1].X + knots[n].X) / 2.0; | |
|
46 | // Get first control points X-values | |
|
47 | double[] x = GetFirstControlPoints(rhs); | |
|
48 | ||
|
49 | // Set right hand side Y values | |
|
50 | for (int i = 1; i < n - 1; ++i) | |
|
51 | rhs[i] = 4 * knots[i].Y + 2 * knots[i + 1].Y; | |
|
52 | rhs[0] = knots[0].Y + 2 * knots[1].Y; | |
|
53 | rhs[n - 1] = (8 * knots[n - 1].Y + knots[n].Y) / 2.0; | |
|
54 | // Get first control points Y-values | |
|
55 | double[] y = GetFirstControlPoints(rhs); | |
|
56 | ||
|
57 | // Fill output arrays. | |
|
58 | firstControlPoints = new Point[n]; | |
|
59 | secondControlPoints = new Point[n]; | |
|
60 | for (int i = 0; i < n; ++i) | |
|
61 | { | |
|
62 | // First control point | |
|
63 | firstControlPoints[i] = new Point(x[i], y[i]); | |
|
64 | // Second control point | |
|
65 | if (i < n - 1) | |
|
66 | secondControlPoints[i] = new Point(2 * knots | |
|
67 | [i + 1].X - x[i + 1], 2 * | |
|
68 | knots[i + 1].Y - y[i + 1]); | |
|
69 | else | |
|
70 | secondControlPoints[i] = new Point((knots | |
|
71 | [n].X + x[n - 1]) / 2, | |
|
72 | (knots[n].Y + y[n - 1]) / 2); | |
|
73 | } | |
|
74 | } | |
|
75 | ||
|
76 | /// <summary> | |
|
77 | /// Solves a tridiagonal system for one of coordinates (x or y) | |
|
78 | /// of first Bezier control points. | |
|
79 | /// </summary> | |
|
80 | /// <param name="rhs">Right hand side vector.</param> | |
|
81 | /// <returns>Solution vector.</returns> | |
|
82 | void GetFirstControlPoints(qreal[] rhs) | |
|
83 | { | |
|
84 | int n = rhs.Length; | |
|
85 | double[] x = new double[n]; // Solution vector. | |
|
86 | double[] tmp = new double[n]; // Temp workspace. | |
|
87 | ||
|
88 | double b = 2.0; | |
|
89 | x[0] = rhs[0] / b; | |
|
90 | for (int i = 1; i < n; i++) // Decomposition and forward substitution. | |
|
91 | { | |
|
92 | tmp[i] = 1 / b; | |
|
93 | b = (i < n - 1 ? 4.0 : 3.5) - tmp[i]; | |
|
94 | x[i] = (rhs[i] - x[i - 1]) / b; | |
|
95 | } | |
|
96 | for (int i = 1; i < n; i++) | |
|
97 | x[n - i - 1] -= tmp[n - i] * x[n - i]; // Backsubstitution. | |
|
98 | ||
|
99 | return x; | |
|
100 | } |
@@ -1,29 +1,31 | |||
|
1 | 1 | #ifndef QSPLINESERIES_H |
|
2 | 2 | #define QSPLINESERIES_H |
|
3 | 3 | |
|
4 | 4 | #include "qchartseries.h" |
|
5 | 5 | |
|
6 | 6 | QTCOMMERCIALCHART_BEGIN_NAMESPACE |
|
7 | 7 | |
|
8 | 8 | class QSplineSeries : public QChartSeries |
|
9 | 9 | { |
|
10 | 10 | Q_OBJECT |
|
11 | 11 | public: |
|
12 | 12 | |
|
13 | 13 | QSplineSeries(QObject *parent = 0); |
|
14 | 14 | QChartSeriesType type() const { return QChartSeries::SeriesTypeSpline; } |
|
15 | 15 | void addData(QPointF value); |
|
16 | 16 | QSplineSeries& operator << (const QPointF &value); |
|
17 | void calculateControlPoints(); | |
|
17 | 18 | |
|
18 | 19 | signals: |
|
19 | 20 | |
|
20 | 21 | public slots: |
|
21 | 22 | |
|
22 | 23 | private: |
|
23 | 24 | QList<QPointF> m_data; |
|
25 | QList<QPointF> m_controlPoints; | |
|
24 | 26 | |
|
25 | 27 | }; |
|
26 | 28 | |
|
27 | 29 | QTCOMMERCIALCHART_END_NAMESPACE |
|
28 | 30 | |
|
29 | 31 | #endif // QSPLINESERIES_H |
General Comments 0
You need to be logged in to leave comments.
Login now