GRASS GIS 7 Programmer's Manual  7.9.dev(2021)-e5379bbd7
gv_quick.c
Go to the documentation of this file.
1 /*!
2  \file lib/ogsf/gv_quick.c
3 
4  \brief OGSF library -
5 
6  GRASS OpenGL gsurf OGSF Library
7 
8  Trying some stuff to draw a quick version of a vector map, to represent
9  it when doing interactive translations.
10 
11  (C) 1999-2008 by the GRASS Development Team
12 
13  This program is free software under the
14  GNU General Public License (>=v2).
15  Read the file COPYING that comes with GRASS
16  for details.
17 
18  \author Bill Brown, USACERL (December 1993)
19  \author Doxygenized by Martin Landa <landa.martin gmail.com> (May 2008)
20  */
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 
25 #include <grass/gis.h>
26 #include <grass/ogsf.h>
27 
28 #include "rowcol.h"
29 
30 /*!
31  \brief target number of desired points to represent entire file
32  */
33 #define TFAST_PTS 800
34 
35 /*!
36  \brief max number of lines desired
37  */
38 #define MFAST_LNS 400
39 
40 static geoline *copy_line(geoline *);
41 static geoline *thin_line(geoline *, float);
42 
43 /*!
44  \brief Copy line
45 
46  \param gln source line (geoline)
47 
48  \return pointer to geoline struct
49  \return on failure
50  */
51 static geoline *copy_line(geoline * gln)
52 {
53  geoline *newln;
54  int i, np;
55 
56  newln = (geoline *) G_malloc(sizeof(geoline)); /* G_fatal_error */
57  if (!newln) {
58  return (NULL);
59  }
60 
61  np = newln->npts = gln->npts;
62 
63  if (2 == (newln->dims = gln->dims)) {
64  newln->p2 = (Point2 *) G_calloc(np, sizeof(Point2)); /* G_fatal_error */
65  if (!newln->p2) {
66  return (NULL);
67  }
68 
69  for (i = 0; i < np; i++) {
70  newln->p2[i][X] = gln->p2[i][X];
71  newln->p2[i][Y] = gln->p2[i][Y];
72  }
73  }
74  else {
75  newln->p3 = (Point3 *) G_calloc(np, sizeof(Point3)); /* G_fatal_error */
76  if (!newln->p3) {
77  return (NULL);
78  }
79 
80  for (i = 0; i < np; i++) {
81  newln->p3[i][X] = gln->p3[i][X];
82  newln->p3[i][Y] = gln->p3[i][Y];
83  newln->p3[i][Z] = gln->p3[i][Z];
84  }
85  }
86 
87  newln->next = NULL;
88 
89  return (newln);
90 }
91 
92 
93 /*!
94  \brief Thin line
95 
96  For now, just eliminate points at regular interval
97 
98  \param gln line (geoline)
99  \param factor
100 
101  \return pointer to geoline struct
102  \return NULL on failure
103  */
104 static geoline *thin_line(geoline * gln, float factor)
105 {
106  geoline *newln;
107  int i, nextp, targp;
108 
109  newln = (geoline *) G_malloc(sizeof(geoline)); /* G_fatal_error */
110  if (!newln) {
111  return (NULL);
112  }
113 
114  targp = (int)(gln->npts / factor);
115 
116  if (targp < 2) {
117  targp = 2;
118  }
119 
120  newln->npts = targp;
121 
122  if (2 == (newln->dims = gln->dims)) {
123  newln->p2 = (Point2 *) G_calloc(targp, sizeof(Point2)); /* G_fatal_error */
124  if (!newln->p2) {
125  return (NULL);
126  }
127 
128  for (i = 0; i < targp; i++) {
129  if (i == targp - 1) {
130  nextp = gln->npts - 1; /* avoid rounding error */
131  }
132  else {
133  nextp = (int)((i * (gln->npts - 1)) / (targp - 1));
134  }
135 
136  newln->p2[i][X] = gln->p2[nextp][X];
137  newln->p2[i][Y] = gln->p2[nextp][Y];
138  }
139  }
140  else {
141  newln->p3 = (Point3 *) G_calloc(targp, sizeof(Point3)); /* G_fatal_error */
142  if (!newln->p3) {
143  return (NULL);
144  }
145 
146  for (i = 0; i < targp; i++) {
147  if (i == targp - 1) {
148  nextp = gln->npts - 1; /* avoid rounding error */
149  }
150  else {
151  nextp = (int)((i * (gln->npts - 1)) / (targp - 1));
152  }
153 
154  newln->p3[i][X] = gln->p3[nextp][X];
155  newln->p3[i][Y] = gln->p3[nextp][Y];
156  newln->p3[i][Z] = gln->p3[nextp][Z];
157  }
158  }
159 
160  newln->next = NULL;
161 
162  return (newln);
163 }
164 
165 /*!
166  \brief Get line width
167 
168  \param gln line (geoline)
169 
170  \return line width
171  */
173 {
174  int n;
175  float length = 0.0;
176 
177  for (n = 0; n < gln->npts - 1; n++) {
178  if (gln->p2) {
179  length += GS_P2distance(gln->p2[n + 1], gln->p2[n]);
180  }
181  else {
182  length += GS_distance(gln->p3[n + 1], gln->p3[n]);
183  }
184  }
185 
186  return (length);
187 }
188 
189 /*!
190  \brief Get number of line vertices
191 
192  \param gln line (geoline)
193 
194  \return number of vertices
195  */
197 {
198  int np = 0;
199  geoline *tln;
200 
201  for (tln = gln; tln; tln = tln->next) {
202  np += tln->npts;
203  }
204 
205  return (np);
206 }
207 
208 /*!
209  \brief Get number of points in vector
210 
211  \param gv vector (geovect)
212 
213  \return number of points
214  */
216 {
217  return (gln_num_points(gv->lines));
218 }
219 
220 
221 
222 /*!
223  \brief Decimate line
224 
225  strategy here: if line has more than average number of points, decimate
226  by eliminating points, otherwise decimate by eliminating shorter lines
227 
228  \param gv vector (geovect)
229 
230  \return
231  */
233 {
234  int T_pts, A_ppl, N_s;
235  float decim_factor, slength[MFAST_LNS], T_slength, A_slength;
236  geoline *gln, *prev;
237 
238  /* should check if already exists & free if != gv->lines */
239  if (TFAST_PTS > (T_pts = gv_num_points(gv))) {
240  gv->fastlines = gv->lines;
241 
242  return (1);
243  }
244 
245  N_s = 0;
246  T_slength = 0.0;
247  decim_factor = T_pts / TFAST_PTS;
248  A_ppl = T_pts / gv->n_lines; /* (int) Average points per line */
249 
250  prev = NULL;
251 
252  for (gln = gv->lines; gln; gln = gln->next) {
253  if (gln->npts > A_ppl) {
254  if (prev) {
255  prev->next = thin_line(gln, decim_factor);
256  prev = prev->next;
257  }
258  else {
259  prev = gv->fastlines = thin_line(gln, decim_factor);
260  }
261  }
262  else if (N_s < MFAST_LNS) {
263  T_slength += slength[N_s++] = gv_line_length(gln);
264  }
265  }
266 
267  A_slength = T_slength / N_s;
268  N_s = 0;
269 
270  for (gln = gv->lines; gln; gln = gln->next) {
271  if (gln->npts <= A_ppl) {
272  if (N_s < MFAST_LNS) {
273  if (slength[N_s++] > A_slength) {
274  if (prev) {
275  prev->next = copy_line(gln);
276  prev = prev->next;
277  }
278  else {
279  prev = gv->fastlines = copy_line(gln);
280  }
281  }
282  }
283  }
284  }
285 
286  G_debug(3, "Decimated lines have %d points.",
288 
289  return (1);
290 }
#define G_malloc(n)
Definition: defs/gis.h:112
float Point2[2]
Definition: ogsf.h:202
struct g_line * next
Definition: ogsf.h:326
float Point3[3]
Definition: ogsf.h:201
geoline * lines
Definition: ogsf.h:340
#define NULL
Definition: ccmath.h:32
#define G_calloc(m, n)
Definition: defs/gis.h:113
#define TFAST_PTS
target number of desired points to represent entire file
Definition: gv_quick.c:33
float GS_distance(float *, float *)
Calculate distance.
Definition: gs_util.c:141
float gv_line_length(geoline *gln)
Get line width.
Definition: gv_quick.c:172
int gv_decimate_lines(geovect *gv)
Decimate line.
Definition: gv_quick.c:232
int n_lines
Definition: ogsf.h:333
Definition: ogsf.h:330
int gln_num_points(geoline *gln)
Get number of line vertices.
Definition: gv_quick.c:196
int gv_num_points(geovect *gv)
Get number of points in vector.
Definition: gv_quick.c:215
int npts
Definition: ogsf.h:318
#define Z
Definition: ogsf.h:139
#define Y
Definition: ogsf.h:138
int dims
Definition: ogsf.h:318
Point3 * p3
Definition: ogsf.h:319
#define X
Definition: ogsf.h:137
#define MFAST_LNS
max number of lines desired
Definition: gv_quick.c:38
float GS_P2distance(float *, float *)
Calculate distance in plane.
Definition: gs_util.c:160
geoline * fastlines
Definition: ogsf.h:341
int G_debug(int, const char *,...) __attribute__((format(printf
Definition: ogsf.h:314
Point2 * p2
Definition: ogsf.h:320