File indexing completed on 2024-12-22 04:10:13

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_bsplines_test.h"
0008 
0009 #include <simpletest.h>
0010 
0011 #include <cmath>
0012 
0013 #include <bsplines/kis_bspline_1d.h>
0014 #include <bsplines/kis_bspline_2d.h>
0015 #include <bsplines/kis_nu_bspline_2d.h>
0016 #include <kis_debug.h>
0017 #include <kis_global.h>
0018 
0019 #include <boost/accumulators/accumulators.hpp>
0020 #include <boost/accumulators/statistics/stats.hpp>
0021 #include <boost/accumulators/statistics/variance.hpp>
0022 #include <boost/accumulators/statistics/min.hpp>
0023 #include <boost/accumulators/statistics/max.hpp>
0024 
0025 using namespace boost::accumulators;
0026 using namespace KisBSplines;
0027 
0028 struct FunctionOp {
0029     float operator() (qreal x) {
0030         return std::sqrt(x);
0031     }
0032 
0033     float operator() (qreal x, qreal y) const {
0034         return std::sqrt(x) + y - pow2(x + y);
0035     }
0036 };
0037 
0038 void KisBSplinesTest::test1D()
0039 {
0040     const qreal start = 1.0;
0041     const qreal end = 11.0;
0042 
0043     KisBSpline1D spline(start, end, 10, Natural);
0044     spline.initializeSpline<FunctionOp>();
0045 
0046     accumulator_set<qreal, stats<tag::variance, tag::max, tag::min> > accum;
0047 
0048     FunctionOp op;
0049     for (qreal x = start; x < end; x += 0.01) {
0050         qreal value = op(x);
0051         qreal relError = (spline.value(x) - value) / value;
0052 
0053         accum(relError);
0054 
0055         if (relError > 0.10) {
0056             dbgKrita << ppVar(x) << ppVar(op(x)) << ppVar(spline.value(x)) << ppVar(relError);
0057         }
0058     }
0059 
0060     dbgKrita << ppVar(count(accum));
0061     dbgKrita << ppVar(mean(accum));
0062     dbgKrita << ppVar(variance(accum));
0063     dbgKrita << ppVar((min)(accum));
0064     dbgKrita << ppVar((max)(accum));
0065 
0066     qreal maxError = qMax(qAbs((min)(accum)), qAbs((max)(accum)));
0067     QVERIFY(maxError < 0.10); // Error is less than 10%
0068 
0069 }
0070 
0071 void KisBSplinesTest::testEmpty1D()
0072 {
0073     const qreal start = 1.0;
0074     const qreal end = 11.0;
0075     KisBSpline1D spline(start, end, 10, Natural);
0076     // just let it be destructed uninitialized
0077 }
0078 
0079 template <class Spline, class Op>
0080 bool test2DSpline(const Spline &spline, const Op &op, qreal start, qreal end)
0081 {
0082     accumulator_set<qreal, stats<tag::variance, tag::max, tag::min> > accum;
0083 
0084     for (qreal y = start; y < end; y += 0.01) {
0085         for (qreal x = start; x < end; x += 0.01) {
0086             qreal value = op(x, y);
0087             qreal relError = (spline.value(x, y) - value) / value;
0088 
0089             accum(relError);
0090 
0091             if (relError > 0.10) {
0092                 dbgKrita << ppVar(x) << ppVar(y) << ppVar(op(x, y)) << ppVar(spline.value(x, y)) << ppVar(relError);
0093             }
0094         }
0095     }
0096 
0097     dbgKrita << ppVar(count(accum));
0098     dbgKrita << ppVar(mean(accum));
0099     dbgKrita << ppVar(variance(accum));
0100     dbgKrita << ppVar((min)(accum));
0101     dbgKrita << ppVar((max)(accum));
0102 
0103     qreal maxError = qMax(qAbs((min)(accum)), qAbs((max)(accum)));
0104     return maxError < 0.10; // Error is less than 10%
0105 }
0106 
0107 void KisBSplinesTest::test2D()
0108 {
0109     const qreal start = 1.0;
0110     const qreal end = 11.0;
0111 
0112     KisBSpline2D spline(start, end, 10, Natural,
0113                         start, end, 10, Natural);
0114 
0115     FunctionOp op;
0116     spline.initializeSpline(op);
0117 
0118     QVERIFY(test2DSpline(spline, op, start, end));
0119 
0120     dbgKrita << "Resampled";
0121 
0122     QScopedPointer<KisBSpline2D> resampledSpline(
0123         KisBSpline2D::createResampledSpline(spline, 7, 7));
0124 
0125     QVERIFY(test2DSpline(*resampledSpline.data(), op, start, end));
0126 }
0127 
0128 void KisBSplinesTest::testEmpty2D()
0129 {
0130     const qreal start = 1.0;
0131     const qreal end = 11.0;
0132     KisBSpline2D spline(start, end, 10, Natural,
0133                         start, end, 10, Natural);
0134     // just let it be destructed uninitialized
0135 }
0136 
0137 void KisBSplinesTest::testNU2D()
0138 {
0139     const qreal start = 1.0;
0140     const qreal end = 11.0;
0141 
0142     QVector<double> samples;
0143 
0144     double v = start;
0145     int i = 1;
0146     do {
0147         samples << v;
0148         v += (0.1 * i++);
0149     } while (v < end);
0150 
0151     samples << end;
0152 
0153     KisNUBSpline2D spline(samples, Natural,
0154                          samples, Natural);
0155     FunctionOp op;
0156     spline.initializeSpline(op);
0157 
0158     QVERIFY(test2DSpline(spline, op, start, end));
0159 
0160     dbgKrita << "Resampled";
0161 
0162     QScopedPointer<KisBSpline2D> resampledSpline(
0163         KisBSpline2D::createResampledSpline(spline, 7, 7));
0164 
0165     QVERIFY(test2DSpline(*resampledSpline.data(), op, start, end));
0166 
0167 }
0168 
0169 SIMPLE_TEST_MAIN(KisBSplinesTest)