From d6a999e30ac3ddec51e9c0568076a6ef02231365 2012-12-11 08:32:42 From: Marek Rosa Date: 2012-12-11 08:32:42 Subject: [PATCH] QSplineSeries calculateControlPoints moved to splinechartitem. This way we don't need to deal with controlPoints on logaritmic scale --- diff --git a/src/axis/logvalueaxis/chartlogvalueaxisx.cpp b/src/axis/logvalueaxis/chartlogvalueaxisx.cpp index de9dc3c..a06509f 100644 --- a/src/axis/logvalueaxis/chartlogvalueaxisx.cpp +++ b/src/axis/logvalueaxis/chartlogvalueaxisx.cpp @@ -49,8 +49,7 @@ QVector ChartLogValueAxisX::calculateLayout() const qreal logMin = log10(m_axis->min()) / log10(m_axis->base()); qreal leftEdge = logMin < logMax ? logMin : logMax; qreal ceilEdge = ceil(leftEdge); - int tickCount = qAbs(qRound(logMax - logMin)); - tickCount++; + int tickCount = qAbs(ceil(logMax) - ceil(logMin)); points.resize(tickCount); const QRectF &gridRect = gridGeometry(); diff --git a/src/axis/logvalueaxis/chartlogvalueaxisy.cpp b/src/axis/logvalueaxis/chartlogvalueaxisy.cpp index 25d51c0..5ca0b16 100644 --- a/src/axis/logvalueaxis/chartlogvalueaxisy.cpp +++ b/src/axis/logvalueaxis/chartlogvalueaxisy.cpp @@ -48,8 +48,7 @@ QVector ChartLogValueAxisY::calculateLayout() const qreal logMin = log10(m_axis->min()) / log10(m_axis->base()); qreal leftEdge = logMin < logMax ? logMin : logMax; qreal ceilEdge = ceil(leftEdge); - int tickCount = qAbs(qRound(logMax - logMin)); - tickCount++; + int tickCount = qAbs(ceil(logMax) - ceil(logMin)); points.resize(tickCount); const QRectF &gridRect = gridGeometry(); @@ -100,8 +99,6 @@ QSizeF ChartLogValueAxisY::sizeHint(Qt::SizeHint which, const QSizeF &constraint ticksList = createLogValueLabels(m_axis->min(), m_axis->max(), m_axis->base(), tickCount, m_axis->labelFormat()); else ticksList.append(QString(" ")); - qDebug() << ticksList; - qDebug() << tickCount; qreal width = 0; qreal height = 0; diff --git a/src/splinechart/qsplineseries.cpp b/src/splinechart/qsplineseries.cpp index a0ef9c4..15c4d61 100644 --- a/src/splinechart/qsplineseries.cpp +++ b/src/splinechart/qsplineseries.cpp @@ -89,11 +89,6 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE QSplineSeries::QSplineSeries(QObject *parent) : QLineSeries(*new QSplineSeriesPrivate(this), parent) { - Q_D(QSplineSeries); - QObject::connect(this, SIGNAL(pointAdded(int)), d, SLOT(updateControlPoints())); - QObject::connect(this, SIGNAL(pointRemoved(int)), d, SLOT(updateControlPoints())); - QObject::connect(this, SIGNAL(pointReplaced(int)), d, SLOT(updateControlPoints())); - QObject::connect(this, SIGNAL(pointsReplaced()), d, SLOT(updateControlPoints())); } /*! @@ -118,120 +113,6 @@ QSplineSeriesPrivate::QSplineSeriesPrivate(QSplineSeries *q) { } -/*! - Calculates control points which are needed by QPainterPath.cubicTo function to draw the cubic Bezier cureve between two points. - */ -void QSplineSeriesPrivate::calculateControlPoints() -{ - Q_Q(QSplineSeries); - - const QList& points = q->points(); - - int n = points.count() - 1; - - if (n == 1) { - //for n==1 - m_controlPoints[0].setX((2 * points[0].x() + points[1].x()) / 3); - m_controlPoints[0].setY((2 * points[0].y() + points[1].y()) / 3); - m_controlPoints[1].setX(2 * m_controlPoints[0].x() - points[0].x()); - m_controlPoints[1].setY(2 * m_controlPoints[0].y() - points[0].y()); - return; - } - - // Calculate first Bezier control points - // Set of equations for P0 to Pn points. - // - // | 2 1 0 0 ... 0 0 0 ... 0 0 0 | | P1_1 | | P0 + 2 * P1 | - // | 1 4 1 0 ... 0 0 0 ... 0 0 0 | | P1_2 | | 4 * P1 + 2 * P2 | - // | 0 1 4 1 ... 0 0 0 ... 0 0 0 | | P1_3 | | 4 * P2 + 2 * P3 | - // | . . . . . . . . . . . . | | ... | | ... | - // | 0 0 0 0 ... 1 4 1 ... 0 0 0 | * | P1_i | = | 4 * P(i-1) + 2 * Pi | - // | . . . . . . . . . . . . | | ... | | ... | - // | 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 | - // - QVector vector; - vector.resize(n); - - vector[0] = points[0].x() + 2 * points[1].x(); - - - for (int i = 1; i < n - 1; ++i) - vector[i] = 4 * points[i].x() + 2 * points[i + 1].x(); - - vector[n - 1] = (8 * points[n - 1].x() + points[n].x()) / 2.0; - - QVector xControl = firstControlPoints(vector); - - vector[0] = points[0].y() + 2 * points[1].y(); - - for (int i = 1; i < n - 1; ++i) - vector[i] = 4 * points[i].y() + 2 * points[i + 1].y(); - - vector[n - 1] = (8 * points[n - 1].y() + points[n].y()) / 2.0; - - QVector yControl = firstControlPoints(vector); - - for (int i = 0, j = 0; i < n; ++i, ++j) { - - m_controlPoints[j].setX(xControl[i]); - m_controlPoints[j].setY(yControl[i]); - - j++; - - if (i < n - 1) { - m_controlPoints[j].setX(2 * points[i + 1].x() - xControl[i + 1]); - m_controlPoints[j].setY(2 * points[i + 1].y() - yControl[i + 1]); - } else { - m_controlPoints[j].setX((points[n].x() + xControl[n - 1]) / 2); - m_controlPoints[j].setY((points[n].y() + yControl[n - 1]) / 2); - } - } -} - -QVector QSplineSeriesPrivate::firstControlPoints(const QVector& vector) -{ - 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; - - 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 < count; i++) - result[count - i - 1] -= temp[count - i] * result[count - i]; - - return result; -} - -QPointF QSplineSeriesPrivate::controlPoint(int index) const -{ - return m_controlPoints[index]; -} - -/*! - Updates the control points, besed on currently avaiable knots. - */ -void QSplineSeriesPrivate::updateControlPoints() -{ - Q_Q(QSplineSeries); - if (q->count() > 1) { - m_controlPoints.resize(2 * q->count() - 2); - calculateControlPoints(); - } -} - void QSplineSeriesPrivate::initializeGraphics(QGraphicsItem* parent) { Q_Q(QSplineSeries); @@ -253,7 +134,6 @@ void QSplineSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool fo } } - void QSplineSeriesPrivate::initializeAnimations(QtCommercialChart::QChart::AnimationOptions options) { SplineChartItem *item = static_cast(m_item.data()); diff --git a/src/splinechart/qsplineseries_p.h b/src/splinechart/qsplineseries_p.h index 8bca724..35e1a7b 100644 --- a/src/splinechart/qsplineseries_p.h +++ b/src/splinechart/qsplineseries_p.h @@ -45,17 +45,6 @@ public: void initializeGraphics(QGraphicsItem* parent); void initializeAnimations(QtCommercialChart::QChart::AnimationOptions options); - QPointF controlPoint(int index) const; - -public Q_SLOTS: - void updateControlPoints(); - -private: - void calculateControlPoints(); - QVector firstControlPoints(const QVector& vector); - -public: - QVector m_controlPoints; private: Q_DECLARE_PUBLIC(QSplineSeries) }; diff --git a/src/splinechart/splinechartitem.cpp b/src/splinechart/splinechartitem.cpp index d991d39..17a2d3a 100644 --- a/src/splinechart/splinechartitem.cpp +++ b/src/splinechart/splinechartitem.cpp @@ -77,14 +77,8 @@ QVector SplineChartItem::controlGeometryPoints() const void SplineChartItem::updateChart(QVector &oldPoints, QVector &newPoints, int index) { QVector controlPoints; - if (newPoints.count() >= 2) - controlPoints.resize(newPoints.count() * 2 - 2); - - for (int i = 0; i < newPoints.size() - 1; i++) { - controlPoints[2 * i] = calculateGeometryControlPoint(2 * i); - controlPoints[2 * i + 1] = calculateGeometryControlPoint(2 * i + 1); - } + controlPoints = calculateControlPoints(newPoints); if (m_animation) m_animation->setup(oldPoints, newPoints, m_controlPoints, controlPoints, index); @@ -99,12 +93,6 @@ void SplineChartItem::updateChart(QVector &oldPoints, QVector updateGeometry(); } -QPointF SplineChartItem::calculateGeometryControlPoint(int index) const -{ - bool ok; - return domain()->calculateGeometryPoint(m_series->d_func()->controlPoint(index), ok); -} - void SplineChartItem::updateGeometry() { const QVector &points = m_points; @@ -135,6 +123,103 @@ void SplineChartItem::updateGeometry() } +/*! + Calculates control points which are needed by QPainterPath.cubicTo function to draw the cubic Bezier cureve between two points. + */ +QVector SplineChartItem::calculateControlPoints(const QVector &points) +{ + QVector controlPoints; + controlPoints.resize(points.count() * 2 - 2); + + int n = points.count() - 1; + + if (n == 1) { + //for n==1 + controlPoints[0].setX((2 * points[0].x() + points[1].x()) / 3); + controlPoints[0].setY((2 * points[0].y() + points[1].y()) / 3); + controlPoints[1].setX(2 * controlPoints[0].x() - points[0].x()); + controlPoints[1].setY(2 * controlPoints[0].y() - points[0].y()); + return controlPoints; + } + + // Calculate first Bezier control points + // Set of equations for P0 to Pn points. + // + // | 2 1 0 0 ... 0 0 0 ... 0 0 0 | | P1_1 | | P0 + 2 * P1 | + // | 1 4 1 0 ... 0 0 0 ... 0 0 0 | | P1_2 | | 4 * P1 + 2 * P2 | + // | 0 1 4 1 ... 0 0 0 ... 0 0 0 | | P1_3 | | 4 * P2 + 2 * P3 | + // | . . . . . . . . . . . . | | ... | | ... | + // | 0 0 0 0 ... 1 4 1 ... 0 0 0 | * | P1_i | = | 4 * P(i-1) + 2 * Pi | + // | . . . . . . . . . . . . | | ... | | ... | + // | 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 | + // + QVector vector; + vector.resize(n); + + vector[0] = points[0].x() + 2 * points[1].x(); + + + for (int i = 1; i < n - 1; ++i) + vector[i] = 4 * points[i].x() + 2 * points[i + 1].x(); + + vector[n - 1] = (8 * points[n - 1].x() + points[n].x()) / 2.0; + + QVector xControl = firstControlPoints(vector); + + vector[0] = points[0].y() + 2 * points[1].y(); + + for (int i = 1; i < n - 1; ++i) + vector[i] = 4 * points[i].y() + 2 * points[i + 1].y(); + + vector[n - 1] = (8 * points[n - 1].y() + points[n].y()) / 2.0; + + QVector yControl = firstControlPoints(vector); + + for (int i = 0, j = 0; i < n; ++i, ++j) { + + controlPoints[j].setX(xControl[i]); + controlPoints[j].setY(yControl[i]); + + j++; + + if (i < n - 1) { + controlPoints[j].setX(2 * points[i + 1].x() - xControl[i + 1]); + controlPoints[j].setY(2 * points[i + 1].y() - yControl[i + 1]); + } else { + controlPoints[j].setX((points[n].x() + xControl[n - 1]) / 2); + controlPoints[j].setY((points[n].y() + yControl[n - 1]) / 2); + } + } + return controlPoints; +} + +QVector SplineChartItem::firstControlPoints(const QVector& vector) +{ + 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; + + 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 < count; i++) + result[count - i - 1] -= temp[count - i] * result[count - i]; + + return result; +} + //handlers void SplineChartItem::handleUpdated() diff --git a/src/splinechart/splinechartitem_p.h b/src/splinechart/splinechartitem_p.h index b2aa8fb..d6e0862 100644 --- a/src/splinechart/splinechartitem_p.h +++ b/src/splinechart/splinechartitem_p.h @@ -60,15 +60,14 @@ public Q_SLOTS: protected: void updateGeometry(); + QVector calculateControlPoints(const QVector &points); + QVector firstControlPoints(const QVector& vector); void updateChart(QVector &oldPoints, QVector &newPoints, int index); void mousePressEvent(QGraphicsSceneMouseEvent *event); void hoverEnterEvent(QGraphicsSceneHoverEvent *event); void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); private: - QPointF calculateGeometryControlPoint(int index) const; - -private: QSplineSeries *m_series; QPainterPath m_path; QRectF m_rect;