File indexing completed on 2024-05-26 04:27:30

0001 /*
0002  *  SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_nu_bspline_2d.h"
0008 
0009 #include <kis_debug.h>
0010 #include <limits>
0011 
0012 #include "einspline/nubspline_create.h"
0013 #include "einspline/nubspline_eval_std_s.h"
0014 
0015 #include "kis_bspline_p.h"
0016 
0017 namespace KisBSplines {
0018 
0019 struct Q_DECL_HIDDEN KisNUBSpline2D::Private
0020 {
0021     BorderCondition bcX;
0022     BorderCondition bcY;
0023 
0024     NUBspline_2d_s* spline;
0025 
0026     NUgrid *xGrid;
0027     NUgrid *yGrid;
0028 
0029     float minX;
0030     float maxX;
0031     float minY;
0032     float maxY;
0033 };
0034 
0035 KisNUBSpline2D::KisNUBSpline2D(const QVector<double> &xSamples, BorderCondition bcX,
0036                                const QVector<double> &ySamples, BorderCondition bcY)
0037     : m_d(new Private),
0038       m_xSamples(xSamples),
0039       m_ySamples(ySamples)
0040 {
0041     m_d->xGrid = create_general_grid(const_cast<double*>(m_xSamples.constData()), m_xSamples.size());
0042     m_d->yGrid = create_general_grid(const_cast<double*>(m_ySamples.constData()), m_ySamples.size());
0043 
0044     m_d->bcX = bcX;
0045     m_d->bcY = bcY;
0046 
0047     m_d->minX = xSamples.first();
0048     m_d->maxX = xSamples.last();
0049 
0050     m_d->minY = ySamples.first();
0051     m_d->maxY = ySamples.last();
0052 
0053     m_d->spline = 0;
0054 }
0055 
0056 KisNUBSpline2D::~KisNUBSpline2D()
0057 {
0058     if (m_d->spline) {
0059         destroy_Bspline(m_d->spline);
0060     }
0061 
0062     destroy_grid(m_d->xGrid);
0063     destroy_grid(m_d->yGrid);
0064 }
0065 
0066 void KisNUBSpline2D::initializeSplineImpl(const QVector<float> &values)
0067 {
0068     BCtype_s bctypeX;
0069     bctypeX.lCode = bctypeX.rCode = convertBorderType(m_d->bcX);
0070     bctypeX.lVal = bctypeX.rVal = 0.0;
0071 
0072     BCtype_s bctypeY;
0073     bctypeY.lCode = bctypeY.rCode = convertBorderType(m_d->bcY);
0074     bctypeY.lVal = bctypeY.rVal = 0.0;
0075 
0076     m_d->spline =
0077         create_NUBspline_2d_s(m_d->xGrid, m_d->yGrid,
0078                               bctypeX, bctypeY,
0079                               const_cast<float*>(values.constData()));
0080 }
0081 
0082 float KisNUBSpline2D::value(float x, float y) const
0083 {
0084     /**
0085      * The spline works for an open interval only, so include the last point
0086      * explicitly
0087      */
0088 
0089     if (x == m_d->maxX) {
0090         x -= x * std::numeric_limits<float>::epsilon();
0091     }
0092 
0093     if (y == m_d->maxY) {
0094         y -= y * std::numeric_limits<float>::epsilon();
0095     }
0096 
0097     KIS_ASSERT_RECOVER_NOOP(x >= m_d->minX && x < m_d->maxX);
0098     KIS_ASSERT_RECOVER_NOOP(y >= m_d->minY && y < m_d->maxY);
0099 
0100     float value;
0101     eval_NUBspline_2d_s(m_d->spline, x, y, &value);
0102 
0103     return value;
0104 }
0105 
0106 QPointF KisNUBSpline2D::topLeft() const
0107 {
0108     return QPointF(m_d->minX, m_d->minY);
0109 }
0110 
0111 QPointF KisNUBSpline2D::bottomRight() const
0112 {
0113     return QPointF(m_d->maxX, m_d->maxY);
0114 }
0115 
0116 BorderCondition KisNUBSpline2D::borderConditionX() const
0117 {
0118     return m_d->bcX;
0119 }
0120 
0121 BorderCondition KisNUBSpline2D::borderConditionY() const
0122 {
0123     return m_d->bcY;
0124 }
0125 
0126 }