From d444309c9f1bbab9c01853e2ce110ba47bf38fa1 2012-04-18 14:37:18 From: Michal Klocek Date: 2012-04-18 14:37:18 Subject: [PATCH] Fixes and improvments to series API * removes pos index * adds unified append, replace , remove * optimizes spline drawing to use QVector --- diff --git a/demos/chartthemes/themewidget.cpp b/demos/chartthemes/themewidget.cpp index 6bdeda8..eb6d557 100644 --- a/demos/chartthemes/themewidget.cpp +++ b/demos/chartthemes/themewidget.cpp @@ -189,9 +189,10 @@ QChart* ThemeWidget::createAreaChart() const QLineSeries *upperSeries = new QLineSeries(chart); for (int j(0); j < m_dataTable[i].count(); j++) { Data data = m_dataTable[i].at(j); - if (lowerSeries) - upperSeries->append(QPointF(j, lowerSeries->y(i) + data.first.y())); - else + if (lowerSeries){ + const QList& points = lowerSeries->points(); + upperSeries->append(QPointF(j, points[i].y() + data.first.y())); + }else upperSeries->append(QPointF(j, data.first.y())); } QAreaSeries *area = new QAreaSeries(upperSeries, lowerSeries); diff --git a/demos/dynamicspline/chart.cpp b/demos/dynamicspline/chart.cpp index 2464ad4..38a5d51 100644 --- a/demos/dynamicspline/chart.cpp +++ b/demos/dynamicspline/chart.cpp @@ -57,9 +57,10 @@ Chart::~Chart() void Chart::handleTimeout() { m_x += m_step; + qreal y = m_y; m_y = qrand() % 5 - 2.5; m_series->append(m_x, m_y); if (m_x >= 10) - m_series->remove(m_x - 10); + m_series->remove(m_x - 10,y); scrollRight(); } diff --git a/src/areachart/qareaseries.cpp b/src/areachart/qareaseries.cpp index eeedd52..4e04f59 100644 --- a/src/areachart/qareaseries.cpp +++ b/src/areachart/qareaseries.cpp @@ -231,20 +231,25 @@ void QAreaSeriesPrivate::scaleDomain(Domain& domain) QLineSeries* upperSeries = q->upperSeries(); QLineSeries* lowerSeries = q->lowerSeries(); - for (int i = 0; i < upperSeries->count(); i++) + const QList& points = upperSeries->points(); + + for (int i = 0; i < points.count(); i++) { - qreal x = upperSeries->x(i); - qreal y = upperSeries->y(i); + qreal x = points[i].x(); + qreal y = points[i].y(); minX = qMin(minX, x); minY = qMin(minY, y); maxX = qMax(maxX, x); maxY = qMax(maxY, y); } if(lowerSeries) { - for (int i = 0; i < lowerSeries->count(); i++) + + const QList& points = upperSeries->points(); + + for (int i = 0; i < points.count(); i++) { - qreal x = lowerSeries->x(i); - qreal y = lowerSeries->y(i); + qreal x = points[i].x(); + qreal y = points[i].y(); minX = qMin(minX, x); minY = qMin(minY, y); maxX = qMax(maxX, x); diff --git a/src/scatterseries/scatterchartitem.cpp b/src/scatterseries/scatterchartitem.cpp index 90dc9d0..b275d23 100644 --- a/src/scatterseries/scatterchartitem.cpp +++ b/src/scatterseries/scatterchartitem.cpp @@ -98,7 +98,7 @@ void ScatterChartItem::deletePoints(int count) void ScatterChartItem::markerSelected(Marker *marker) { - emit XYChartItem::clicked(QPointF(m_series->x(marker->index()), m_series->y(marker->index()))); + emit XYChartItem::clicked(marker->point()); } void ScatterChartItem::setLayout(QVector& points) @@ -126,7 +126,7 @@ void ScatterChartItem::setLayout(QVector& points) Marker* item = static_cast(items.at(i)); const QPointF& point = points.at(i); const QRectF& rect = item->boundingRect(); - item->setIndex(i); + item->setPoint(point); item->setPos(point.x()-rect.width()/2,point.y()-rect.height()/2); if(!clipRect().contains(point)) { item->setVisible(false); diff --git a/src/scatterseries/scatterchartitem_p.h b/src/scatterseries/scatterchartitem_p.h index b1b95b5..a6a26fe 100644 --- a/src/scatterseries/scatterchartitem_p.h +++ b/src/scatterseries/scatterchartitem_p.h @@ -72,7 +72,7 @@ class Marker: public QAbstractGraphicsShapeItem public: - Marker(QAbstractGraphicsShapeItem *item , ScatterChartItem *parent) : QAbstractGraphicsShapeItem(0) ,m_item(item), m_parent(parent), m_index(-1) + Marker(QAbstractGraphicsShapeItem *item , ScatterChartItem *parent) : QAbstractGraphicsShapeItem(0) ,m_item(item), m_parent(parent) { } @@ -81,14 +81,14 @@ public: delete m_item; } - void setIndex(int index) + void setPoint(const QPointF& point) { - m_index=index; + m_point=point; } - int index() const + QPointF point() const { - return m_index; + return m_point; } QPainterPath shape() const @@ -132,7 +132,7 @@ protected: private: QAbstractGraphicsShapeItem* m_item; ScatterChartItem* m_parent; - int m_index; + QPointF m_point; }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/splinechart/qsplineseries.cpp b/src/splinechart/qsplineseries.cpp index 9c00915..671c265 100644 --- a/src/splinechart/qsplineseries.cpp +++ b/src/splinechart/qsplineseries.cpp @@ -105,15 +105,15 @@ QSplineSeriesPrivate::QSplineSeriesPrivate(QSplineSeries* q):QLineSeriesPrivate( void QSplineSeriesPrivate::calculateControlPoints() { - Q_Q(QSplineSeries); - - int n = q->count() - 1; + int n = m_points.count() - 1; if (n == 1) { //for n==1 - m_controlPoints.append(QPointF((2 * q->x(0) + q->x(1)) / 3, (2 * q->y(0) + q->y(1)) / 3)); - m_controlPoints.append(QPointF(2 * m_controlPoints[0].x() - q->x(0), 2 * m_controlPoints[0].y() - q->y(0))); + m_controlPoints[0].setX((2 * m_points[0].x() + m_points[1].x()) / 3); + m_controlPoints[0].setY((2 * m_points[0].y() + m_points[1].y()) / 3); + m_controlPoints[1].setX(2 * m_controlPoints[0].x() - m_points[0].x()); + m_controlPoints[1].setY(2 * m_controlPoints[0].y() - m_points[0].y()); return; } @@ -130,53 +130,68 @@ void QSplineSeriesPrivate::calculateControlPoints() // | 0 0 0 0 0 0 0 0 ... 1 4 1 | | P1_(n-1)| | 4 * P(n-2) + 2 * P(n-1) | // | 0 0 0 0 0 0 0 0 ... 0 2 7 | | P1_n | | 8 * P(n-1) + Pn | // - QList points; + QVector vector; + vector.resize(n); - points.append(q->x(0) + 2 * q->x(1)); + vector[0] = m_points[0].x() + 2 * m_points[1].x(); - for (int i = 1; i < n - 1; ++i) - points.append(4 * q->x(i) + 2 * q->x(i + 1)); + for (int i = 1; i < n - 1; ++i){ + vector[i] = 4 * m_points[i].x() + 2 * m_points[i + 1].x(); + } - points.append((8 * q->x(n - 1) + q->x(n)) / 2.0); + vector[n - 1] = (8 * m_points[n-1].x() + m_points[n].x()) / 2.0; - QList xControl = firstControlPoints(points); - points[0] = q->y(0) + 2 * q->y(1); + QVector xControl = firstControlPoints(vector); + + vector[0] = m_points[0].y() + 2 * m_points[1].y(); for (int i = 1; i < n - 1; ++i) { - points[i] = 4 * q->y(i) + 2 * q->y(i + 1); + vector[i] = 4 * m_points[i].y() + 2 * m_points[i + 1].y(); } - points[n - 1] = (8 * q->y(n - 1) + q->y(n)) / 2.0; + vector[n - 1] = (8 * m_points[n-1].y() + m_points[n].y()) / 2.0; + + QVector yControl = firstControlPoints(vector); - QList yControl = firstControlPoints(points); + for (int i = 0,j =0; i < n; ++i, ++j) { - for (int i = 0; i < n; ++i) { + m_controlPoints[j].setX(xControl[i]); + m_controlPoints[j].setY(yControl[i]); - m_controlPoints.append(QPointF(xControl[i], yControl[i])); + j++; - if (i < n - 1) - m_controlPoints.append(QPointF(2 * q->x(i + 1) - xControl[i + 1], 2 * q->y(i + 1) - yControl[i + 1])); - else - m_controlPoints.append(QPointF((q->x(n) + xControl[n - 1]) / 2, (q->y(n) + yControl[n - 1]) / 2)); + if (i < n - 1){ + m_controlPoints[j].setX(2 * m_points[i+1].x() - xControl[i + 1]); + m_controlPoints[j].setY(2 * m_points[i+1].y() - yControl[i + 1]); + }else{ + m_controlPoints[j].setX((m_points[n].x() + xControl[n - 1]) / 2); + m_controlPoints[j].setY((m_points[n].y() + yControl[n - 1]) / 2); + } } } -QList QSplineSeriesPrivate::firstControlPoints(QList list) +QVector QSplineSeriesPrivate::firstControlPoints(const QVector& vector) { - QList result; - QList temp; + QVector result; + + int count = vector.count(); + result.resize(count); + result[0] = vector[0] / 2.0; + + QVector temp; + temp.resize(count); + temp[0] = 0; qreal b = 2.0; - result.append(list[0] / b); - temp.append(0); - for (int i = 1; i < list.size(); i++) { - temp.append(1 / b); - b = (i < list.size() - 1 ? 4.0 : 3.5) - temp[i]; - result.append((list[i] - result[i - 1]) / b); + + for (int i = 1; i < count; i++) { + temp[i] = 1 / b; + b = (i < count - 1 ? 4.0 : 3.5) - temp[i]; + result[i]=(vector[i] - result[i - 1]) / b; } - for (int i = 1; i < list.size(); i++) - result[list.size() - i - 1] -= temp[list.size() - i] * result[list.size() - i]; + for (int i = 1; i < count; i++) + result[count - i - 1] -= temp[count - i] * result[count - i]; return result; } @@ -186,9 +201,8 @@ QList QSplineSeriesPrivate::firstControlPoints(QList list) */ void QSplineSeriesPrivate::updateControlPoints() { - Q_Q(QSplineSeries); - if (q->count() > 1) { - m_controlPoints.clear(); + if (m_points.count() > 1) { + m_controlPoints.resize(2*m_points.count()-2); calculateControlPoints(); } } diff --git a/src/splinechart/qsplineseries_p.h b/src/splinechart/qsplineseries_p.h index 4f38eb7..e8bbc16 100644 --- a/src/splinechart/qsplineseries_p.h +++ b/src/splinechart/qsplineseries_p.h @@ -41,13 +41,16 @@ class QSplineSeriesPrivate: public QLineSeriesPrivate public: Chart* createGraphics(ChartPresenter* presenter); QSplineSeriesPrivate(QSplineSeries* q); - void calculateControlPoints(); - QList firstControlPoints(QList rhs); public Q_SLOTS: void updateControlPoints(); + +private: + void calculateControlPoints(); + QVector firstControlPoints(const QVector& vector); + public: - QList m_controlPoints; + QVector m_controlPoints; private: Q_DECLARE_PUBLIC(QSplineSeries) }; diff --git a/src/xychart/qxyseries.cpp b/src/xychart/qxyseries.cpp index 75f04b6..b329b1a 100644 --- a/src/xychart/qxyseries.cpp +++ b/src/xychart/qxyseries.cpp @@ -98,11 +98,7 @@ QXYSeries::~QXYSeries() */ void QXYSeries::append(qreal x,qreal y) { - Q_D(QXYSeries); - Q_ASSERT(d->m_x.size() == d->m_y.size()); - d->m_x<m_y<pointAdded(d->m_x.size()-1); + append(QPointF(x,y)); } /*! @@ -111,55 +107,35 @@ void QXYSeries::append(qreal x,qreal y) */ void QXYSeries::append(const QPointF &point) { - append(point.x(),point.y()); + Q_D(QXYSeries); + d->m_points<pointAdded(d->m_points.count()-1); } /*! This is an overloaded function. Adds list of data \a points to the series. Points are connected with lines on the chart. */ -void QXYSeries::append(const QList points) +void QXYSeries::append(const QList &points) { foreach(const QPointF& point , points) { - append(point.x(),point.y()); + append(point); } } -/*! - Modifies \a y value for given \a x a value. -*/ -void QXYSeries::replace(qreal x,qreal y) -{ - Q_D(QXYSeries); - int index = d->m_x.indexOf(x); - d->m_x[index] = x; - d->m_y[index] = y; - emit d->pointReplaced(index); -} -/*! - This is an overloaded function. - Replaces current y value of for given \a point x value with \a point y value. -*/ -void QXYSeries::replace(const QPointF &point) +void QXYSeries::replace(qreal oldX,qreal oldY,qreal newX,qreal newY) { - replace(point.x(),point.y()); + replace(QPointF(oldX,oldY),QPointF(newX,newY)); } -/*! - Removes first \a x value and related y value. -*/ -void QXYSeries::remove(qreal x) +void QXYSeries::replace(const QPointF &oldPoint,const QPointF &newPoint) { Q_D(QXYSeries); - int index = d->m_x.indexOf(x); - - if (index == -1) return; - - d->m_x.remove(index); - d->m_y.remove(index); - - emit d->pointRemoved(index); + int index = d->m_points.indexOf(oldPoint); + if(index==1) return; + d->m_points[index] = newPoint; + emit d->pointReplaced(index); } /*! @@ -167,17 +143,7 @@ void QXYSeries::remove(qreal x) */ void QXYSeries::remove(qreal x,qreal y) { - Q_D(QXYSeries); - int index =-1; - do { - index = d->m_x.indexOf(x,index+1); - } while (index !=-1 && d->m_y.at(index)!=y); - - if (index==-1) return; - - d->m_x.remove(index); - d->m_y.remove(index); - emit d->pointRemoved(index); + remove(QPointF(x,y)); } /*! @@ -185,7 +151,11 @@ void QXYSeries::remove(qreal x,qreal y) */ void QXYSeries::remove(const QPointF &point) { - remove(point.x(),point.y()); + Q_D(QXYSeries); + int index = d->m_points.indexOf(point); + if(index==1) return; + d->m_points.remove(index); + emit d->pointRemoved(index); } /*! @@ -194,45 +164,41 @@ void QXYSeries::remove(const QPointF &point) void QXYSeries::removeAll() { Q_D(QXYSeries); - d->m_x.clear(); - d->m_y.clear(); -} - -/*! - \internal \a pos -*/ -qreal QXYSeries::x(int pos) const -{ - Q_D(const QXYSeries); - if (d->m_model) { - if (d->m_mapOrientation == Qt::Vertical) - // consecutive data is read from model's column - return d->m_model->data(d->m_model->index(pos + d->m_mapFirst, d->m_mapX), Qt::DisplayRole).toDouble(); - else - // consecutive data is read from model's row - return d->m_model->data(d->m_model->index(d->m_mapX, pos + d->m_mapFirst), Qt::DisplayRole).toDouble(); - } else { - // model is not specified, return the data from series' internal data store - return d->m_x.at(pos); + foreach(const QPointF& point, d->m_points) { + remove(point); } } /*! \internal \a pos */ -qreal QXYSeries::y(int pos) const +QList QXYSeries::points() const { Q_D(const QXYSeries); if (d->m_model) { - if (d->m_mapOrientation == Qt::Vertical) + QList result; + if (d->m_mapOrientation == Qt::Vertical){ // consecutive data is read from model's column - return d->m_model->data(d->m_model->index(pos + d->m_mapFirst, d->m_mapY), Qt::DisplayRole).toDouble(); - else + + for(int i = d->m_mapFirst; i< d->m_mapFirst + count(); ++i) { + qreal x = d->m_model->data(d->m_model->index(i, d->m_mapX), Qt::DisplayRole).toReal(); + qreal y = d->m_model->data(d->m_model->index(i, d->m_mapY), Qt::DisplayRole).toReal(); + result << QPointF(x,y); + } + return result; + } + else{ // consecutive data is read from model's row - return d->m_model->data(d->m_model->index(d->m_mapY, pos + d->m_mapFirst), Qt::DisplayRole).toDouble(); + for(int i = d->m_mapFirst; i< d->m_mapFirst + count(); ++i) { + qreal x = d->m_model->data(d->m_model->index(d->m_mapX, i), Qt::DisplayRole).toReal(); + qreal y = d->m_model->data(d->m_model->index(d->m_mapY, i), Qt::DisplayRole).toReal(); + result << QPointF(x,y); + } + return result; + } } else { // model is not specified, return the data from series' internal data store - return d->m_y.at(pos); + return d->m_points.toList(); } } @@ -243,8 +209,6 @@ int QXYSeries::count() const { Q_D(const QXYSeries); - Q_ASSERT(d->m_x.size() == d->m_y.size()); - if (d->m_model) { if (d->m_mapOrientation == Qt::Vertical) { // data is in a column. Return the number of mapped items if the model's column have enough items @@ -264,19 +228,7 @@ int QXYSeries::count() const } // model is not specified, return the number of points in the series internal data store - return d->m_x.size(); -} - -/*! - Returns the data points of the series. -*/ -QList QXYSeries::data() -{ - Q_D(QXYSeries); - QList data; - for (int i(0); i < d->m_x.count() && i < d->m_y.count(); i++) - data.append(QPointF(d->m_x.at(i), d->m_y.at(i))); - return data; + return d->m_points.count(); } @@ -359,7 +311,7 @@ QXYSeries& QXYSeries::operator<< (const QPointF &point) \sa append() */ -QXYSeries& QXYSeries::operator<< (const QList points) +QXYSeries& QXYSeries::operator<< (const QList& points) { append(points); return *this; @@ -443,11 +395,11 @@ void QXYSeriesPrivate::scaleDomain(Domain& domain) int tickXCount(domain.tickXCount()); int tickYCount(domain.tickYCount()); - Q_Q(QXYSeries); - for (int i = 0; i < q->count(); i++) + for (int i = 0; i < m_points.count(); i++) { - qreal x = q->x(i); - qreal y = q->y(i); + + qreal x = m_points[i].x(); + qreal y = m_points[i].y(); minX = qMin(minX, x); minY = qMin(minY, y); maxX = qMax(maxX, x); diff --git a/src/xychart/qxyseries.h b/src/xychart/qxyseries.h index f99c591..ea37219 100644 --- a/src/xychart/qxyseries.h +++ b/src/xychart/qxyseries.h @@ -42,21 +42,18 @@ protected: public: void append(qreal x, qreal y); void append(const QPointF &point); - void append(const QList points); - void replace(qreal x,qreal y); - void replace(const QPointF &point); - void remove(qreal x); + void append(const QList &points); + void replace(qreal oldX,qreal oldY,qreal newX,qreal newY); + void replace(const QPointF &oldPoint,const QPointF &newPoint); void remove(qreal x, qreal y); void remove(const QPointF &point); void removeAll(); int count() const; - qreal x(int pos) const; - qreal y(int pos) const; - QList data(); + QList points() const; QXYSeries& operator << (const QPointF &point); - QXYSeries& operator << (const QList points); + QXYSeries& operator << (const QList &points); void setPen(const QPen &pen); QPen pen() const; diff --git a/src/xychart/qxyseries_p.h b/src/xychart/qxyseries_p.h index b809f0b..275d72c 100644 --- a/src/xychart/qxyseries_p.h +++ b/src/xychart/qxyseries_p.h @@ -62,8 +62,7 @@ Q_SIGNALS: protected: - QVector m_x; - QVector m_y; + QVector m_points; QPen m_pen; QBrush m_brush; diff --git a/src/xychart/xychartitem.cpp b/src/xychart/xychartitem.cpp index e4c1b2b..f3f9acf 100644 --- a/src/xychart/xychartitem.cpp +++ b/src/xychart/xychartitem.cpp @@ -61,8 +61,9 @@ QPointF XYChartItem::calculateGeometryPoint(int index) const { const qreal deltaX = m_size.width()/(m_maxX-m_minX); const qreal deltaY = m_size.height()/(m_maxY-m_minY); - qreal x = (m_series->x(index) - m_minX)* deltaX; - qreal y = (m_series->y(index) - m_minY)*-deltaY + m_size.height(); + const QList& vector = m_series->points(); + qreal x = (vector[index].x() - m_minX)* deltaX; + qreal y = (vector[index].y() - m_minY)*-deltaY + m_size.height(); return QPointF(x,y); } @@ -71,14 +72,16 @@ QVector XYChartItem::calculateGeometryPoints() const const qreal deltaX = m_size.width()/(m_maxX-m_minX); const qreal deltaY = m_size.height()/(m_maxY-m_minY); - QVector points; - points.reserve(m_series->count()); + QVector result; + result.resize(m_series->count()); + const QList& vector = m_series->points(); for (int i = 0; i < m_series->count(); ++i) { - qreal x = (m_series->x(i) - m_minX)* deltaX; - qreal y = (m_series->y(i) - m_minY)*-deltaY + m_size.height(); - points << QPointF(x,y); + qreal x = (vector[i].x() - m_minX)* deltaX; + qreal y = (vector[i].y() - m_minY)*-deltaY + m_size.height(); + result[i].setX(x); + result[i].setY(y); } - return points; + return result; } QPointF XYChartItem::calculateDomainPoint(const QPointF &point) const diff --git a/test/auto/auto.pro b/test/auto/auto.pro index e180036..c2440e2 100644 --- a/test/auto/auto.pro +++ b/test/auto/auto.pro @@ -3,7 +3,7 @@ } TEMPLATE = subdirs -SUBDIRS += qchartview qchart +SUBDIRS += qchartview qchart qlineseries test_private:{ SUBDIRS += chartdataset domain diff --git a/test/wavechart/wavechart.cpp b/test/wavechart/wavechart.cpp index 13132c9..8225a42 100644 --- a/test/wavechart/wavechart.cpp +++ b/test/wavechart/wavechart.cpp @@ -58,10 +58,10 @@ void WaveChart::update() { int fluctuate; - + const QList& points = m_series->points(); for (qreal i = 0, x = 0; x <= 2 * PI; x += m_step, i++) { fluctuate = qrand() % 100; - m_series->replace(x, fabs(sin(x) * fluctuate)); + m_series->replace(x,points[i].y(),x,fabs(sin(x) * fluctuate)); }