qsplineseries.cpp
100 lines
| 3.3 KiB
| text/x-c
|
CppLexer
|
r295 | #include "qsplineseries.h" | ||
QSplineSeries::QSplineSeries(QObject *parent) : | ||||
QObject(parent) | ||||
{ | ||||
} | ||||
|
r305 | |||
QSplineSeries& QSplineSeries::operator << (const QPointF &value) | ||||
{ | ||||
d->m_data.append(value); | ||||
emit changed(); | ||||
return *this; | ||||
} | ||||
|
r318 | |||
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); | ||||
} | ||||
} | ||||
/// <summary> | ||||
/// Solves a tridiagonal system for one of coordinates (x or y) | ||||
/// of first Bezier control points. | ||||
/// </summary> | ||||
/// <param name="rhs">Right hand side vector.</param> | ||||
/// <returns>Solution vector.</returns> | ||||
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; | ||||
} | ||||