File indexing completed on 2024-04-28 15:14:11

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