GRASS 8 Programmer's Manual 8.6.0dev(2026)-4bb960b182
Loading...
Searching...
No Matches
prune.c
Go to the documentation of this file.
1/*****************************************************************************
2 *
3 * MODULE: Vector library
4 *
5 * AUTHOR(S): Original author CERL, probably Dave Gerdes.
6 * Update to GRASS 5.7 Radim Blazek.
7 *
8 * PURPOSE: Lower level functions for reading/writing/manipulating vectors.
9 *
10 * SPDX-FileCopyrightText: 2001 GRASS Development Team
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 *
13 *****************************************************************************/
14
15/* @(#)prune.c 3.0 2/19/98 */
16/* by Michel Wurtz for GRASS 4.2.1 - <mw@engees.u-strasbg.fr>
17 * This is a complete rewriting of the previous dig_prune subroutine.
18 * The goal remains : it resamples a dense string of x,y coordinates to
19 * produce a set of coordinates that approaches hand digitizing.
20 * That is, the density of points is very low on straight lines, and
21 * highest on tight curves.
22 *
23 * The algorithm used is very different, and based on the suppression
24 * of intermediate points, when they are closer than thresh from a
25 * moving straight line.
26 *
27 * The distance between a point M -> ->
28 * and a AD segment is given || AM ^ AD ||
29 * by the following formula : d = ---------------
30 * ->
31 * || AD ||
32 *
33 * -> -> ->
34 * When comparing || AM ^ AD || and t = thresh * || AD ||
35 *
36 * -> -> -> ->
37 * we call sqdist = | AM ^ AD | = | OA ^ OM + beta |
38 *
39 * -> ->
40 * with beta = OA ^ OD
41 *
42 * The implementation is based on an old integer routine (optimised
43 * for machine without math coprocessor), itself inspired by a PL/1
44 * routine written after a fortran program on some prehistoric
45 * hardware (IBM 360 probably). Yeah, I'm older than before :-)
46 *
47 * The algorithm used doesn't eliminate "duplicate" points (following
48 * points with same coordinates). So we should clean the set of points
49 * before. As a side effect, dig_prune can be called with a null thresh
50 * value. In this case only cleaning is made. The command v.prune is to
51 * be modified accordingly.
52 *
53 * Another important note : Don't try too big threshold, this subroutine
54 * may produce strange things with some pattern (mainly loops, or crossing
55 * of level curves): Try the set { 0,0 -5,0 -4,10 -6,20 -5,30 -5,20 10,10}
56 * with a thershold of 5. This isn't a programmation, but a conceptal bug ;-)
57 *
58 * Input parameters :
59 * points->x, ->y - double precision sets of coordinates.
60 * points->n_points - the total number of points in the set.
61 * thresh - the distance that a string must wander from a straight
62 * line before another point is selected.
63 *
64 * Value returned : - the final number of points in the pruned set.
65 */
66
67#include <stdio.h>
68#include <grass/vector.h>
69#include <math.h>
70
71int dig_prune(struct line_pnts *points, double thresh)
72{
73 double *ox, *oy, *nx, *ny;
74 double cur_x, cur_y;
75 int o_num;
76 int n_num; /* points left */
77 int at_num;
78 int ij = 0, /* position of farthest point */
79 ja, jd, i, j, k, n, inu, it; /* indicateur de parcours du segment */
80
81 double sqdist; /* square of distance */
82 double fpdist; /* square of distance from chord to farthest point */
83 double t, beta; /* as explained in commented algorithm */
84
85 double dx, dy; /* temporary variables */
86
87 double sx[18], sy[18]; /* temporary table for processing points */
88 int nt[17], nu[17];
89
90 /* nothing to do if less than 3 points ! */
91 if (points->n_points <= 2)
92 return (points->n_points);
93
94 ox = points->x;
95 oy = points->y;
96 nx = points->x;
97 ny = points->y;
98
99 o_num = points->n_points;
100 n_num = 0;
101
102 /* Eliminate duplicate points */
103
104 at_num = 0;
105 while (at_num < o_num) {
106 if (nx != ox) {
107 *nx = *ox++;
108 *ny = *oy++;
109 }
110 else {
111 ox++;
112 oy++;
113 }
114 cur_x = *nx++;
115 cur_y = *ny++;
116 n_num++;
117 at_num++;
118
119 while (*ox == cur_x && *oy == cur_y) {
120 if (at_num == o_num)
121 break;
122 at_num++;
123 ox++;
124 oy++;
125 }
126 }
127
128 /* Return if less than 3 points left. When all points are identical,
129 * output only one point (is this valid for calling function ?) */
130
131 if (n_num <= 2)
132 return n_num;
133
134 if (thresh == 0.0) /* Thresh is null, nothing more to do */
135 return n_num;
136
137 /* some (re)initialisations */
138
139 o_num = n_num;
140 ox = points->x;
141 oy = points->y;
142
143 sx[0] = ox[0];
144 sy[0] = oy[0];
145 n_num = 1;
146 at_num = 2;
147 k = 1;
148 sx[1] = ox[1];
149 sy[1] = oy[1];
150 nu[0] = 9;
151 nu[1] = 0;
152 inu = 2;
153
154 while (at_num < o_num) { /* Position of last point to be */
155 if (o_num - at_num > 14) /* processed in a segment. */
156 n = at_num + 9; /* There must be at least 6 points */
157 else /* in the current segment. */
158 n = o_num;
159 sx[0] = sx[nu[1]]; /* Last point written becomes */
160 sy[0] = sy[nu[1]]; /* first of new segment. */
161 if (inu >
162 1) { /* One point was keeped in the */ /* previous segment : */
163 sx[1] = sx[k]; /* Last point of the old segment */
164 sy[1] = sy[k]; /* becomes second of the new one. */
165 k = 1;
166 }
167 else { /* No point keeped : farthest point */
168 sx[1] = sx[ij]; /* is loaded in second position */
169 sy[1] = sy[ij]; /* to avoid cutting lines with */
170 sx[2] = sx[k]; /* small cuvature. */
171 sy[2] = sy[k]; /* First point of previous segment */
172 k = 2; /* becomes the third one. */
173 }
174 /* Loading remaining points */
175 for (j = at_num; j < n; j++) {
176 k++;
177 sx[k] = ox[j];
178 sy[k] = oy[j];
179 }
180
181 jd = 0;
182 ja = k;
183 nt[0] = 0;
184 nu[0] = k;
185 inu = 0;
186 it = 0;
187 for (;;) {
188 if (jd + 1 == ja) /* Exploration of segment terminated */
189 goto endseg;
190
191 dx = sx[ja] - sx[jd];
192 dy = sy[ja] - sy[jd];
193 t = thresh * hypot(dx, dy);
194 beta = sx[jd] * sy[ja] - sx[ja] * sy[jd];
195
196 /* Initializing ij, we don't take 0 as initial value
197 ** for fpdist, in case ja and jd are the same
198 */
199 ij = (ja + jd + 1) >> 1;
200 fpdist = 1.0;
201
202 for (j = jd + 1; j < ja; j++) {
203 sqdist = fabs(dx * sy[j] - dy * sx[j] + beta);
204 if (sqdist > fpdist) {
205 ij = j;
206 fpdist = sqdist;
207 }
208 }
209 if (fpdist >
210 t) { /* We found a point to be keeped */ /* Restart from
211 farthest point */
212 jd = ij;
213 nt[++it] = ij;
214 }
215 else
216 endseg: { /* All points are inside threshold. */
217 /* Former start becomes new end */
218 nu[++inu] = jd;
219 if (--it < 0)
220 break;
221 ja = jd;
222 jd = nt[it];
223 }
224 }
225 for (j = inu - 1; j > 0; j--) { /* Copy of segment's keeped points */
226 i = nu[j];
227 ox[n_num] = sx[i];
228 oy[n_num] = sy[i];
229 n_num++;
230 }
231 at_num = n;
232 }
233 i = nu[0];
234 ox[n_num] = sx[i];
235 oy[n_num] = sy[i];
236 n_num++;
237 return n_num;
238}
double cur_x
Definition driver/init.c:30
double cur_y
Definition driver/init.c:31
int dig_prune(struct line_pnts *points, double thresh)
Definition prune.c:71
double t
Definition r_raster.c:37
Feature geometry info - coordinates.
double * y
Array of Y coordinates.
double * x
Array of X coordinates.
int n_points
Number of points.