GRASS GIS 8 Programmer's Manual  8.2.2dev(2023)-3d2c704037
clean_nodes.c
Go to the documentation of this file.
1 /*!
2  \file lib/vector/Vlib/clean_nodes.c
3 
4  \brief Vector library - Clean boundaries at nodes
5 
6  Higher level functions for reading/writing/manipulating vectors.
7 
8  (C) 2001-2009 by the GRASS Development Team
9 
10  This program is free software under the GNU General Public License
11  (>=v2). Read the file COPYING that comes with GRASS for details.
12 
13  \author Radim Blazek
14  */
15 
16 #include <stdlib.h>
17 #include <grass/vector.h>
18 #include <grass/glocale.h>
19 
20 /*!
21  \brief Clean small angles at nodes.
22 
23  It may happen that even if the angle between 2 boundaries at node
24  is very small, the calculated angle is 0 because of representation
25  error. The map must be built at least on level GV_BUILD_BASE
26 
27  \param Map input map
28  \param otype feature type
29  \param[out] Err vector map where error line segments are written
30 
31  \return number of line modifications
32  */
33 int
35  struct Map_info *Err)
36 {
37  int node, nnodes;
38  int nmodif = 0;
39  struct line_pnts *Points;
40  struct line_cats *SCats, *LCats, *OCats;
41 
42  Points = Vect_new_line_struct();
43  SCats = Vect_new_cats_struct();
44  LCats = Vect_new_cats_struct();
45  OCats = Vect_new_cats_struct();
46 
47  nnodes = Vect_get_num_nodes(Map);
48  for (node = 1; node <= Vect_get_num_nodes(Map); node++) {
49  int i, nlines;
50 
51  if (node <= nnodes)
52  G_percent(node, nnodes, 1);
53  G_debug(3, "node = %d", node);
54  if (!Vect_node_alive(Map, node))
55  continue;
56 
57  while (1) {
58  float angle1 = -100;
59  int line1 = -999; /* value not important, just for debug */
60  int clean = 1;
61 
62  nlines = Vect_get_node_n_lines(Map, node);
63  G_debug(3, "nlines = %d", nlines);
64 
65  for (i = 0; i < nlines; i++) {
66  struct P_line *Line;
67  int line2;
68  float angle2;
69 
70  line2 = Vect_get_node_line(Map, node, i);
71  Line = Map->plus.Line[abs(line2)];
72  if (!Line)
73  continue;
74  G_debug(4, " type = %d", Line->type);
75  if (!(Line->type & (otype & GV_LINES)))
76  continue;
77 
78  angle2 = Vect_get_node_line_angle(Map, node, i);
79  if (angle2 == -9.0)
80  continue; /* Degenerated line */
81 
82  G_debug(4, " line1 = %d angle1 = %e line2 = %d angle2 = %e",
83  line1, angle1, line2, angle2);
84 
85  if (angle2 == angle1) {
86  int j;
87  double length1, length2;
88  int short_line; /* line with shorter end segment */
89  int long_line; /* line with longer end segment */
90  int new_short_line = 0; /* line number of short line after rewrite */
91  int short_type, long_type, type;
92  double x, y, z, nx, ny, nz;
93 
94  G_debug(4, " identical angles -> clean");
95 
96  /* Length of end segments for both lines */
97  Vect_read_line(Map, Points, NULL, abs(line1));
98  if (line1 > 0) {
99  length1 =
100  Vect_points_distance(Points->x[0], Points->y[0],
101  0.0, Points->x[1],
102  Points->y[1], 0.0, 0);
103  }
104  else {
105  int np;
106 
107  np = Points->n_points;
108  length1 =
109  Vect_points_distance(Points->x[np - 1],
110  Points->y[np - 1], 0.0,
111  Points->x[np - 2],
112  Points->y[np - 2], 0.0, 0);
113  }
114 
115  Vect_read_line(Map, Points, NULL, abs(line2));
116  if (line2 > 0) {
117  length2 =
118  Vect_points_distance(Points->x[0], Points->y[0],
119  0.0, Points->x[1],
120  Points->y[1], 0.0, 0);
121  }
122  else {
123  int np;
124 
125  np = Points->n_points;
126  length2 =
127  Vect_points_distance(Points->x[np - 1],
128  Points->y[np - 1], 0.0,
129  Points->x[np - 2],
130  Points->y[np - 2], 0.0, 0);
131  }
132 
133  G_debug(4, " length1 = %f length2 = %f", length1,
134  length2);
135 
136  if (length1 < length2) {
137  short_line = line1;
138  long_line = line2;
139  }
140  else {
141  short_line = line2;
142  long_line = line1;
143  }
144 
145  /* Remove end segment from short_line */
146  short_type =
147  Vect_read_line(Map, Points, SCats, abs(short_line));
148 
149  if (short_line > 0) {
150  x = Points->x[1];
151  y = Points->y[1];
152  z = Points->z[1];
153  Vect_line_delete_point(Points, 0); /* first */
154  }
155  else {
156  x = Points->x[Points->n_points - 2];
157  y = Points->y[Points->n_points - 2];
158  z = Points->z[Points->n_points - 2];
159  Vect_line_delete_point(Points, Points->n_points - 1); /* last */
160  }
161 
162  /* It may happen that it is one line: node could be deleted,
163  * in that case we have to read the node coords first */
164  Vect_get_node_coor(Map, node, &nx, &ny, &nz);
165 
166  if (Points->n_points > 1) {
167  new_short_line =
168  Vect_rewrite_line(Map, abs(short_line),
169  short_type, Points, SCats);
170  }
171  else {
172  Vect_delete_line(Map, abs(short_line));
173  }
174 
175  /* It may happen that it is one line, in that case we have to take the new
176  * short line as long line, orientation is not changed */
177  if (abs(line1) == abs(line2)) {
178  if (long_line > 0)
179  long_line = new_short_line;
180  else
181  long_line = -new_short_line;
182  }
183 
184  /* Add new line (must be before rewrite of long_line otherwise node could be deleted) */
185  long_type =
186  Vect_read_line(Map, NULL, LCats, abs(long_line));
187 
188  Vect_reset_cats(OCats);
189  for (j = 0; j < SCats->n_cats; j++) {
190  Vect_cat_set(OCats, SCats->field[j], SCats->cat[j]);
191  }
192  for (j = 0; j < LCats->n_cats; j++) {
193  Vect_cat_set(OCats, LCats->field[j], LCats->cat[j]);
194  }
195 
196  if (long_type == GV_BOUNDARY || short_type == GV_BOUNDARY) {
197  type = GV_BOUNDARY;
198  }
199  else {
200  type = GV_LINE;
201  }
202 
203  Vect_reset_line(Points);
204  Vect_append_point(Points, nx, ny, nz);
205  Vect_append_point(Points, x, y, z);
206  Vect_write_line(Map, type, Points, OCats);
207 
208  if (Err) {
209  Vect_write_line(Err, type, Points, OCats);
210  }
211 
212  /* Snap long_line to the new short_line end */
213  long_type =
214  Vect_read_line(Map, Points, LCats, abs(long_line));
215  if (long_line > 0) {
216  Points->x[0] = x;
217  Points->y[0] = y;
218  Points->z[0] = z;
219  }
220  else {
221  Points->x[Points->n_points - 1] = x;
222  Points->y[Points->n_points - 1] = y;
223  Points->z[Points->n_points - 1] = z;
224  }
225  Vect_line_prune(Points);
226  if (Points->n_points > 1) {
227  Vect_rewrite_line(Map, abs(long_line), long_type,
228  Points, LCats);
229  }
230  else {
231  Vect_delete_line(Map, abs(long_line));
232  }
233 
234  nmodif += 3;
235  clean = 0;
236 
237  break;
238  }
239 
240  line1 = line2;
241  angle1 = angle2;
242  }
243 
244  if (clean || !Vect_node_alive(Map, node))
245  break;
246  }
247  }
248  G_verbose_message(_("Modifications: %d"), nmodif);
249 
250  return (nmodif);
251 }
plus_t Vect_get_num_nodes(const struct Map_info *)
Get number of nodes in vector map.
Definition: level_two.c:34
Vector geometry.
Definition: dig_structs.h:1574
struct P_line ** Line
Array of vector geometries.
Definition: dig_structs.h:887
off_t Vect_rewrite_line(struct Map_info *, off_t, int, const struct line_pnts *, const struct line_cats *)
Rewrites existing feature (topological level required)
int n_points
Number of points.
Definition: dig_structs.h:1692
int Vect_clean_small_angles_at_nodes(struct Map_info *Map, int otype, struct Map_info *Err)
Clean small angles at nodes.
Definition: clean_nodes.c:34
int Vect_line_prune(struct line_pnts *)
Remove duplicate points, i.e. zero length segments.
Definition: line.c:281
double Vect_points_distance(double, double, double, double, double, double, int)
Calculate distance of 2 points.
Definition: line.c:898
#define NULL
Definition: ccmath.h:32
#define x
int Vect_get_node_n_lines(const struct Map_info *, int)
Get number of lines for node.
Definition: level_two.c:384
Feature category info.
Definition: dig_structs.h:1702
int Vect_get_node_coor(const struct Map_info *, int, double *, double *, double *)
Get node coordinates.
Definition: level_two.c:278
#define GV_LINE
Definition: dig_defines.h:183
double * x
Array of X coordinates.
Definition: dig_structs.h:1680
char type
Line type.
Definition: dig_structs.h:1586
Feature geometry info - coordinates.
Definition: dig_structs.h:1675
int Vect_get_node_line(const struct Map_info *, int, int)
Get line id for node line index.
Definition: level_two.c:401
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition: line.c:45
int n_cats
Number of categories attached to element.
Definition: dig_structs.h:1715
int * cat
Array of categories.
Definition: dig_structs.h:1711
off_t Vect_write_line(struct Map_info *, int, const struct line_pnts *, const struct line_cats *)
Writes a new feature.
float Vect_get_node_line_angle(const struct Map_info *, int, int)
Angle of segment of the line connected to the node.
Definition: level_two.c:417
int Vect_append_point(struct line_pnts *, double, double, double)
Appends one point to the end of a line.
Definition: line.c:149
#define GV_BOUNDARY
Definition: dig_defines.h:184
struct Plus_head plus
Plus info (topology, version, ...)
Definition: dig_structs.h:1286
int Vect_reset_cats(struct line_cats *)
Reset category structure to make sure cats structure is clean to be re-used.
void G_percent(long, long, int)
Print percent complete messages.
Definition: percent.c:62
Vector map info.
Definition: dig_structs.h:1259
double * y
Array of Y coordinates.
Definition: dig_structs.h:1684
int Vect_delete_line(struct Map_info *, off_t)
Delete existing feature (topological level required)
struct line_cats * Vect_new_cats_struct(void)
Creates and initializes line_cats structure.
double * z
Array of Z coordinates.
Definition: dig_structs.h:1688
#define _(str)
Definition: glocale.h:10
int Vect_node_alive(const struct Map_info *, int)
Check if node is alive or dead (topological level required)
int * field
Array of layers (fields)
Definition: dig_structs.h:1707
#define GV_LINES
Definition: dig_defines.h:192
void void G_verbose_message(const char *,...) __attribute__((format(printf
int Vect_read_line(const struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
int G_debug(int, const char *,...) __attribute__((format(printf
void Vect_reset_line(struct line_pnts *)
Reset line.
Definition: line.c:130
int Vect_line_delete_point(struct line_pnts *, int)
Delete point at given index and move all points above down.
Definition: line.c:211
int Vect_cat_set(struct line_cats *, int, int)
Add new field/cat to category structure if doesn&#39;t exist yet.