GRASS GIS 8 Programmer's Manual  8.5.0dev(2024)-602118adcc
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 Vect_clean_small_angles_at_nodes(struct Map_info *Map, int otype,
34  struct Map_info *Err)
35 {
36  int node, nnodes;
37  int nmodif = 0;
38  struct line_pnts *Points;
39  struct line_cats *SCats, *LCats, *OCats;
40 
41  Points = Vect_new_line_struct();
42  SCats = Vect_new_cats_struct();
43  LCats = Vect_new_cats_struct();
44  OCats = Vect_new_cats_struct();
45 
46  nnodes = Vect_get_num_nodes(Map);
47  for (node = 1; node <= Vect_get_num_nodes(Map); node++) {
48  int i, nlines;
49 
50  if (node <= nnodes)
51  G_percent(node, nnodes, 1);
52  G_debug(3, "node = %d", node);
53  if (!Vect_node_alive(Map, node))
54  continue;
55 
56  while (1) {
57  float angle1 = -100;
58  int line1 = -999; /* value not important, just for debug */
59  int clean = 1;
60 
61  nlines = Vect_get_node_n_lines(Map, node);
62  G_debug(3, "nlines = %d", nlines);
63 
64  for (i = 0; i < nlines; i++) {
65  struct P_line *Line;
66  int line2;
67  float angle2;
68 
69  line2 = Vect_get_node_line(Map, node, i);
70  Line = Map->plus.Line[abs(line2)];
71  if (!Line)
72  continue;
73  G_debug(4, " type = %d", Line->type);
74  if (!(Line->type & (otype & GV_LINES)))
75  continue;
76 
77  angle2 = Vect_get_node_line_angle(Map, node, i);
78  if (angle2 == -9.0)
79  continue; /* Degenerated line */
80 
81  G_debug(4, " line1 = %d angle1 = %e line2 = %d angle2 = %e",
82  line1, angle1, line2, angle2);
83 
84  if (angle2 == angle1) {
85  int j;
86  double length1, length2;
87  int short_line; /* line with shorter end segment */
88  int long_line; /* line with longer end segment */
89  int new_short_line =
90  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 = Vect_points_distance(
100  Points->x[0], Points->y[0], 0.0, Points->x[1],
101  Points->y[1], 0.0, 0);
102  }
103  else {
104  int np;
105 
106  np = Points->n_points;
107  length1 = Vect_points_distance(
108  Points->x[np - 1], Points->y[np - 1], 0.0,
109  Points->x[np - 2], Points->y[np - 2], 0.0, 0);
110  }
111 
112  Vect_read_line(Map, Points, NULL, abs(line2));
113  if (line2 > 0) {
114  length2 = Vect_points_distance(
115  Points->x[0], Points->y[0], 0.0, Points->x[1],
116  Points->y[1], 0.0, 0);
117  }
118  else {
119  int np;
120 
121  np = Points->n_points;
122  length2 = Vect_points_distance(
123  Points->x[np - 1], Points->y[np - 1], 0.0,
124  Points->x[np - 2], Points->y[np - 2], 0.0, 0);
125  }
126 
127  G_debug(4, " length1 = %f length2 = %f", length1, length2);
128 
129  if (length1 < length2) {
130  short_line = line1;
131  long_line = line2;
132  }
133  else {
134  short_line = line2;
135  long_line = line1;
136  }
137 
138  /* Remove end segment from short_line */
139  short_type =
140  Vect_read_line(Map, Points, SCats, abs(short_line));
141 
142  if (short_line > 0) {
143  x = Points->x[1];
144  y = Points->y[1];
145  z = Points->z[1];
146  Vect_line_delete_point(Points, 0); /* first */
147  }
148  else {
149  x = Points->x[Points->n_points - 2];
150  y = Points->y[Points->n_points - 2];
151  z = Points->z[Points->n_points - 2];
152  Vect_line_delete_point(Points,
153  Points->n_points - 1); /* last */
154  }
155 
156  /* It may happen that it is one line: node could be deleted,
157  * in that case we have to read the node coords first */
158  Vect_get_node_coor(Map, node, &nx, &ny, &nz);
159 
160  if (Points->n_points > 1) {
161  new_short_line = Vect_rewrite_line(
162  Map, abs(short_line), short_type, Points, SCats);
163  }
164  else {
165  Vect_delete_line(Map, abs(short_line));
166  }
167 
168  /* It may happen that it is one line, in that case we have
169  * to take the new short line as long line, orientation is
170  * not changed */
171  if (abs(line1) == abs(line2)) {
172  if (long_line > 0)
173  long_line = new_short_line;
174  else
175  long_line = -new_short_line;
176  }
177 
178  /* Add new line (must be before rewrite of long_line
179  * otherwise node could be deleted) */
180  long_type =
181  Vect_read_line(Map, NULL, LCats, abs(long_line));
182 
183  Vect_reset_cats(OCats);
184  for (j = 0; j < SCats->n_cats; j++) {
185  Vect_cat_set(OCats, SCats->field[j], SCats->cat[j]);
186  }
187  for (j = 0; j < LCats->n_cats; j++) {
188  Vect_cat_set(OCats, LCats->field[j], LCats->cat[j]);
189  }
190 
191  if (long_type == GV_BOUNDARY || short_type == GV_BOUNDARY) {
192  type = GV_BOUNDARY;
193  }
194  else {
195  type = GV_LINE;
196  }
197 
198  Vect_reset_line(Points);
199  Vect_append_point(Points, nx, ny, nz);
200  Vect_append_point(Points, x, y, z);
201  Vect_write_line(Map, type, Points, OCats);
202 
203  if (Err) {
204  Vect_write_line(Err, type, Points, OCats);
205  }
206 
207  /* Snap long_line to the new short_line end */
208  long_type =
209  Vect_read_line(Map, Points, LCats, abs(long_line));
210  if (long_line > 0) {
211  Points->x[0] = x;
212  Points->y[0] = y;
213  Points->z[0] = z;
214  }
215  else {
216  Points->x[Points->n_points - 1] = x;
217  Points->y[Points->n_points - 1] = y;
218  Points->z[Points->n_points - 1] = z;
219  }
220  Vect_line_prune(Points);
221  if (Points->n_points > 1) {
222  Vect_rewrite_line(Map, abs(long_line), long_type,
223  Points, LCats);
224  }
225  else {
226  Vect_delete_line(Map, abs(long_line));
227  }
228 
229  nmodif += 3;
230  clean = 0;
231 
232  break;
233  }
234 
235  line1 = line2;
236  angle1 = angle2;
237  }
238 
239  if (clean || !Vect_node_alive(Map, node))
240  break;
241  }
242  }
243  G_verbose_message(_("Modifications: %d"), nmodif);
244  Vect_destroy_line_struct(Points);
248 
249  return (nmodif);
250 }
#define NULL
Definition: ccmath.h:32
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:33
void G_percent(long, long, int)
Print percent complete messages.
Definition: percent.c:61
void void G_verbose_message(const char *,...) __attribute__((format(printf
int G_debug(int, const char *,...) __attribute__((format(printf
void Vect_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
Definition: line.c:77
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 Vect_get_node_coor(struct Map_info *, int, double *, double *, double *)
Get node coordinates.
Definition: level_two.c:274
int Vect_reset_cats(struct line_cats *)
Reset category structure to make sure cats structure is clean to be re-used.
float Vect_get_node_line_angle(struct Map_info *, int, int)
Angle of segment of the line connected to the node.
Definition: level_two.c:412
int Vect_cat_set(struct line_cats *, int, int)
Add new field/cat to category structure if doesn't exist yet.
void Vect_destroy_cats_struct(struct line_cats *)
Frees all memory associated with line_cats structure, including the struct itself.
int Vect_read_line(struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
double Vect_points_distance(double, double, double, double, double, double, int)
Calculate distance of 2 points.
Definition: line.c:866
int Vect_delete_line(struct Map_info *, off_t)
Delete existing feature (topological level required)
off_t Vect_write_line(struct Map_info *, int, const struct line_pnts *, const struct line_cats *)
Writes a new feature.
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition: line.c:45
int Vect_get_node_n_lines(struct Map_info *, int)
Get number of lines for node.
Definition: level_two.c:380
plus_t Vect_get_num_nodes(struct Map_info *)
Get number of nodes in vector map.
Definition: level_two.c:34
int Vect_line_delete_point(struct line_pnts *, int)
Delete point at given index and move all points above down.
Definition: line.c:210
int Vect_node_alive(struct Map_info *, int)
Check if node is alive or dead (topological level required)
void Vect_reset_line(struct line_pnts *)
Reset line.
Definition: line.c:129
int Vect_get_node_line(struct Map_info *, int, int)
Get line id for node line index.
Definition: level_two.c:396
int Vect_line_prune(struct line_pnts *)
Remove duplicate points, i.e. zero length segments.
Definition: line.c:279
struct line_cats * Vect_new_cats_struct(void)
Creates and initializes line_cats structure.
int Vect_append_point(struct line_pnts *, double, double, double)
Appends one point to the end of a line.
Definition: line.c:148
#define GV_LINE
Definition: dig_defines.h:184
#define GV_LINES
Definition: dig_defines.h:193
#define GV_BOUNDARY
Definition: dig_defines.h:185
#define _(str)
Definition: glocale.h:10
Vector map info.
Definition: dig_structs.h:1243
struct Plus_head plus
Plus info (topology, version, ...)
Definition: dig_structs.h:1270
Vector geometry.
Definition: dig_structs.h:1553
char type
Line type.
Definition: dig_structs.h:1564
struct P_line ** Line
Array of vector geometries.
Definition: dig_structs.h:871
Feature category info.
Definition: dig_structs.h:1677
int * field
Array of layers (fields)
Definition: dig_structs.h:1681
int * cat
Array of categories.
Definition: dig_structs.h:1685
int n_cats
Number of categories attached to element.
Definition: dig_structs.h:1689
Feature geometry info - coordinates.
Definition: dig_structs.h:1651
double * y
Array of Y coordinates.
Definition: dig_structs.h:1659
double * x
Array of X coordinates.
Definition: dig_structs.h:1655
int n_points
Number of points.
Definition: dig_structs.h:1667
double * z
Array of Z coordinates.
Definition: dig_structs.h:1663
#define x