Krita Source Code Documentation
Loading...
Searching...
No Matches
KisCubicSpline< T_point, T > Class Template Reference

#include <kis_cubic_curve_spline.h>

Classes

struct  Coefficients
 

Public Member Functions

void createSpline (const QList< T_point > &a)
 
getValue (T x) const
 
 KisCubicSpline ()
 
 KisCubicSpline (const QList< T_point > &a)
 

Private Attributes

QList< Coefficientsm_coefficients
 
QList< T_point > m_points
 

Detailed Description

template<typename T_point, typename T>
class KisCubicSpline< T_point, T >

Definition at line 226 of file kis_cubic_curve_spline.h.

Constructor & Destructor Documentation

◆ KisCubicSpline() [1/2]

template<typename T_point , typename T >
KisCubicSpline< T_point, T >::KisCubicSpline ( )
inline

Definition at line 229 of file kis_cubic_curve_spline.h.

229{}

◆ KisCubicSpline() [2/2]

template<typename T_point , typename T >
KisCubicSpline< T_point, T >::KisCubicSpline ( const QList< T_point > & a)
inline

Definition at line 230 of file kis_cubic_curve_spline.h.

230 {
231 createSpline(a);
232 }
void createSpline(const QList< T_point > &a)

References KisCubicSpline< T_point, T >::createSpline().

Member Function Documentation

◆ createSpline()

template<typename T_point , typename T >
void KisCubicSpline< T_point, T >::createSpline ( const QList< T_point > & a)
inline

Create new spline and precalculate some values for future

- base points of the spline

Definition at line 240 of file kis_cubic_curve_spline.h.

240 {
241 KIS_SAFE_ASSERT_RECOVER_RETURN(a.size() > 0);
242
243 const int intervals = a.size() - 1;
244 m_points = a;
245
246 m_coefficients.clear();
247
248 if (a.size() == 1) {
249 // Constant function
250 m_coefficients.append({ 0.0, 0.0, 0.0, a.first().y() });
251 return;
252 }
253
254 if (a.size() == 2) {
255 // Linear function
256 const T c = (a.last().y() - a.first().y()) / (a.last().x() - a.first().x());
257 const T d = a.first().y() - c * a.first().x();
258 m_coefficients.append({ 0.0, 0.0, c, d });
259 return;
260 }
261
262 using Triplet = Eigen::Triplet<qreal>;
263 using Matrix = Eigen::SparseMatrix<qreal>;
264 using Vector = Eigen::VectorXd;
265
266 const int numberOfRows = intervals * 4;
267 const int numberOfColumns = numberOfRows;
268 std::vector<Triplet> triplets;
269 Matrix A(numberOfRows, numberOfColumns);
270 Vector b(numberOfRows);
271
272 // Fill the triplet list
273 triplets.reserve(numberOfRows * 4);
274 qint32 row = 0;
275 // Fill rows with position equations
276 // Initialize the values for the left point of the first interval. The
277 // rest of the left points of the intervals use the values computed for
278 // the right point of the previous interval
279 T pointX = a.first().x();
280 T pointY = a.first().y();
281 T pointXSquared = pointX * pointX;
282 T pointXCubed = pointXSquared * pointX;
283 for (qint32 i = 0; i < intervals; ++i) {
284 const int baseColumn = i * 4;
285 // Left point
286 triplets.push_back(Triplet(row, baseColumn + 0, pointXCubed));
287 triplets.push_back(Triplet(row, baseColumn + 1, pointXSquared));
288 triplets.push_back(Triplet(row, baseColumn + 2, pointX));
289 triplets.push_back(Triplet(row, baseColumn + 3, 1.0));
290 b(row) = pointY;
291 ++row;
292 // Right point (the following values are reused for the left point
293 // of the next interval)
294 pointX = a[i + 1].x();
295 pointY = a[i + 1].y();
296 pointXSquared = pointX * pointX;
297 pointXCubed = pointXSquared * pointX;
298 triplets.push_back(Triplet(row, baseColumn + 0, pointXCubed));
299 triplets.push_back(Triplet(row, baseColumn + 1, pointXSquared));
300 triplets.push_back(Triplet(row, baseColumn + 2, pointX));
301 triplets.push_back(Triplet(row, baseColumn + 3, 1.0));
302 b(row) = pointY;
303 ++row;
304 }
305 // Fill rows with derivative equations
306 // Extreme knots second derivatives
307 pointX = a.first().x();
308 triplets.push_back(Triplet(row, 0, 6.0 * pointX));
309 triplets.push_back(Triplet(row, 1, 2.0));
310 b(row) = 0.0;
311 ++row;
312 pointX = a.last().x();
313 triplets.push_back(Triplet(row, numberOfColumns - 4, 6.0 * pointX));
314 triplets.push_back(Triplet(row, numberOfColumns - 3, 2.0));
315 b(row) = 0.0;
316 ++row;
317 // Interior knots derivatives
318 for (qint32 i = 1; i < a.size() - 1; ++i) {
319 pointX = a[i].x();
320 const qint32 baseColumn = i * 4;
321 if (a[i].isSetAsCorner()) {
322 triplets.push_back(Triplet(row, baseColumn - 4, 6.0 * pointX));
323 triplets.push_back(Triplet(row, baseColumn - 3, 2.0));
324 b(row) = 0.0;
325 ++row;
326 triplets.push_back(Triplet(row, baseColumn + 0, 6.0 * pointX));
327 triplets.push_back(Triplet(row, baseColumn + 1, 2.0));
328 b(row) = 0.0;
329 ++row;
330 } else {
331 pointXSquared = pointX * pointX;
332 // First derivatives
333 triplets.push_back(Triplet(row, baseColumn - 4, 3.0 * pointXSquared));
334 triplets.push_back(Triplet(row, baseColumn - 3, 2.0 * pointX));
335 triplets.push_back(Triplet(row, baseColumn - 2, 1.0));
336 triplets.push_back(Triplet(row, baseColumn + 0, -3.0 * pointXSquared));
337 triplets.push_back(Triplet(row, baseColumn + 1, -2.0 * pointX));
338 triplets.push_back(Triplet(row, baseColumn + 2, -1.0));
339 b(row) = 0.0;
340 ++row;
341 // Second derivatives
342 triplets.push_back(Triplet(row, baseColumn - 4, 6.0 * pointX));
343 triplets.push_back(Triplet(row, baseColumn - 3, 2.0));
344 triplets.push_back(Triplet(row, baseColumn + 0, -6.0 * pointX));
345 triplets.push_back(Triplet(row, baseColumn + 1, -2.0));
346 b(row) = 0.0;
347 ++row;
348 }
349 }
350 // Solve
351 A.setFromTriplets(triplets.begin(), triplets.end());
352 Eigen::SparseLU<Matrix> solver(A);
353 Vector x = solver.solve(b);
354 // Fill coefficients
355 for (qint32 i = 0; i < intervals; ++i) {
356 row = i * 4;
357 m_coefficients.append({x(row), x(row + 1), x(row + 2), x(row + 3)});
358 }
359 }
QList< T_point > m_points
QList< Coefficients > m_coefficients
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128

