##// END OF EJS Templates
Spline working somewhat
Marek Rosa -
r401:e71d8c300b9c
parent child
Show More
@@ -0,0 +1,11
1 #include <QtGui/QApplication>
2 #include "splinewidget.h"
3
4 int main(int argc, char *argv[])
5 {
6 QApplication a(argc, argv);
7 SplineWidget w;
8 w.show();
9
10 return a.exec();
11 }
@@ -0,0 +1,20
1 #-------------------------------------------------
2 #
3 # Project created by QtCreator 2012-02-29T12:37:46
4 #
5 #-------------------------------------------------
6
7 !include( ../example.pri ) {
8 error( "Couldn't find the example.pri file!" )
9 }
10
11 QT += core gui
12
13 TARGET = splinechart
14 TEMPLATE = app
15
16
17 SOURCES += main.cpp\
18 splinewidget.cpp
19
20 HEADERS += splinewidget.h
@@ -0,0 +1,53
1 #include "splinewidget.h"
2 #include "qchartview.h"
3 #include "qsplineseries.h"
4 #include "qlinechartseries.h"
5 #include <QGridLayout>
6
7 QTCOMMERCIALCHART_USE_NAMESPACE
8
9 SplineWidget::SplineWidget(QWidget *parent)
10 : QWidget(parent)
11 {
12 //create QSplineSeries
13 QSplineSeries* series = new QSplineSeries(this);
14 series->addData(QPointF(150, 100));
15 series->addData(QPointF(200, 180));
16 series->addData(QPointF(240, 130));
17 series->addData(QPointF(270, 120));
18 series->addData(QPointF(310, 120));
19 series->addData(QPointF(420, 160));
20 series->addData(QPointF(535, 250));
21
22 series->calculateControlPoints();
23
24 QLineChartSeries* lineSeries = new QLineChartSeries;
25 for (int i = 0; i < series->count() - 1; i++)
26 {
27 lineSeries->add(series->at(i).x(), series->at(i).y());
28 lineSeries->add(series->controlPoint(2*i).x(), series->controlPoint(2*i).y());
29 lineSeries->add(series->controlPoint(2*i + 1).x(), series->controlPoint(2*i + 1).y());
30 }
31
32 // QLineChartSeries* lineSeries2 = new QLineChartSeries;
33 // lineSeries2->add(10, 50);
34 // lineSeries2->add(30, 15);
35 // lineSeries2->add(60, 40);
36 // lineSeries2->add(90, 70);
37 // lineSeries2->add(100, 20);
38
39 //create chart view
40 QChartView* chart = new QChartView;
41 chart->setMinimumSize(800,600);
42 // chart->setGeometry(50, 50, 400, 300);
43 chart->addSeries(series);
44
45 QGridLayout* mainLayout = new QGridLayout;
46 mainLayout->addWidget(chart);
47 setLayout(mainLayout);
48 }
49
50 SplineWidget::~SplineWidget()
51 {
52
53 }
@@ -0,0 +1,15
1 #ifndef SPLINEWIDGET_H
2 #define SPLINEWIDGET_H
3
4 #include <QtGui/QWidget>
5
6 class SplineWidget : public QWidget
7 {
8 Q_OBJECT
9
10 public:
11 SplineWidget(QWidget *parent = 0);
12 ~SplineWidget();
13 };
14
15 #endif // SPLINEWIDGET_H
@@ -11,4 +11,5 SUBDIRS += linechart \
11 11 axischart \
12 12 multichart \
13 13 gdpbarchart \
14 presenterchart
14 presenterchart \
15 splinechart
@@ -7,6 +7,7
7 7 #include "qpercentbarchartseries.h"
8 8 #include "qpieseries.h"
9 9 #include "qscatterseries.h"
10 #include "qsplineseries.h"
10 11
11 12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
12 13
@@ -123,6 +124,21 void ChartDataSet::addSeries(QChartSeries* series, QChartAxis *axisY)
123 124 break;
124 125 }
125 126
127 case QChartSeries::SeriesTypeSpline: {
128 QSplineSeries* splineSeries = static_cast<QSplineSeries*>(series);
129
130 for (int i = 0; i < splineSeries->count(); i++)
131 {
132 qreal x = splineSeries->at(i).x();
133 qreal y = splineSeries->at(i).y();
134 domain.m_minX = qMin(domain.m_minX,x);
135 domain.m_minY = qMin(domain.m_minY,y);
136 domain.m_maxX = qMax(domain.m_maxX,x);
137 domain.m_maxY = qMax(domain.m_maxY,y);
138 }
139 break;
140 }
141
126 142 default: {
127 143 qDebug()<<__FUNCTION__<<"type" << series->type()<<"not supported";
128 144 return;
@@ -60,7 +60,7 QRectF ChartPresenter::geometry() const
60 60 void ChartPresenter::handleGeometryChanged()
61 61 {
62 62 m_rect = QRectF(QPoint(0,0),m_chart->size());
63 m_rect.adjust(m_marginSize,m_marginSize, -m_marginSize, -m_marginSize);
63 // m_rect.adjust(m_marginSize,m_marginSize, -m_marginSize, -m_marginSize);
64 64 Q_ASSERT(m_rect.isValid());
65 65 emit geometryChanged(m_rect);
66 66 }
@@ -166,7 +166,10 void ChartPresenter::handleSeriesAdded(QChartSeries* series)
166 166 }
167 167 case QChartSeries::SeriesTypeSpline: {
168 168 QSplineSeries* splineSeries = qobject_cast<QSplineSeries*>(series);
169 SplinePresenter* splinePresenter = new SplinePresenter
169 SplinePresenter* splinePresenter = new SplinePresenter(splineSeries, m_chart);
170 QObject::connect(this, SIGNAL(geometryChanged(const QRectF&)), splinePresenter, SLOT(handleGeometryChanged(const QRectF&)));
171 m_chartTheme->decorate(splinePresenter, splineSeries, m_chartItems.count());
172 m_chartItems.insert(splineSeries, splinePresenter);
170 173 break;
171 174 }
172 175 default: {
@@ -12,6 +12,7
12 12 #include "qscatterseries.h"
13 13 #include "qpieseries.h"
14 14 #include "qpieslice.h"
15 #include "qsplineseries.h"
15 16
16 17 //items
17 18 #include "axisitem_p.h"
@@ -21,6 +22,7
21 22 #include "percentbarpresenter.h"
22 23 #include "scatterpresenter_p.h"
23 24 #include "piepresenter.h"
25 #include "splinepresenter_p.h"
24 26
25 27 //themes
26 28 #include "chartthemevanilla_p.h"
@@ -226,4 +228,21 void ChartTheme::decorate(QChartAxis* axis,AxisItem* item)
226 228 axis->setShadesOpacity(0.5);
227 229 }
228 230
231 void ChartTheme::decorate(SplinePresenter* presenter, QSplineSeries* series, int count)
232 {
233 Q_ASSERT(presenter);
234 Q_ASSERT(series);
235
236 // QColor color = m_seriesColor.at(count % m_seriesColor.size());
237 // TODO: define alpha in the theme? or in the series?
238 //color.setAlpha(120);
239
240 // QBrush brush(color, Qt::SolidPattern);
241 // presenter->m_markerBrush = brush;
242
243 // QPen pen(brush, 3);
244 // pen.setColor(color);
245 // presenter->m_markerPen = pen;
246 }
247
229 248 QTCOMMERCIALCHART_END_NAMESPACE
@@ -21,6 +21,8 class QScatterSeries;
21 21 class ScatterPresenter;
22 22 class PiePresenter;
23 23 class QPieSeries;
24 class SplinePresenter;
25 class QSplineSeries;
24 26
25 27 class ChartTheme
26 28 {
@@ -38,6 +40,7 public:
38 40 void decorate(ScatterPresenter* presenter, QScatterSeries* series, int count);
39 41 void decorate(PiePresenter* item, QPieSeries* series, int count);
40 42 void decorate(QChartAxis* axis,AxisItem* item);
43 void decorate(SplinePresenter* presenter, QSplineSeries* series, int count);
41 44
42 45 protected:
43 46 QChart::ChartTheme m_id;
@@ -1,100 +1,110
1 1 #include "qsplineseries.h"
2 2
3 QTCOMMERCIALCHART_BEGIN_NAMESPACE
4
3 5 QSplineSeries::QSplineSeries(QObject *parent) :
4 QObject(parent)
6 QChartSeries(parent)
5 7 {
6 8 }
7 9
8 10 QSplineSeries& QSplineSeries::operator << (const QPointF &value)
9 11 {
10 d->m_data.append(value);
11 emit changed();
12 // d->m_data.append(value);
13 m_data.append(value);
14 // emit changed();
12 15 return *this;
13 16 }
14 17
15 void QSplineSeries::GetCurveControlPoints()
18 void QSplineSeries::addData(QPointF value)
16 19 {
20 m_data.append(value);
21 }
22
23 void QSplineSeries::calculateControlPoints()
24 {
25
26 // Based on http://www.codeproject.com/Articles/31859/Draw-a-Smooth-Curve-through-a-Set-of-2D-Points-wit
27 // CPOL Licence
28
17 29 int n = m_data.size() - 1;
18 if (n < 1)
19 throw new ArgumentException
20 ("At least two knot points required", "knots");
21 30 if (n == 1)
22 31 { // Special case: Bezier curve should be a straight line.
23 firstControlPoints = new Point[1];
32 // firstControlPoints = new Point[1];
24 33 // 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;
34 m_controlPoints.append(QPointF((2 * m_data[0].x() + m_data[1].x()) / 3, (2 * m_data[0].y() + m_data[1].y()) / 3));
27 35
28 secondControlPoints = new Point[1];
29 36 // 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;
37 m_controlPoints.append(QPointF(2 * m_controlPoints[0].x() - m_data[0].x(), 2 * m_controlPoints[0].y() - m_data[0].y()));
34 38 return;
35 39 }
36 40
37 41 // Calculate first Bezier control points
38 42 // Right hand side vector
39 double[] rhs = new double[n];
43 // Set of equations for P0 to Pn points.
44 //
45 // | 2 1 0 0 ... 0 0 0 ... 0 0 0 | | P1_1 | | P0 + 2 * P1 |
46 // | 1 4 1 0 ... 0 0 0 ... 0 0 0 | | P1_2 | | 4 * P1 + 2 * P2 |
47 // | 0 1 4 1 ... 0 0 0 ... 0 0 0 | | P1_3 | | 4 * P2 + 2 * P3 |
48 // | . . . . . . . . . . . . | | ... | | ... |
49 // | 0 0 0 0 ... 1 4 1 ... 0 0 0 | * | P1_i | = | 4 * P(i-1) + 2 * Pi |
50 // | . . . . . . . . . . . . | | ... | | ... |
51 // | 0 0 0 0 0 0 0 0 ... 1 4 1 | | P1_(n-1)| | 4 * P(n-2) + 2 * P(n-1) |
52 // | 0 0 0 0 0 0 0 0 ... 0 2 7 | | P1_n | | 8 * P(n-1) + Pn |
53 //
54 QList<qreal> rhs;
55 rhs.append(m_data[0].x() + 2 * m_data[1].x());
40 56
41 57 // 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;
58 for (int i = 1; i < m_data.size() - 1; ++i)
59 rhs.append(4 * m_data[i].x() + 2 * m_data[i + 1].x());
60
61 rhs.append((8 * m_data[n - 1].x() + m_data[n].x()) / 2.0);
46 62 // Get first control points X-values
47 double[] x = GetFirstControlPoints(rhs);
63 QList<qreal> x = getFirstControlPoints(rhs);
64 rhs[0] = m_data[0].y() + 2 * m_data[1].y();
48 65
49 66 // 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;
67 for (int i = 1; i < m_data.size() - 1; ++i)
68 rhs[i] = 4 * m_data[i].y() + 2 * m_data[i + 1].y();
69
70 rhs[n - 1] = (8 * m_data[n - 1].y() + m_data[n].y()) / 2.0;
54 71 // Get first control points Y-values
55 double[] y = GetFirstControlPoints(rhs);
72 QList<qreal> y = getFirstControlPoints(rhs);
56 73
57 74 // Fill output arrays.
58 firstControlPoints = new Point[n];
59 secondControlPoints = new Point[n];
60 for (int i = 0; i < n; ++i)
75 // firstControlPoints = new Point[n];
76 // secondControlPoints = new Point[n];
77 for (int i = 0; i < m_data.size(); ++i)
61 78 {
62 79 // First control point
63 firstControlPoints[i] = new Point(x[i], y[i]);
80 m_controlPoints.append(QPointF(x[i], y[i]));
64 81 // Second control point
65 82 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]);
83 m_controlPoints.append(QPointF(2 * m_data[i + 1].x() - x[i + 1], 2 * m_data[i + 1].y() - y[i + 1]));
69 84 else
70 secondControlPoints[i] = new Point((knots
71 [n].X + x[n - 1]) / 2,
72 (knots[n].Y + y[n - 1]) / 2);
85 m_controlPoints.append(QPointF((m_data[n].x() + x[n - 1]) / 2, (m_data[n].y() + y[n - 1]) / 2));
73 86 }
74 87 }
75 88
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)
89 QList<qreal> QSplineSeries::getFirstControlPoints(QList<qreal> rhs)
83 90 {
84 int n = rhs.Length;
85 double[] x = new double[n]; // Solution vector.
86 double[] tmp = new double[n]; // Temp workspace.
91 QList<qreal> x; // Solution vector.
92 QList<qreal> tmp; // Temp workspace.
87 93
88 double b = 2.0;
89 x[0] = rhs[0] / b;
90 for (int i = 1; i < n; i++) // Decomposition and forward substitution.
94 qreal b = 2.0;
95 x.append(rhs[0] / b);
96 tmp.append(0);
97 for (int i = 1; i < rhs.size(); i++) // Decomposition and forward substitution.
91 98 {
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;
99 tmp.append(1 / b);
100 b = (i < rhs.size() - 1 ? 4.0 : 3.5) - tmp[i];
101 x.append((rhs[i] - x[i - 1]) / b);
95 102 }
96 for (int i = 1; i < n; i++)
97 x[n - i - 1] -= tmp[n - i] * x[n - i]; // Backsubstitution.
103 for (int i = 1; i < rhs.size(); i++)
104 x[rhs.size() - i - 1] -= tmp[rhs.size() - i] * x[rhs.size() - i]; // Backsubstitution.
98 105
99 106 return x;
100 107 }
108 #include "moc_qsplineseries.cpp"
109
110 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,7 +1,11
1 1 #ifndef QSPLINESERIES_H
2 2 #define QSPLINESERIES_H
3 3
4 #include "qchartglobal.h"
5 #include <QtGlobal>
4 6 #include "qchartseries.h"
7 #include <QList>
8 #include <QPointF>
5 9
6 10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
7 11
@@ -15,6 +19,12 class QSplineSeries : public QChartSeries
15 19 void addData(QPointF value);
16 20 QSplineSeries& operator << (const QPointF &value);
17 21 void calculateControlPoints();
22 QList<qreal> getFirstControlPoints(QList<qreal> rhs);
23
24 int count() const { return m_data.size(); }
25
26 QPointF at(int index) const { return m_data[index]; }
27 QPointF controlPoint(int index) const { return m_controlPoints[index]; }
18 28
19 29 signals:
20 30
@@ -3,13 +3,10 DEPENDPATH += $$PWD
3 3
4 4 SOURCES += \
5 5 $$PWD/qsplineseries.cpp \
6 splinechart/splinepresenter.cpp
6 $$PWD/splinepresenter.cpp
7 7
8 PRIVATE_HEADERS +=
8 PRIVATE_HEADERS += \
9 $$PWD/splinepresenter_p.h
9 10
10 11 PUBLIC_HEADERS += \
11 12 $$PWD/qsplineseries.h
12
13 HEADERS += \
14 splinechart/qsplineseries.h \
15 splinechart/splinepresenter_p.h
@@ -1,16 +1,54
1 1 #include "splinepresenter_p.h"
2 #include <QPainter>
2 3
3 SplinePresenter::SplinePresenter(QObject *parent) :
4 QObject(parent)
4 QTCOMMERCIALCHART_BEGIN_NAMESPACE
5
6 SplinePresenter::SplinePresenter(QSplineSeries* series, QGraphicsObject *parent) :
7 ChartItem(parent),m_series(series),m_boundingRect()
5 8 {
9 if (parent)
10 m_boundingRect = parent->boundingRect();
11 else
12 m_boundingRect = QRectF(10,50, 250, 250);
6 13 }
7 14
8 15 void SplinePresenter::handleGeometryChanged(const QRectF&)
9 16 {
10 //
17 update();
11 18 }
12 19
13 20 void SplinePresenter::handleDomainChanged(const Domain& domain)
14 21 {
15 22 //
16 23 }
24
25 void SplinePresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
26 {
27 Q_UNUSED(widget);
28 Q_UNUSED(option);
29 painter->save();
30
31 painter->setPen(Qt::SolidLine);
32
33 QPainterPath splinePath;
34 splinePath.moveTo(m_series->at(0));
35 for (int i = 0; i < m_series->count() - 1; i++)
36 {
37 painter->setPen(Qt::red);
38 splinePath.cubicTo(m_series->controlPoint(2 * i), m_series->controlPoint(2 * i + 1), m_series->at(i + 1));
39 painter->drawEllipse(m_series->at(i), 4, 4);
40
41 painter->setPen(Qt::blue);
42 painter->drawLine(m_series->at(i), m_series->controlPoint(2 * i));
43 painter->drawLine(m_series->at(i + 1), m_series->controlPoint(2 * i + 1));
44 painter->drawEllipse(m_series->controlPoint(2 * i), 4, 4);
45 painter->drawEllipse(m_series->controlPoint(2 * i + 1), 4, 4);
46 }
47 painter->setPen(Qt::red);
48 painter->drawPath(splinePath);
49 painter->restore();
50 }
51
52 #include "moc_splinepresenter_p.cpp"
53
54 QTCOMMERCIALCHART_END_NAMESPACE
@@ -3,6 +3,7
3 3
4 4 #include "chartitem_p.h"
5 5 #include <QObject>
6 #include "qsplineseries.h"
6 7
7 8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8 9
@@ -10,14 +11,20 class SplinePresenter : public QObject, public ChartItem
10 11 {
11 12 Q_OBJECT
12 13 public:
13 SplinePresenter(QObject *parent = 0);
14 SplinePresenter(QSplineSeries* series, QGraphicsObject *parent = 0);
14 15
15 void handleGeometryChanged(const QRectF&);
16 void handleDomainChanged(const Domain& domain);
16 QRectF boundingRect() const { return m_boundingRect; }
17 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
17 18
18 19 signals:
19 20
20 21 public slots:
22 void handleDomainChanged(const Domain& domain);
23 void handleGeometryChanged(const QRectF& rect);
24
25 private:
26 QSplineSeries* m_series;
27 QRectF m_boundingRect;
21 28
22 29 };
23 30
@@ -1,7 +1,7
1 1 #include "dataseriedialog.h"
2 2 #include <QDialogButtonBox>
3 3 #include <QGridLayout>
4 #include <QCheckbox>
4 #include <QCheckBox>
5 5 #include <QPushButton>
6 6 #include <QGroupBox>
7 7 #include <QRadioButton>
General Comments 0
You need to be logged in to leave comments. Login now