##// END OF EJS Templates
Added automatic refresh of control points on add/remove point. Spline example updated
Marek Rosa -
r431:575ceaee424c
parent child
Show More
@@ -1,77 +1,109
1 1 #include "splinewidget.h"
2 2 #include "qchartview.h"
3 #include "qsplineseries.h"
4 3 #include "qlineseries.h"
5 4 #include <QGridLayout>
5 #include <QPushButton>
6 6
7 7 QTCOMMERCIALCHART_USE_NAMESPACE
8 8
9 9 SplineWidget::SplineWidget(QWidget *parent)
10 10 : QWidget(parent)
11 11 {
12 12 //create QSplineSeries
13 QSplineSeries* series = new QSplineSeries(this);
14 // series->add(QPointF(150, 100));
15 // series->add(QPointF(200, 130));
16 // series->add(QPointF(250, 120));
17 // series->add(QPointF(300, 140));
18 // series->add(QPointF(350, 100));
19 // series->add(QPointF(400, 120));
20 // series->add(QPointF(450, 150));
21 //// series->add(QPointF(600, 150));
22 // series->add(QPointF(500, 145));
23 // series->add(QPointF(550, 170));
24 // series->add(QPointF(600, 190));
25 // series->add(QPointF(650, 210));
26 // series->add(QPointF(700, 190));
27 // series->add(QPointF(750, 180));
28 // series->add(QPointF(800, 170));
13 series = new QSplineSeries(this);
14 series->add(QPointF(150, 100));
15 series->add(QPointF(200, 130));
16 series->add(QPointF(250, 120));
17 series->add(QPointF(300, 140));
18 series->add(QPointF(350, 100));
19 series->add(QPointF(400, 120));
20 series->add(QPointF(450, 150));
21 // series->add(QPointF(600, 150));
22 series->add(QPointF(500, 145));
23 series->add(QPointF(550, 170));
24 series->add(QPointF(600, 190));
25 series->add(QPointF(650, 210));
26 series->add(QPointF(700, 190));
27 series->add(QPointF(750, 180));
28 series->add(QPointF(800, 170));
29 29
30 // qsrand(time(NULL));
31 // for (int i = 0; i < 100; i++)
32 // {
33 // series->add(QPointF(i*7, qrand()%600));
34 // }
30 // series->calculateControlPoints();
31
32 QSplineSeries* series2 = new QSplineSeries(this);
33 qsrand(time(NULL));
34 // for (int i = 0; i < 100; i++)
35 // {
36 // series2->add(QPointF(i*7, qrand()%600));
37 // }
35 38 int k = 10;
36 39 for (int i = 0; i < 25; i++)
37 40 {
38 41 if (k > 60)
39 42 {
40 43 k = 10;
41 44 }
42 series->add(QPointF(i*50, k));
45 series2->add(QPointF(i*50, k));
43 46 k +=10;
44 47 }
45 48
46 series->calculateControlPoints();
49 // series2->calculateControlPoints();
47 50
48 // QLineSeries* lineSeries = new QLineSeries;
49 // for (int i = 0; i < series->count() - 1; i++)
50 // {
51 // lineSeries->add(series->at(i).x(), series->at(i).y());
52 // lineSeries->add(series->controlPoint(2*i).x(), series->controlPoint(2*i).y());
53 // lineSeries->add(series->controlPoint(2*i + 1).x(), series->controlPoint(2*i + 1).y());
54 // }
51 // QLineSeries* lineSeries = new QLineSeries;
52 // for (int i = 0; i < series->count() - 1; i++)
53 // {
54 // lineSeries->add(series->at(i).x(), series->at(i).y());
55 // lineSeries->add(series->controlPoint(2*i).x(), series->controlPoint(2*i).y());
56 // lineSeries->add(series->controlPoint(2*i + 1).x(), series->controlPoint(2*i + 1).y());
57 // }
55 58
56 // QLineChartSeries* lineSeries2 = new QLineChartSeries;
57 // lineSeries2->add(10, 50);
58 // lineSeries2->add(30, 15);
59 // lineSeries2->add(60, 40);
60 // lineSeries2->add(90, 70);
61 // lineSeries2->add(100, 20);
59 // QLineChartSeries* lineSeries2 = new QLineChartSeries;
60 // lineSeries2->add(10, 50);
61 // lineSeries2->add(30, 15);
62 // lineSeries2->add(60, 40);
63 // lineSeries2->add(90, 70);
64 // lineSeries2->add(100, 20);
62 65
63 66 //create chart view
64 67 QChartView* chart = new QChartView;
65 68 chart->setMinimumSize(800,600);
66 // chart->setGeometry(50, 50, 400, 300);
69 // chart->setGeometry(50, 50, 400, 300);
67 70 chart->addSeries(series);
71 chart->addSeries(series2);
72
73 //add new item
74 QPushButton* addButton = new QPushButton("Add new point");
75 connect(addButton, SIGNAL(clicked()), this, SLOT(addNewPoint()));
76
77 QPushButton* removeButton = new QPushButton("Remove point from the end");
78 connect(removeButton, SIGNAL(clicked()), this, SLOT(removePoint()));
79
80 //butttons layout
81 QVBoxLayout* buttonsLayout = new QVBoxLayout;
82 buttonsLayout->addWidget(addButton);
83 buttonsLayout->addWidget(removeButton);
84 buttonsLayout->addStretch();
68 85
69 86 QGridLayout* mainLayout = new QGridLayout;
70 mainLayout->addWidget(chart);
87 mainLayout->addWidget(chart, 1, 0);
88 mainLayout->addLayout(buttonsLayout, 1, 1);
71 89 setLayout(mainLayout);
72 90 }
73 91
92 void SplineWidget::addNewPoint()
93 {
94 if (series->count() > 0)
95 series->add(QPointF(series->x(series->count() - 1) + 50, series->y(series->count() - 1) - 50 + qrand()%100));
96 else
97 series->add(QPointF(50, 50 + qrand()%50));
98 }
99
100 void SplineWidget::removePoint()
101 {
102 if (series->count() > 0)
103 series->remove(QPointF(series->x(series->count() - 1), series->y(series->count() - 1)));
104 }
105
74 106 SplineWidget::~SplineWidget()
75 107 {
76 108
77 109 }
@@ -1,15 +1,25
1 1 #ifndef SPLINEWIDGET_H
2 2 #define SPLINEWIDGET_H
3 3
4 4 #include <QtGui/QWidget>
5 #include "qsplineseries.h"
6
7 QTCOMMERCIALCHART_USE_NAMESPACE
5 8
6 9 class SplineWidget : public QWidget
7 10 {
8 11 Q_OBJECT
9 12
10 13 public:
11 14 SplineWidget(QWidget *parent = 0);
12 15 ~SplineWidget();
16
17 public slots:
18 void addNewPoint();
19 void removePoint();
20
21 private:
22 QSplineSeries* series;
13 23 };
14 24
15 25 #endif // SPLINEWIDGET_H
@@ -1,110 +1,108
1 1 #include "qsplineseries.h"
2 2
3 3 QTCOMMERCIALCHART_BEGIN_NAMESPACE
4 4
5 5 QSplineSeries::QSplineSeries(QObject *parent) :
6 6 QLineSeries(parent)
7 7 {
8 connect(this,SIGNAL(pointAdded(int)), this, SLOT(updateControlPoints()));
9 connect(this,SIGNAL(pointRemoved(int)), this, SLOT(updateControlPoints()));
10 connect(this,SIGNAL(pointReplaced(int)), this, SLOT(updateControlPoints()));
8 11 }
9 12
10 //QSplineSeries& QSplineSeries::operator << (const QPointF &value)
11 //{
12 //// d->m_data.append(value);
13 // m_data.append(value);
14 //// emit changed();
15 // return *this;
16 //}
17
18 //void QSplineSeries::addData(QPointF value)
19 //{
20 // m_data.append(value);
21 //}
22
23 13 void QSplineSeries::calculateControlPoints()
24 14 {
25 15
26 16 // Based on http://www.codeproject.com/Articles/31859/Draw-a-Smooth-Curve-through-a-Set-of-2D-Points-wit
27 17 // CPOL Licence
28 18
29 19 int n = m_x.size() - 1;
30 20 if (n == 1)
31 21 { // Special case: Bezier curve should be a straight line.
32 22 // firstControlPoints = new Point[1];
33 23 // 3P1 = 2P0 + P3
34 24 m_controlPoints.append(QPointF((2 * m_x[0] + m_x[1]) / 3, (2 * m_y[0] + m_y[1]) / 3));
35 25
36 26 // P2 = 2P1 P0
37 27 m_controlPoints.append(QPointF(2 * m_controlPoints[0].x() - m_x[0], 2 * m_controlPoints[0].y() - m_y[0]));
38 28 return;
39 29 }
40 30
41 31 // Calculate first Bezier control points
42 32 // Right hand side vector
43 33 // Set of equations for P0 to Pn points.
44 34 //
45 35 // | 2 1 0 0 ... 0 0 0 ... 0 0 0 | | P1_1 | | P0 + 2 * P1 |
46 36 // | 1 4 1 0 ... 0 0 0 ... 0 0 0 | | P1_2 | | 4 * P1 + 2 * P2 |
47 37 // | 0 1 4 1 ... 0 0 0 ... 0 0 0 | | P1_3 | | 4 * P2 + 2 * P3 |
48 38 // | . . . . . . . . . . . . | | ... | | ... |
49 39 // | 0 0 0 0 ... 1 4 1 ... 0 0 0 | * | P1_i | = | 4 * P(i-1) + 2 * Pi |
50 40 // | . . . . . . . . . . . . | | ... | | ... |
51 41 // | 0 0 0 0 0 0 0 0 ... 1 4 1 | | P1_(n-1)| | 4 * P(n-2) + 2 * P(n-1) |
52 42 // | 0 0 0 0 0 0 0 0 ... 0 2 7 | | P1_n | | 8 * P(n-1) + Pn |
53 43 //
54 44 QList<qreal> rhs;
55 45 rhs.append(m_x[0] + 2 * m_x[1]);
56 46
57 47 // Set right hand side X values
58 48 for (int i = 1; i < n - 1; ++i)
59 49 rhs.append(4 * m_x[i] + 2 * m_x[i + 1]);
60 50
61 51 rhs.append((8 * m_x[n - 1] + m_x[n]) / 2.0);
62 52 // Get first control points X-values
63 53 QList<qreal> x = getFirstControlPoints(rhs);
64 54 rhs[0] = m_y[0] + 2 * m_y[1];
65 55
66 56 // Set right hand side Y values
67 57 for (int i = 1; i < n - 1; ++i)
68 58 rhs[i] = 4 * m_y[i] + 2 * m_y[i + 1];
69 59
70 60 rhs[n - 1] = (8 * m_y[n - 1] + m_y[n]) / 2.0;
71 61 // Get first control points Y-values
72 62 QList<qreal> y = getFirstControlPoints(rhs);
73 63
74 64 // Fill output arrays.
75 // firstControlPoints = new Point[n];
76 // secondControlPoints = new Point[n];
77 65 for (int i = 0; i < n; ++i)
78 66 {
79 67 // First control point
80 68 m_controlPoints.append(QPointF(x[i], y[i]));
81 69 // Second control point
82 70 if (i < n - 1)
83 71 m_controlPoints.append(QPointF(2 * m_x[i + 1] - x[i + 1], 2 * m_y[i + 1] - y[i + 1]));
84 72 else
85 73 m_controlPoints.append(QPointF((m_x[n] + x[n - 1]) / 2, (m_y[n] + y[n - 1]) / 2));
86 74 }
87 75 }
88 76
89 77 QList<qreal> QSplineSeries::getFirstControlPoints(QList<qreal> rhs)
90 78 {
91 79 QList<qreal> x; // Solution vector.
92 80 QList<qreal> tmp; // Temp workspace.
93 81
94 82 qreal b = 2.0;
95 83 x.append(rhs[0] / b);
96 84 tmp.append(0);
97 85 for (int i = 1; i < rhs.size(); i++) // Decomposition and forward substitution.
98 86 {
99 87 tmp.append(1 / b);
100 88 b = (i < rhs.size() - 1 ? 4.0 : 3.5) - tmp[i];
101 89 x.append((rhs[i] - x[i - 1]) / b);
102 90 }
103 91 for (int i = 1; i < rhs.size(); i++)
104 92 x[rhs.size() - i - 1] -= tmp[rhs.size() - i] * x[rhs.size() - i]; // Backsubstitution.
105 93
106 94 return x;
107 95 }
96
97 void QSplineSeries::updateControlPoints()
98 {
99 if(m_x.size() > 1)
100 {
101 m_controlPoints.clear();
102 calculateControlPoints();
103 }
104 }
105
108 106 #include "moc_qsplineseries.cpp"
109 107
110 108 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,41 +1,37
1 1 #ifndef QSPLINESERIES_H
2 2 #define QSPLINESERIES_H
3 3
4 4 #include "qchartglobal.h"
5 5 #include <QtGlobal>
6 6 #include "qlineseries.h"
7 7 #include <QList>
8 8 #include <QPointF>
9 9
10 10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11 11
12 12 class QSplineSeries : public QLineSeries
13 13 {
14 14 Q_OBJECT
15 15 public:
16 16
17 17 QSplineSeries(QObject *parent = 0);
18 18 QSeriesType type() const { return QSeries::SeriesTypeSpline; }
19 // void addData(QPointF value);
20 // QSplineSeries& operator << (const QPointF &value);
21 void calculateControlPoints();
22 QList<qreal> getFirstControlPoints(QList<qreal> rhs);
23 19
24 20 int count() const { return m_x.size(); }
25
26 // QPointF at(int index) const { return m_data[index]; }
27 21 QPointF controlPoint(int index) const { return m_controlPoints[index]; }
28 22
29 signals:
30
31 public slots:
23 private:
24 void calculateControlPoints();
25 QList<qreal> getFirstControlPoints(QList<qreal> rhs);
26
27 private slots:
28 void updateControlPoints();
32 29
33 30 private:
34 // QList<QPointF> m_data;
35 31 QList<QPointF> m_controlPoints;
36 32
37 33 };
38 34
39 35 QTCOMMERCIALCHART_END_NAMESPACE
40 36
41 37 #endif // QSPLINESERIES_H
@@ -1,74 +1,77
1 1 #include "splinepresenter_p.h"
2 2 #include <QPainter>
3 3
4 4 QTCOMMERCIALCHART_BEGIN_NAMESPACE
5 5
6 6 SplinePresenter::SplinePresenter(QSplineSeries* series, QGraphicsObject *parent) :
7 7 LineChartItem(0, series, parent)//,m_boundingRect()
8 8 {
9 //
9 //
10 10 }
11 11
12 12
13 13
14 14 QPointF SplinePresenter::calculateGeometryControlPoint(int index) const
15 15 {
16 16 QSplineSeries* splineSeries = qobject_cast<QSplineSeries*>(m_series);
17 17 const qreal deltaX = m_size.width()/m_domain.spanX();
18 18 const qreal deltaY = m_size.height()/m_domain.spanY();
19 19 qreal x = (splineSeries->controlPoint(index).x() - m_domain.m_minX)* deltaX;
20 20 qreal y = (splineSeries->controlPoint(index).y() - m_domain.m_minY)*-deltaY + m_size.height();
21 21 return QPointF(x,y);
22 22 }
23 23
24 24 void SplinePresenter::applyGeometry(QVector<QPointF>& points)
25 25 {
26 26 if(points.size()==0) return;
27 27
28 28 QPainterPath splinePath;
29 29 const QPointF& point = points.at(0);
30 30 splinePath.moveTo(point);
31 31
32 32 QSplineSeries* splineSeries = qobject_cast<QSplineSeries*>(m_series);
33 33 for (int i = 0; i < splineSeries->count() - 1; i++)
34 34 {
35 35 const QPointF& point = points.at(i + 1);
36 36 splinePath.cubicTo(calculateGeometryControlPoint(2 * i), calculateGeometryControlPoint(2 * i + 1), point);
37 37 }
38 38
39 39
40 40
41 41 prepareGeometryChange();
42 42 m_path = splinePath;
43 43 m_rect = splinePath.boundingRect();
44 44 }
45 45
46 46 void SplinePresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
47 47 {
48 48 Q_UNUSED(widget);
49 49 Q_UNUSED(option);
50 50 painter->save();
51 51 painter->setPen(m_pen);
52 52 painter->setClipRect(m_clipRect);
53 53 painter->drawPath(m_path);
54 54
55 55 QSplineSeries* splineSeries = qobject_cast<QSplineSeries*>(m_series);
56 56 for (int i = 0; i < splineSeries->count() - 1; i++)
57 57 {
58 58 painter->setPen(Qt::red);
59 59 painter->drawEllipse(m_points[i], 4, 4);
60 60
61 61 painter->setPen(Qt::blue);
62 62 // painter->drawLine(m_series->at(i), m_series->controlPoint(2 * i));
63 63 // painter->drawLine(m_series->at(i + 1), m_series->controlPoint(2 * i + 1));
64 painter->drawEllipse(calculateGeometryControlPoint(2 * i), 4, 4);
65 painter->drawEllipse(calculateGeometryControlPoint(2 * i + 1), 4, 4);
64 // painter->drawEllipse(calculateGeometryControlPoint(2 * i), 4, 4);
65 // painter->drawEllipse(calculateGeometryControlPoint(2 * i + 1), 4, 4);
66 }
67 if (m_points.count() > 0)
68 {
69 painter->setPen(Qt::red);
70 painter->drawEllipse(m_points[m_points.count() - 1], 4, 4);
66 71 }
67 painter->setPen(Qt::red);
68 painter->drawEllipse(m_points[m_points.count() - 1], 4, 4);
69 72 painter->restore();
70 73 }
71 74
72 75 #include "moc_splinepresenter_p.cpp"
73 76
74 77 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now