References A, KIS_SAFE_ASSERT_RECOVER_RETURN, KisCubicSpline< T_point, T >::m_coefficients, and KisCubicSpline< T_point, T >::m_points.

◆ getValue()

template<typename T_point , typename T >
T KisCubicSpline< T_point, T >::getValue ( T x) const
inline

Get value of precalculated spline in the point @x

Definition at line 364 of file kis_cubic_curve_spline.h.

364 {
366 // Find the interval for the given x value
367 int interval;
368 for (interval = 0; interval < m_coefficients.size() - 1; ++interval) {
369 if (x < m_points[interval + 1].x()) {
370 break;
371 }
372 }
373 // Evaluate
374 const T xSquared = x * x;
375 const T xCubed = xSquared * x;
376 const Coefficients& coefficients = m_coefficients[interval];
377 return coefficients.a * xCubed + coefficients.b * xSquared +
378 coefficients.c * x + coefficients.d;
379 }
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129

References KisCubicSpline< T_point, T >::Coefficients::a, KisCubicSpline< T_point, T >::Coefficients::b, KisCubicSpline< T_point, T >::Coefficients::c, KisCubicSpline< T_point, T >::Coefficients::d, KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, KisCubicSpline< T_point, T >::m_coefficients, and KisCubicSpline< T_point, T >::m_points.

Member Data Documentation

◆ m_coefficients

template<typename T_point , typename T >
QList<Coefficients> KisCubicSpline< T_point, T >::m_coefficients
private

Definition at line 391 of file kis_cubic_curve_spline.h.

◆ m_points

template<typename T_point , typename T >
QList<T_point> KisCubicSpline< T_point, T >::m_points
private

Definition at line 390 of file kis_cubic_curve_spline.h.


The documentation for this class was generated from the following file: