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)