File indexing completed on 2024-05-05 03:48:44

0001 /*
0002     File                 : NSLGeomTest.cpp
0003     Project              : LabPlot
0004     Description          : NSL Tests for geometric functions
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2019 Stefan Gerlach <stefan.gerlach@uni.kn>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "NSLGeomTest.h"
0012 
0013 extern "C" {
0014 #include "backend/nsl/nsl_geom.h"
0015 #include "backend/nsl/nsl_geom_linesim.h"
0016 }
0017 
0018 void NSLGeomTest::initTestCase() {
0019     const QString currentDir = QLatin1String(__FILE__);
0020     m_dataDir = currentDir.left(currentDir.lastIndexOf(QDir::separator())) + QDir::separator() + QLatin1String("data") + QDir::separator();
0021 }
0022 
0023 // ##############################################################################
0024 // #################  line sim test
0025 // ##############################################################################
0026 
0027 void NSLGeomTest::testDist() {
0028     double dist = nsl_geom_point_point_dist(0, 0, 1, 1);
0029     QCOMPARE(dist, M_SQRT2);
0030     dist = nsl_geom_point_point_dist(1, 2, 2, 1);
0031     QCOMPARE(dist, M_SQRT2);
0032     dist = nsl_geom_point_point_dist(-1, -2, 2, 2);
0033     QCOMPARE(dist, 5.);
0034 
0035     dist = nsl_geom_point_line_dist(0, 0, 1, 0, .5, 1);
0036     QCOMPARE(dist, 1.);
0037     dist = nsl_geom_point_line_dist(0, 0, 1, 0, 0, 1);
0038     QCOMPARE(dist, 1.);
0039     dist = nsl_geom_point_line_dist(0, 0, 1, 0, 1, 1);
0040     QCOMPARE(dist, 1.);
0041     dist = nsl_geom_point_line_dist(0, 0, 1, 1, 0, 1);
0042     QCOMPARE(dist, M_SQRT1_2);
0043     dist = nsl_geom_point_line_dist(0, 0, 1, 1, 1, 0);
0044     QCOMPARE(dist, M_SQRT1_2);
0045 
0046     // TODO: nsl_geom_point_line_dist_y
0047     // TODO: nsl_geom_three_point_area
0048 
0049     dist = nsl_geom_point_point_dist3(0, 0, 0, 1, 1, 1);
0050     QCOMPARE(dist, M_SQRT3);
0051     dist = nsl_geom_point_point_dist3(-1, -1, 1, 1, 1, 1);
0052     QCOMPARE(dist, 2. * M_SQRT2);
0053 }
0054 
0055 void NSLGeomTest::testLineSim() {
0056     const double xdata[] = {1, 2, 2.5, 3, 4, 7, 9, 11, 13, 14};
0057     const double ydata[] = {1, 1, 1, 3, 4, 7, 8, 12, 13, 13};
0058     const size_t n = 10;
0059 
0060     double atol = nsl_geom_linesim_clip_diag_perpoint(xdata, ydata, n);
0061     printf("automatic tol clip_diag_perpoint = %.15g\n", atol);
0062     QCOMPARE(atol, 1.76918060129541);
0063     atol = nsl_geom_linesim_clip_area_perpoint(xdata, ydata, n);
0064     printf("automatic tol clip_area_perpoint = %.15g\n", atol);
0065     QCOMPARE(atol, 15.6);
0066     atol = nsl_geom_linesim_avg_dist_perpoint(xdata, ydata, n);
0067     printf("automatic tol avg_dist = %.15g\n", atol);
0068     QCOMPARE(atol, 1.91626789723004);
0069 
0070     size_t index[n], i;
0071     const double tol = 0.6;
0072     const size_t result[] = {0, 2, 3, 6, 7, 9};
0073     printf("* Simplification (Douglas Peucker)\n");
0074     size_t nout = nsl_geom_linesim_douglas_peucker(xdata, ydata, n, tol, index);
0075     double perr = nsl_geom_linesim_positional_squared_error(xdata, ydata, n, index);
0076     double aerr = nsl_geom_linesim_area_error(xdata, ydata, n, index);
0077     printf("pos. error = %.15g, area error = %.15g\n", perr, aerr);
0078     QCOMPARE(nout, 6uL);
0079     QCOMPARE(perr, 0.0378688524590164);
0080     QCOMPARE(aerr, 0.25);
0081 
0082     for (i = 0; i < nout; ++i)
0083         QCOMPARE(index[i], result[i]);
0084 
0085     const size_t no = 6;
0086     printf("* Simplification (Douglas Peucker variant) nout = %zu\n", no);
0087     double tolout = nsl_geom_linesim_douglas_peucker_variant(xdata, ydata, n, no, index);
0088     perr = nsl_geom_linesim_positional_squared_error(xdata, ydata, n, index);
0089     aerr = nsl_geom_linesim_area_error(xdata, ydata, n, index);
0090     printf("tolout = %.15g, pos. error = %.15g, area error = %.15g)\n", tolout, perr, aerr);
0091     QCOMPARE(tolout, 0.994505452921406);
0092     QCOMPARE(perr, 0.0378688524590164);
0093     QCOMPARE(aerr, 0.25);
0094 
0095     for (i = 0; i < no; ++i)
0096         QCOMPARE(index[i], result[i]);
0097 
0098     const size_t np = 2;
0099     const size_t result2[] = {0, 2, 4, 6, 8, 9};
0100     printf("* N-th point\n");
0101     nout = nsl_geom_linesim_nthpoint(n, np, index);
0102     perr = nsl_geom_linesim_positional_squared_error(xdata, ydata, n, index);
0103     aerr = nsl_geom_linesim_area_error(xdata, ydata, n, index);
0104     printf("pos. error = %.15g, area error = %.15g\n", perr, aerr);
0105     QCOMPARE(nout, 6uL);
0106     QCOMPARE(perr, 0.129756097560976);
0107     QCOMPARE(aerr, 0.525);
0108 
0109     for (i = 0; i < nout; ++i)
0110         QCOMPARE(index[i], result2[i]);
0111 
0112     const double tol2 = 1.5;
0113     const size_t result3[] = {0, 3, 5, 6, 7, 9};
0114     printf("* Radial distance (tol = %g)\n", tol2);
0115     nout = nsl_geom_linesim_raddist(xdata, ydata, n, tol2, index);
0116     perr = nsl_geom_linesim_positional_squared_error(xdata, ydata, n, index);
0117     aerr = nsl_geom_linesim_area_error(xdata, ydata, n, index);
0118     printf("pos. error = %.15g, area error = %.15g\n", perr, aerr);
0119     QCOMPARE(nout, 6uL);
0120     QCOMPARE(perr, 0.1725);
0121     QCOMPARE(aerr, 0.2);
0122 
0123     for (i = 0; i < nout; ++i)
0124         QCOMPARE(index[i], result3[i]);
0125 
0126     const double tol3 = 0.5;
0127     const size_t repeat = 3;
0128     const size_t result4[] = {0, 2, 4, 6, 7, 9};
0129     printf("* Perpendicular distance (repeat = %zu)\n", repeat);
0130     nout = nsl_geom_linesim_perpdist_repeat(xdata, ydata, n, tol3, repeat, index);
0131     perr = nsl_geom_linesim_positional_squared_error(xdata, ydata, n, index);
0132     aerr = nsl_geom_linesim_area_error(xdata, ydata, n, index);
0133     printf("pos. error = %.15g, area error = %.15g\n", perr, aerr);
0134     QCOMPARE(nout, 6uL);
0135     QCOMPARE(perr, 0.0519512195121951);
0136     QCOMPARE(aerr, 0.275);
0137 
0138     for (i = 0; i < nout; ++i)
0139         QCOMPARE(index[i], result4[i]);
0140 
0141     const double tol4 = 0.7;
0142     printf("* Y distance (interpolation)\n");
0143     nout = nsl_geom_linesim_interp(xdata, ydata, n, tol4, index);
0144     perr = nsl_geom_linesim_positional_squared_error(xdata, ydata, n, index);
0145     aerr = nsl_geom_linesim_area_error(xdata, ydata, n, index);
0146     printf("pos. error = %.15g, area error = %.15g\n", perr, aerr);
0147     QCOMPARE(nout, 6uL);
0148     QCOMPARE(perr, 0.0378688524590164);
0149     QCOMPARE(aerr, 0.25);
0150 
0151     for (i = 0; i < nout; ++i)
0152         QCOMPARE(index[i], result[i]);
0153 
0154     const double tol5 = 1.6;
0155     printf("* minimum area (Visvalingam-Whyatt)\n");
0156     nout = nsl_geom_linesim_visvalingam_whyatt(xdata, ydata, n, tol5, index);
0157     perr = nsl_geom_linesim_positional_squared_error(xdata, ydata, n, index);
0158     aerr = nsl_geom_linesim_area_error(xdata, ydata, n, index);
0159     printf("pos. error = %.15g, area error = %.15g\n", perr, aerr);
0160     QCOMPARE(nout, 6uL);
0161     QCOMPARE(perr, 0.1725);
0162     QCOMPARE(aerr, 0.2);
0163 
0164     // nout can be up to 10 when third arg of nsl_geom_linesim_visvalingam_whyatt() is 10
0165     for (i = 0; i < std::min(nout, (size_t)6uL); ++i)
0166         QCOMPARE(index[i], result3[i]);
0167 
0168     const size_t result5[] = {0, 2, 3, 5, 6, 7, 9};
0169     printf("* Perp. distance (Reumann-Witkam)\n");
0170     nout = nsl_geom_linesim_reumann_witkam(xdata, ydata, n, tol3, index);
0171     perr = nsl_geom_linesim_positional_squared_error(xdata, ydata, n, index);
0172     aerr = nsl_geom_linesim_area_error(xdata, ydata, n, index);
0173     printf("pos. error = %.15g, area error = %.15g\n", perr, aerr);
0174     QCOMPARE(nout, 7uL);
0175     QCOMPARE(perr, 0.01);
0176     QCOMPARE(aerr, 0.05);
0177 
0178     for (i = 0; i < nout; ++i)
0179         QCOMPARE(index[i], result5[i]);
0180 
0181     const double mintol = 2.0;
0182     const double maxtol = 7.0;
0183     printf("* Perp. distance (Opheim)\n");
0184     nout = nsl_geom_linesim_opheim(xdata, ydata, n, mintol, maxtol, index);
0185     perr = nsl_geom_linesim_positional_squared_error(xdata, ydata, n, index);
0186     aerr = nsl_geom_linesim_area_error(xdata, ydata, n, index);
0187     printf("pos. error = %.15g, area error = %.15g\n", perr, aerr);
0188     QCOMPARE(nout, 6uL);
0189     QCOMPARE(perr, 0.129756097560976);
0190     QCOMPARE(aerr, 0.525);
0191 
0192     for (i = 0; i < nout; ++i)
0193         QCOMPARE(index[i], result2[i]);
0194 
0195     const size_t region = 5;
0196     printf("* Simplification (Lang)\n");
0197     nout = nsl_geom_linesim_lang(xdata, ydata, n, tol3, region, index);
0198     perr = nsl_geom_linesim_positional_squared_error(xdata, ydata, n, index);
0199     aerr = nsl_geom_linesim_area_error(xdata, ydata, n, index);
0200     printf("pos. error = %.15g, area error = %.15g\n", perr, aerr);
0201     QCOMPARE(nout, 6uL);
0202     QCOMPARE(perr, 0.0519512195121951);
0203     QCOMPARE(aerr, 0.275);
0204 
0205     for (i = 0; i < nout; ++i)
0206         QCOMPARE(index[i], result4[i]);
0207 }
0208 
0209 #ifdef _MSC_VER // crashes on Windows
0210 void NSLGeomTest::testLineSimMorse() {
0211 }
0212 #else
0213 void NSLGeomTest::testLineSimMorse() {
0214     printf("NSLGeomTest::testLineSimMorse()\n");
0215 
0216     const QString fileName = m_dataDir + QStringLiteral("morse_code.dat");
0217     FILE* file;
0218     if ((file = fopen(fileName.toLocal8Bit().constData(), "r")) == nullptr) {
0219         printf("ERROR reading %s. Giving up.\n", fileName.toLocal8Bit().constData());
0220         return;
0221     }
0222 
0223     const int N = 152000;
0224     const int NOUT = 15200;
0225 
0226     printf("NSLGeomTest::testLineSimMorse(): allocating space for reading data\n");
0227     QScopedArrayPointer<double> xdata(new double[N]);
0228     QScopedArrayPointer<double> ydata(new double[N]);
0229 
0230     printf("NSLGeomTest::testLineSimMorse(): reading data from file\n");
0231     size_t i;
0232     for (i = 0; i < N; i++) {
0233         int num = fscanf(file, "%lf %lf", &xdata[i], &ydata[i]);
0234         if (num != 2) { // failed to read two values
0235             printf("ERROR reading data\n");
0236             fclose(file);
0237             return;
0238         }
0239     }
0240     fclose(file);
0241 
0242     double atol = nsl_geom_linesim_clip_diag_perpoint(xdata.data(), ydata.data(), N);
0243     printf("automatic tol clip_diag_perpoint = %.15g\n", atol);
0244     QCOMPARE(atol, 0.999993446759985);
0245     atol = nsl_geom_linesim_clip_area_perpoint(xdata.data(), ydata.data(), N);
0246     printf("automatic tol clip_area_perpoint = %.15g\n", atol);
0247     QCOMPARE(atol, 34.4653732526316);
0248     atol = nsl_geom_linesim_avg_dist_perpoint(xdata.data(), ydata.data(), N);
0249     printf("automatic tol avg_dist = %.15g\n", atol);
0250     QCOMPARE(atol, 4.72091524721907);
0251 
0252     printf("* Simplification (Douglas Peucker variant) nout = %d\n", NOUT);
0253 
0254     double tolout;
0255     size_t index[N];
0256     QBENCHMARK {
0257         tolout = nsl_geom_linesim_douglas_peucker_variant(xdata.data(), ydata.data(), N, NOUT, index);
0258         QCOMPARE(tolout, 11.5280857733246);
0259     }
0260 
0261     double perr = nsl_geom_linesim_positional_squared_error(xdata.data(), ydata.data(), N, index);
0262     double aerr = nsl_geom_linesim_area_error(xdata.data(), ydata.data(), N, index);
0263     printf("maxtol = %.15g (pos. error = %.15g, area error = %.15g)\n", tolout, perr, aerr);
0264     QCOMPARE(perr, 11.9586266895937);
0265     QCOMPARE(aerr, 17.558046450762);
0266 }
0267 #endif
0268 
0269 // ##############################################################################
0270 // #################  performance
0271 // ##############################################################################
0272 
0273 QTEST_MAIN(NSLGeomTest)