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
71
int
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
}
AMI_STREAM
Definition
ami_stream.h:153
cur_x
double cur_x
Definition
driver/init.c:30
cur_y
double cur_y
Definition
driver/init.c:31
dig_prune
int dig_prune(struct line_pnts *points, double thresh)
Definition
prune.c:71
t
double t
Definition
r_raster.c:37
stdio.h
line_pnts
Feature geometry info - coordinates.
Definition
dig_structs.h:1639
line_pnts::y
double * y
Array of Y coordinates.
Definition
dig_structs.h:1647
line_pnts::x
double * x
Array of X coordinates.
Definition
dig_structs.h:1643
line_pnts::n_points
int n_points
Number of points.
Definition
dig_structs.h:1655
vector.h
lib
vector
diglib
prune.c
Generated on Mon Sep 14 2026 06:57:45 for GRASS 8 Programmer's Manual by
1.9.8