diff --git a/src/splinechart/qsplineseries.cpp b/src/splinechart/qsplineseries.cpp
index 9836c3f..828e01c 100644
--- a/src/splinechart/qsplineseries.cpp
+++ b/src/splinechart/qsplineseries.cpp
@@ -11,3 +11,90 @@ QSplineSeries& QSplineSeries::operator << (const QPointF &value)
emit changed();
return *this;
}
+
+void QSplineSeries::GetCurveControlPoints()
+ {
+ int n = m_data.size() - 1;
+ if (n < 1)
+ throw new ArgumentException
+ ("At least two knot points required", "knots");
+ if (n == 1)
+ { // Special case: Bezier curve should be a straight line.
+ firstControlPoints = new Point[1];
+ // 3P1 = 2P0 + P3
+ firstControlPoints[0].X = (2 * knots[0].X + knots[1].X) / 3;
+ firstControlPoints[0].Y = (2 * knots[0].Y + knots[1].Y) / 3;
+
+ secondControlPoints = new Point[1];
+ // P2 = 2P1 P0
+ secondControlPoints[0].X = 2 *
+ firstControlPoints[0].X - knots[0].X;
+ secondControlPoints[0].Y = 2 *
+ firstControlPoints[0].Y - knots[0].Y;
+ return;
+ }
+
+ // Calculate first Bezier control points
+ // Right hand side vector
+ double[] rhs = new double[n];
+
+ // Set right hand side X values
+ for (int i = 1; i < n - 1; ++i)
+ rhs[i] = 4 * knots[i].X + 2 * knots[i + 1].X;
+ rhs[0] = knots[0].X + 2 * knots[1].X;
+ rhs[n - 1] = (8 * knots[n - 1].X + knots[n].X) / 2.0;
+ // Get first control points X-values
+ double[] x = GetFirstControlPoints(rhs);
+
+ // Set right hand side Y values
+ for (int i = 1; i < n - 1; ++i)
+ rhs[i] = 4 * knots[i].Y + 2 * knots[i + 1].Y;
+ rhs[0] = knots[0].Y + 2 * knots[1].Y;
+ rhs[n - 1] = (8 * knots[n - 1].Y + knots[n].Y) / 2.0;
+ // Get first control points Y-values
+ double[] y = GetFirstControlPoints(rhs);
+
+ // Fill output arrays.
+ firstControlPoints = new Point[n];
+ secondControlPoints = new Point[n];
+ for (int i = 0; i < n; ++i)
+ {
+ // First control point
+ firstControlPoints[i] = new Point(x[i], y[i]);
+ // Second control point
+ if (i < n - 1)
+ secondControlPoints[i] = new Point(2 * knots
+ [i + 1].X - x[i + 1], 2 *
+ knots[i + 1].Y - y[i + 1]);
+ else
+ secondControlPoints[i] = new Point((knots
+ [n].X + x[n - 1]) / 2,
+ (knots[n].Y + y[n - 1]) / 2);
+ }
+ }
+
+ ///
+ /// Solves a tridiagonal system for one of coordinates (x or y)
+ /// of first Bezier control points.
+ ///
+ /// Right hand side vector.
+ /// Solution vector.
+void GetFirstControlPoints(qreal[] rhs)
+ {
+ int n = rhs.Length;
+ double[] x = new double[n]; // Solution vector.
+ double[] tmp = new double[n]; // Temp workspace.
+
+ double b = 2.0;
+ x[0] = rhs[0] / b;
+ for (int i = 1; i < n; i++) // Decomposition and forward substitution.
+ {
+ tmp[i] = 1 / b;
+ b = (i < n - 1 ? 4.0 : 3.5) - tmp[i];
+ x[i] = (rhs[i] - x[i - 1]) / b;
+ }
+ for (int i = 1; i < n; i++)
+ x[n - i - 1] -= tmp[n - i] * x[n - i]; // Backsubstitution.
+
+ return x;
+ }
diff --git a/src/splinechart/qsplineseries.h b/src/splinechart/qsplineseries.h
index 3d32dba..9623679 100644
--- a/src/splinechart/qsplineseries.h
+++ b/src/splinechart/qsplineseries.h
@@ -14,6 +14,7 @@ class QSplineSeries : public QChartSeries
QChartSeriesType type() const { return QChartSeries::SeriesTypeSpline; }
void addData(QPointF value);
QSplineSeries& operator << (const QPointF &value);
+ void calculateControlPoints();
signals:
@@ -21,6 +22,7 @@ class QSplineSeries : public QChartSeries
private:
QList m_data;
+ QList m_controlPoints;
};