File indexing completed on 2024-05-12 03:47:52

0001 /*
0002     File                 : nsl_geom_linesim.c
0003     Project              : LabPlot
0004     Description          : NSL geometry line simplification functions
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2016-2019 Stefan Gerlach <stefan.gerlach@uni.kn>
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "nsl_geom_linesim.h"
0011 #include "nsl_common.h"
0012 #include "nsl_geom.h"
0013 #include "nsl_sort.h"
0014 #include "nsl_stats.h"
0015 
0016 const char* nsl_geom_linesim_type_name[] = {i18n("Douglas-Peucker (Number)"),
0017                                             i18n("Douglas-Peucker (Tolerance)"),
0018                                             i18n("Visvalingam-Whyatt"),
0019                                             i18n("Reumann-Witkam"),
0020                                             i18n("Perpendicular Distance"),
0021                                             i18n("n-th Point"),
0022                                             i18n("Radial Distance"),
0023                                             i18n("Interpolation"),
0024                                             i18n("Opheim"),
0025                                             i18n("Lang")};
0026 
0027 /*********** error calculation functions *********/
0028 
0029 double nsl_geom_linesim_positional_error(const double xdata[], const double ydata[], const size_t n, const size_t index[]) {
0030     double dist = 0;
0031     size_t i = 0, j; /* i: index of index[] */
0032     do {
0033         /*for every point not in index[] calculate distance to line*/
0034         /*printf("i=%d (index[i]-index[i+1]=%d-%d)\n", i , index[i], index[i+1]);*/
0035         for (j = 1; j < index[i + 1] - index[i]; j++) {
0036             /*printf("i=%d: j=%d\n", i, j);*/
0037             dist +=
0038                 nsl_geom_point_line_dist(xdata[index[i]], ydata[index[i]], xdata[index[i + 1]], ydata[index[i + 1]], xdata[index[i] + j], ydata[index[i] + j]);
0039             /*printf("dist = %g\n", dist);*/
0040         }
0041         i++;
0042     } while (index[i] != n - 1);
0043 
0044     return dist / (double)n;
0045 }
0046 
0047 double nsl_geom_linesim_positional_squared_error(const double xdata[], const double ydata[], const size_t n, const size_t index[]) {
0048     double dist = 0;
0049     size_t i = 0, j; /* i: index of index[] */
0050     do {
0051         /*for every point not in index[] calculate distance to line*/
0052         /*printf("i=%d (index[i]-index[i+1]=%d-%d)\n", i , index[i], index[i+1]);*/
0053         for (j = 1; j < index[i + 1] - index[i]; j++) {
0054             /*printf("i=%d: j=%d\n", i, j);*/
0055             dist += pow(
0056                 nsl_geom_point_line_dist(xdata[index[i]], ydata[index[i]], xdata[index[i + 1]], ydata[index[i + 1]], xdata[index[i] + j], ydata[index[i] + j]),
0057                 2);
0058             /*printf("dist = %g\n", dist);*/
0059         }
0060         i++;
0061     } while (index[i] != n - 1);
0062 
0063     return dist / (double)n;
0064 }
0065 
0066 double nsl_geom_linesim_area_error(const double xdata[], const double ydata[], const size_t n, const size_t index[]) {
0067     double area = 0;
0068 
0069     size_t i = 0, j; /* i: index of index[] */
0070     do {
0071         /* for every point not in index[] calculate area */
0072         /*printf("i=%d (index[i]-index[i+1]=%d-%d)\n", i , index[i], index[i+1]);*/
0073         for (j = 1; j < index[i + 1] - index[i]; j++) {
0074             /*printf("j=%d: area between %d %d %d\n", j, index[i]+j-1, index[i]+j, index[i+1]);*/
0075             area += nsl_geom_three_point_area(xdata[index[i] + j - 1],
0076                                               ydata[index[i] + j - 1],
0077                                               xdata[index[i] + j],
0078                                               ydata[index[i] + j],
0079                                               xdata[index[i + 1]],
0080                                               ydata[index[i + 1]]);
0081             /*printf("area = %g\n", area);*/
0082         }
0083         i++;
0084     } while (index[i] != n - 1);
0085 
0086     return area / (double)n;
0087 }
0088 
0089 double nsl_geom_linesim_clip_diag_perpoint(const double xdata[], const double ydata[], const size_t n) {
0090     double dx = nsl_stats_maximum(xdata, n, NULL) - nsl_stats_minimum(xdata, n, NULL);
0091     double dy = nsl_stats_maximum(ydata, n, NULL) - nsl_stats_minimum(ydata, n, NULL);
0092     double d = sqrt(dx * dx + dy * dy);
0093 
0094     return d / (double)n; /* per point */
0095 }
0096 
0097 double nsl_geom_linesim_clip_area_perpoint(const double xdata[], const double ydata[], const size_t n) {
0098     double dx = nsl_stats_maximum(xdata, n, NULL) - nsl_stats_minimum(xdata, n, NULL);
0099     double dy = nsl_stats_maximum(ydata, n, NULL) - nsl_stats_minimum(ydata, n, NULL);
0100     double A = dx * dy;
0101 
0102     return A / (double)n; /* per point */
0103 }
0104 
0105 double nsl_geom_linesim_avg_dist_perpoint(const double xdata[], const double ydata[], const size_t n) {
0106     double dist = 0;
0107     size_t i;
0108     for (i = 0; i < n - 1; i++) {
0109         double dx = xdata[i + 1] - xdata[i];
0110         double dy = ydata[i + 1] - ydata[i];
0111         dist += sqrt(dx * dx + dy * dy);
0112     }
0113     dist /= (double)n;
0114 
0115     return dist;
0116 }
0117 
0118 /*********** simplification algorithms *********/
0119 
0120 void nsl_geom_linesim_douglas_peucker_step(const double xdata[],
0121                                            const double ydata[],
0122                                            const size_t start,
0123                                            const size_t end,
0124                                            size_t* nout,
0125                                            const double tol,
0126                                            size_t index[]) {
0127     /*printf("DP: %d - %d\n", start, end);*/
0128 
0129     size_t i, nkey = start;
0130     double maxdist = 0;
0131     /* search for key (biggest perp. distance) */
0132     for (i = start + 1; i < end; i++) {
0133         double dist = nsl_geom_point_line_dist(xdata[start], ydata[start], xdata[end], ydata[end], xdata[i], ydata[i]);
0134         if (dist > maxdist) {
0135             maxdist = dist;
0136             nkey = i;
0137         }
0138     }
0139     /*printf("maxdist = %g @ i = %zu\n", maxdist, nkey);*/
0140 
0141     if (maxdist > tol) {
0142         /*printf("take %d\n", nkey);*/
0143         index[(*nout)++] = nkey;
0144         if (nkey - start > 1)
0145             nsl_geom_linesim_douglas_peucker_step(xdata, ydata, start, nkey, nout, tol, index);
0146         if (end - nkey > 1)
0147             nsl_geom_linesim_douglas_peucker_step(xdata, ydata, nkey, end, nout, tol, index);
0148     }
0149 
0150     /*printf("nout=%d\n", *nout);*/
0151 }
0152 
0153 size_t nsl_geom_linesim_douglas_peucker(const double xdata[], const double ydata[], const size_t n, const double tol, size_t index[]) {
0154     size_t nout = 0;
0155 
0156     /*first point*/
0157     index[nout++] = 0;
0158 
0159     nsl_geom_linesim_douglas_peucker_step(xdata, ydata, 0, n - 1, &nout, tol, index);
0160 
0161     /* last point */
0162     if (index[nout - 1] != n - 1)
0163         index[nout++] = n - 1;
0164 
0165     /* sort array index */
0166     nsl_sort_size_t(index, nout);
0167 
0168     return nout;
0169 }
0170 size_t nsl_geom_linesim_douglas_peucker_auto(const double xdata[], const double ydata[], const size_t n, size_t index[]) {
0171     double tol = nsl_geom_linesim_clip_diag_perpoint(xdata, ydata, n);
0172     return nsl_geom_linesim_douglas_peucker(xdata, ydata, n, tol, index);
0173 }
0174 
0175 /*
0176  * Douglas-Peucker variant:
0177  * The key of all egdes of the current simplified line is calculated and only the
0178  * largest is added. This is repeated until nout is reached.
0179  * */
0180 double nsl_geom_linesim_douglas_peucker_variant(const double xdata[], const double ydata[], const size_t n, const size_t nout, size_t index[]) {
0181     size_t i;
0182     if (nout >= n) { /* use all points */
0183         for (i = 0; i < n; i++)
0184             index[i] = i;
0185         return 0;
0186     }
0187 
0188     /* set first and last point in index (other indizes not initialized) */
0189     size_t ncount = 0;
0190     index[ncount++] = 0;
0191     index[ncount++] = n - 1;
0192 
0193     if (nout <= 2) /* use only first and last point (perp. dist is zero) */
0194         return 0.0;
0195 
0196     double* dist = (double*)malloc(n * sizeof(double));
0197     if (dist == NULL) {
0198         /* printf("nsl_geom_linesim_douglas_peucker_variant(): ERROR allocating memory for 'dist'!\n"); */
0199         return DBL_MAX;
0200     }
0201 
0202     double* maxdist = (double*)malloc(nout * sizeof(double)); /* max dist per edge */
0203     if (maxdist == NULL) {
0204         /* printf("nsl_geom_linesim_douglas_peucker_variant(): ERROR allocating memory for 'maxdist'!\n"); */
0205         free(dist);
0206         return DBL_MAX;
0207     }
0208 
0209     for (i = 0; i < n; i++) { /* initialize  dist */
0210         dist[i] = nsl_geom_point_line_dist(xdata[0], ydata[0], xdata[n - 1], ydata[n - 1], xdata[i], ydata[i]);
0211         /* printf("nsl_geom_linesim_douglas_peucker_variant(): %zu dist = %g\n", i, dist[i]); */
0212     }
0213     for (i = 0; i < nout; i++)
0214         maxdist[i] = 0;
0215 
0216     double newmaxdist = 0;
0217     do {
0218         /* printf("nsl_geom_linesim_douglas_peucker_variant(): NEXT ITERATION\n"); */
0219         size_t key = 0;
0220 
0221         /* find edge of maximum */
0222         size_t maxindex;
0223         nsl_stats_maximum(maxdist, ncount, &maxindex);
0224         /* printf("nsl_geom_linesim_douglas_peucker_variant(): found edge with max dist at index %zu\n", maxindex); */
0225         /*newmaxdist = nsl_stats_maximum(dist, n, &key);*/
0226         newmaxdist = 0;
0227         for (i = index[maxindex] + 1; i < index[maxindex + 1]; i++) {
0228             /* printf("nsl_geom_linesim_douglas_peucker_variant(): iterate i=%zu\n", i); */
0229             if (dist[i] > newmaxdist) {
0230                 newmaxdist = dist[i];
0231                 key = i;
0232             }
0233         }
0234 
0235         /* printf("nsl_geom_linesim_douglas_peucker_variant(): found key %zu (dist = %g)\n", key, newmaxdist); */
0236         ncount++;
0237         dist[key] = 0;
0238 
0239         /* find index of previous key */
0240         size_t previndex = 0;
0241         while (index[previndex + 1] < key)
0242             previndex++;
0243         /* printf("nsl_geom_linesim_douglas_peucker_variant(): previndex = %zu (update keys %zu - %zu)\n", previndex, index[previndex], index[previndex+1]); */
0244 
0245         size_t v;
0246         /* printf("nsl_geom_linesim_douglas_peucker_variant(): ncount = %zu, previndex = %zu\n", ncount, previndex); */
0247         /* update dist[]. no update on last key */
0248         if (ncount < nout) {
0249             /* shift maxdist */
0250             for (v = ncount; v > previndex; v--)
0251                 maxdist[v] = maxdist[v - 1];
0252 
0253             double tmpmax = 0;
0254             for (v = index[previndex] + 1; v < key; v++) {
0255                 /* printf("nsl_geom_linesim_douglas_peucker_variant(): %zu in %zu - %zu", v, index[previndex], key); */
0256                 dist[v] = nsl_geom_point_line_dist(xdata[index[previndex]], ydata[index[previndex]], xdata[key], ydata[key], xdata[v], ydata[v]);
0257                 if (dist[v] > tmpmax)
0258                     tmpmax = dist[v];
0259 
0260                 /* printf(" dist = %g\n", dist[v]); */
0261             }
0262             maxdist[previndex] = tmpmax;
0263 
0264             tmpmax = 0;
0265             for (v = key + 1; v < index[previndex + 1]; v++) {
0266                 /* printf("nsl_geom_linesim_douglas_peucker_variant(): %zu in %zu - %zu", v, key, index[previndex+1]); */
0267                 dist[v] = nsl_geom_point_line_dist(xdata[key], ydata[key], xdata[index[previndex + 1]], ydata[index[previndex + 1]], xdata[v], ydata[v]);
0268                 if (dist[v] > tmpmax)
0269                     tmpmax = dist[v];
0270                 /* printf(" dist = %g\n", dist[v]); */
0271             }
0272             maxdist[previndex + 1] = tmpmax;
0273         }
0274 
0275         /* put into index array */
0276         for (v = ncount; v > previndex + 1; v--)
0277             index[v] = index[v - 1];
0278         index[previndex + 1] = key;
0279     } while (ncount < nout);
0280 
0281     free(maxdist);
0282     free(dist);
0283 
0284     return newmaxdist;
0285 }
0286 
0287 size_t nsl_geom_linesim_nthpoint(const size_t n, const int step, size_t index[]) {
0288     if (step < 1) {
0289         printf("step size must be > 0 (given: %d)\n", step);
0290         return 0;
0291     }
0292 
0293     size_t i, nout = 0;
0294 
0295     /*first point*/
0296     index[nout++] = 0;
0297 
0298     for (i = 1; i < n - 1; i++)
0299         if (i % step == 0)
0300             index[nout++] = i;
0301 
0302     /* last point */
0303     index[nout++] = n - 1;
0304 
0305     return nout;
0306 }
0307 
0308 size_t nsl_geom_linesim_raddist(const double xdata[], const double ydata[], const size_t n, const double tol, size_t index[]) {
0309     size_t i, nout = 0, key = 0;
0310 
0311     /*first point*/
0312     index[nout++] = 0;
0313 
0314     for (i = 1; i < n - 1; i++) {
0315         /* distance to key point */
0316         double dist = nsl_geom_point_point_dist(xdata[i], ydata[i], xdata[key], ydata[key]);
0317         /* distance to last point */
0318         double lastdist = nsl_geom_point_point_dist(xdata[i], ydata[i], xdata[n - 1], ydata[n - 1]);
0319         /*printf("%d: %g %g\n", i, dist, lastdist);*/
0320 
0321         if (dist > tol && lastdist > tol) {
0322             index[nout++] = i;
0323             key = i;
0324         }
0325     }
0326 
0327     /* last point */
0328     index[nout++] = n - 1;
0329 
0330     return nout;
0331 }
0332 size_t nsl_geom_linesim_raddist_auto(const double xdata[], const double ydata[], const size_t n, size_t index[]) {
0333     double tol = 10. * nsl_geom_linesim_clip_diag_perpoint(xdata, ydata, n);
0334     return nsl_geom_linesim_raddist(xdata, ydata, n, tol, index);
0335 }
0336 
0337 size_t nsl_geom_linesim_perpdist(const double xdata[], const double ydata[], const size_t n, const double tol, size_t index[]) {
0338     size_t nout = 0, key = 0, i;
0339 
0340     /*first point*/
0341     index[nout++] = 0;
0342 
0343     for (i = 1; i < n - 1; i++) {
0344         /* distance of point i to line key -- i+1 */
0345         double dist = nsl_geom_point_line_dist(xdata[key], ydata[key], xdata[i + 1], ydata[i + 1], xdata[i], ydata[i]);
0346         /*printf("%d: %g\n", i, dist);*/
0347 
0348         if (dist > tol) { /* take it */
0349             index[nout++] = i;
0350             key = i;
0351             /*printf("%d: take it (key = %d)\n", i, key);*/
0352         } else { /* ignore it */
0353             if (i + 1 < n - 1) /* last point is taken anyway */
0354                 index[nout++] = i + 1; /* take next point in any case */
0355             /*printf("%d: ignore it (key = %d)\n", i, i+1);*/
0356             key = ++i;
0357         }
0358     }
0359 
0360     /* last point */
0361     index[nout++] = n - 1;
0362 
0363     return nout;
0364 }
0365 size_t nsl_geom_linesim_perpdist_auto(const double xdata[], const double ydata[], const size_t n, size_t index[]) {
0366     double tol = nsl_geom_linesim_clip_diag_perpoint(xdata, ydata, n);
0367     return nsl_geom_linesim_perpdist(xdata, ydata, n, tol, index);
0368 }
0369 
0370 size_t nsl_geom_linesim_perpdist_repeat(const double xdata[], const double ydata[], const size_t n, const double tol, const size_t repeat, size_t index[]) {
0371     size_t i, j, nout;
0372     double* xtmp = (double*)malloc(n * sizeof(double));
0373     if (xtmp == NULL) {
0374         printf("nsl_geom_linesim_perpdist_repeat(): ERROR allocating memory for 'xtmp'!\n");
0375         return 0;
0376     }
0377 
0378     double* ytmp = (double*)malloc(n * sizeof(double));
0379     if (ytmp == NULL) {
0380         printf("nsl_geom_linesim_perpdist_repeat(): ERROR allocating memory for 'ytmp'!\n");
0381         free(xtmp);
0382         return 0;
0383     }
0384 
0385     size_t* tmpindex = (size_t*)malloc(n * sizeof(size_t));
0386     if (tmpindex == NULL) {
0387         printf("nsl_geom_linesim_perpdist_repeat(): ERROR allocating memory for 'tmpindex'!\n");
0388         free(xtmp);
0389         free(ytmp);
0390         return 0;
0391     }
0392 
0393     /* first round */
0394     nout = nsl_geom_linesim_perpdist(xdata, ydata, n, tol, index);
0395     /* repeats */
0396     for (i = 0; i < repeat - 1; i++) {
0397         for (j = 0; j < nout; j++) {
0398             xtmp[j] = xdata[index[j]];
0399             ytmp[j] = ydata[index[j]];
0400             tmpindex[j] = index[j];
0401             /*printf("%g %g\n", xtmp[j], ytmp[j]);*/
0402         }
0403         size_t tmpnout = nsl_geom_linesim_perpdist(xtmp, ytmp, nout, tol, tmpindex);
0404         for (j = 0; j < tmpnout; j++) {
0405             index[j] = index[tmpindex[j]];
0406             /*printf("tmpindex[%d]: %d\n", j, tmpindex[j]);*/
0407         }
0408 
0409         if (tmpnout == nout) /* return if nout does not change anymore */
0410             break;
0411         else
0412             nout = tmpnout;
0413     }
0414 
0415     free(tmpindex);
0416     free(xtmp);
0417     free(ytmp);
0418 
0419     return nout;
0420 }
0421 
0422 size_t nsl_geom_linesim_interp(const double xdata[], const double ydata[], const size_t n, const double tol, size_t index[]) {
0423     size_t i, nout = 0;
0424 
0425     /*first  point*/
0426     index[nout++] = 0;
0427 
0428     size_t key = 0;
0429     for (i = 1; i < n - 1; i++) {
0430         /*printf("%d: %d-%d\n", i, key, i+1);*/
0431         double dist = nsl_geom_point_line_dist_y(xdata[key], ydata[key], xdata[i + 1], ydata[i + 1], xdata[i], ydata[i]);
0432         /*printf("%d: dist = %g\n", i, dist);*/
0433         if (dist > tol) {
0434             /*printf("take it %d\n", i);*/
0435             index[nout++] = key = i;
0436         }
0437     }
0438 
0439     /* last point */
0440     index[nout++] = n - 1;
0441 
0442     return nout;
0443 }
0444 size_t nsl_geom_linesim_interp_auto(const double xdata[], const double ydata[], const size_t n, size_t index[]) {
0445     double tol = nsl_geom_linesim_clip_diag_perpoint(xdata, ydata, n);
0446     return nsl_geom_linesim_interp(xdata, ydata, n, tol, index);
0447 }
0448 
0449 size_t nsl_geom_linesim_visvalingam_whyatt(const double xdata[], const double ydata[], const size_t n, const double tol, size_t index[]) {
0450     if (n < 3) /* we need at least three points */
0451         return 0;
0452 
0453     size_t i, nout = n;
0454     double* area = (double*)malloc((n - 2) * sizeof(double)); /* area associated with every point */
0455     if (area == NULL) {
0456         printf("nsl_geom_linesim_visvalingam_whyatt(): ERROR allocating memory!\n");
0457         return 0;
0458     }
0459     for (i = 0; i < n; i++)
0460         index[i] = i;
0461     for (i = 1; i < n - 1; i++)
0462         area[i - 1] = nsl_geom_three_point_area(xdata[i - 1], ydata[i - 1], xdata[i], ydata[i], xdata[i + 1], ydata[i + 1]);
0463 
0464     size_t minindex;
0465     while (nsl_stats_minimum(area, n - 2, &minindex) < tol && nout > 2) {
0466         /* double minarea;
0467         while ( (minarea = nsl_stats_minimum(area, n-2, &minindex)) < tol && nout > 2) { */
0468         /*for (i=0; i < n-2; i++)
0469             if (area[i]<DBL_MAX)
0470                 printf("area[%zu] = %g\n", i, area[i]);
0471         */
0472         /* remove point minindex */
0473         /*printf("removing point %zu (minindex = %zu, minarea = %g) nout=%zu\n", minindex+1, minindex, minarea, nout-1);*/
0474         index[minindex + 1] = 0;
0475         area[minindex] = DBL_MAX;
0476         double tmparea;
0477         /* update area of neigbor points */
0478         size_t before = minindex, after = minindex + 2; /* find index before and after */
0479         while (index[before] == 0 && before > 0)
0480             before--;
0481         while (after < n + 1 && index[after] == 0)
0482             after++;
0483         if (minindex > 0) { /*before */
0484             if (before > 0) {
0485                 size_t beforebefore = before - 1;
0486                 while (index[beforebefore] == 0 && beforebefore > 0)
0487                     beforebefore--;
0488                 /*printf("recalculate area[%zu] from %zu %zu %zu\n", before-1, beforebefore, before, after);*/
0489                 tmparea = nsl_geom_three_point_area(xdata[beforebefore], ydata[beforebefore], xdata[before], ydata[before], xdata[after], ydata[after]);
0490                 if (tmparea > area[before - 1]) /* take largest value of new and old area */
0491                     area[before - 1] = tmparea;
0492             }
0493         }
0494         if (minindex < n - 3) { /* after */
0495             if (after < n - 1) {
0496                 size_t afterafter = after + 1;
0497                 while (afterafter < n - 1 && index[afterafter] == 0)
0498                     afterafter++;
0499                 /*printf("recalculate area[%zu] from %zu %zu %zu\n",after-1, before, after, afterafter);*/
0500                 tmparea = nsl_geom_three_point_area(xdata[before], ydata[before], xdata[after], ydata[after], xdata[afterafter], ydata[afterafter]);
0501                 if (tmparea > area[after - 1]) /* take largest value of new and old area */
0502                     area[after - 1] = tmparea;
0503             }
0504         }
0505         nout--;
0506     };
0507 
0508     /*for(i=0;i<n;i++)
0509         printf("INDEX = %d\n", index[i]);
0510     */
0511 
0512     /* condens index */
0513     i = 1;
0514     size_t newi = 1;
0515     while (newi < n - 1) {
0516         while (index[newi] == 0)
0517             newi++;
0518         index[i++] = index[newi++];
0519     };
0520 
0521     /*for(i=0;i<nout;i++)
0522         printf("INDEX2 = %d\n", index[i]);
0523     */
0524 
0525     free(area);
0526     return nout;
0527 }
0528 size_t nsl_geom_linesim_visvalingam_whyatt_auto(const double xdata[], const double ydata[], const size_t n, size_t index[]) {
0529     double tol = nsl_geom_linesim_clip_area_perpoint(xdata, ydata, n);
0530 
0531     return nsl_geom_linesim_visvalingam_whyatt(xdata, ydata, n, tol, index);
0532 }
0533 
0534 size_t nsl_geom_linesim_reumann_witkam(const double xdata[], const double ydata[], const size_t n, const double tol, size_t index[]) {
0535     size_t i, nout = 0, key = 0, key2 = 1;
0536 
0537     /*first  point*/
0538     index[nout++] = 0;
0539 
0540     for (i = 2; i < n - 1; i++) {
0541         /* distance to line key -- key2 */
0542         double dist = nsl_geom_point_line_dist(xdata[key], ydata[key], xdata[key2], ydata[key2], xdata[i], ydata[i]);
0543         /*printf("%d: %g\n", i, dist);*/
0544 
0545         if (dist > tol) { /* take it */
0546             /*printf("%d: take it\n", i);*/
0547             key = i - 1;
0548             key2 = i;
0549             index[nout++] = i - 1;
0550         }
0551     }
0552 
0553     /* last point */
0554     index[nout++] = n - 1;
0555 
0556     return nout;
0557 }
0558 size_t nsl_geom_linesim_reumann_witkam_auto(const double xdata[], const double ydata[], const size_t n, size_t index[]) {
0559     double tol = nsl_geom_linesim_clip_diag_perpoint(xdata, ydata, n);
0560     return nsl_geom_linesim_reumann_witkam(xdata, ydata, n, tol, index);
0561 }
0562 
0563 size_t nsl_geom_linesim_opheim(const double xdata[], const double ydata[], const size_t n, const double mintol, const double maxtol, size_t index[]) {
0564     size_t i, nout = 0, key = 0, key2;
0565 
0566     /*first  point*/
0567     index[nout++] = 0;
0568 
0569     for (i = 1; i < n - 1; i++) {
0570         double dist, perpdist;
0571         do { /* find key2 */
0572             dist = nsl_geom_point_point_dist(xdata[key], ydata[key], xdata[i], ydata[i]);
0573             /*printf("dist = %g: %d-%d\n", dist, key, i);*/
0574             i++;
0575         } while (dist < mintol);
0576         i--;
0577         if (key == i - 1) /*i+1 outside mintol */
0578             key2 = i;
0579         else
0580             key2 = i - 1; /* last point inside */
0581         /*printf("found key2 @%d\n", key2);*/
0582 
0583         do { /* find next key */
0584             dist = nsl_geom_point_point_dist(xdata[key], ydata[key], xdata[i], ydata[i]);
0585             perpdist = nsl_geom_point_line_dist(xdata[key], ydata[key], xdata[key2], ydata[key2], xdata[i], ydata[i]);
0586             /*printf("dist = %g, perpdist=%g: %d\n", dist, perpdist, i);*/
0587             i++;
0588         } while (dist < maxtol && perpdist < mintol);
0589         i--;
0590         if (key == i - 1) /*i+1 outside */
0591             key = i;
0592         else {
0593             key = i - 1;
0594             i--;
0595         }
0596         /*printf("new key: %d\n", key);*/
0597         index[nout++] = key;
0598     }
0599 
0600     /* last point */
0601     if (index[nout - 1] != n - 1)
0602         index[nout++] = n - 1;
0603 
0604     return nout;
0605 }
0606 size_t nsl_geom_linesim_opheim_auto(const double xdata[], const double ydata[], const size_t n, size_t index[]) {
0607     double mintol = 10. * nsl_geom_linesim_clip_diag_perpoint(xdata, ydata, n);
0608     /* TODO: calculate max tolerance ? */
0609     double maxtol = 5. * mintol;
0610 
0611     return nsl_geom_linesim_opheim(xdata, ydata, n, mintol, maxtol, index);
0612 }
0613 
0614 size_t nsl_geom_linesim_lang(const double xdata[], const double ydata[], const size_t n, const double tol, const size_t region, size_t index[]) {
0615     size_t i, j, nout = 0, key = 0;
0616 
0617     /*first  point*/
0618     index[nout++] = 0;
0619 
0620     double dist, maxdist;
0621     for (i = 1; i < n - 1; i++) {
0622         size_t tmpregion = region;
0623         if (key + tmpregion > n - 1) /* end of data set */
0624             tmpregion = n - 1 - key;
0625 
0626         do {
0627             maxdist = 0;
0628             for (j = 1; j < tmpregion; j++) {
0629                 dist = nsl_geom_point_line_dist(xdata[key], ydata[key], xdata[key + tmpregion], ydata[key + tmpregion], xdata[key + j], ydata[key + j]);
0630                 /*printf("%d: dist (%d to %d-%d) = %g\n", j, key+j, key, key+tmpregion, dist);*/
0631                 if (dist > maxdist)
0632                     maxdist = dist;
0633             }
0634             /*printf("tol = %g maxdist = %g\n", tol, maxdist);*/
0635             tmpregion--;
0636             /*printf("region = %d\n", tmpregion);*/
0637         } while (maxdist > tol && tmpregion > 0);
0638         i += tmpregion;
0639         index[nout++] = key = i;
0640         /*printf("take it (%d) key=%d\n", i, key);*/
0641     }
0642 
0643     /* last point */
0644     if (index[nout - 1] != n - 1)
0645         index[nout++] = n - 1;
0646 
0647     return nout;
0648 }
0649 size_t nsl_geom_linesim_lang_auto(const double xdata[], const double ydata[], const size_t n, size_t index[]) {
0650     double tol = nsl_geom_linesim_clip_diag_perpoint(xdata, ydata, n);
0651     /* TODO: calculate search region */
0652     size_t region = 0;
0653     printf("nsl_geom_linesim_lang_auto(): Not implemented yet\n");
0654 
0655     return nsl_geom_linesim_lang(xdata, ydata, n, tol, region, index);
0656 }