GRASS GIS 8 Programmer's Manual  8.2.2dev(2023)-3d2c704037
dangles.c
Go to the documentation of this file.
1 /*!
2  \file lib/vector/Vlib/dangles.c
3 
4  \brief Vector library - clean geometry (dangles)
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 #define REMOVE_DANGLE 0
21 #define CHTYPE_DANGLE 1
22 #define SELECT_DANGLE 2
23 
24 static void dangles(struct Map_info *, int, int, double,
25  struct Map_info *, struct ilist *);
26 
27 /*!
28  \brief Remove dangles from vector map.
29 
30  Remove dangles of given type shorter than maxlength from vector
31  map.
32 
33  Line is considered to be a dangle if on at least one end node is no
34  other line of given type(s). If a dangle is formed by more lines,
35  such string of lines is taken as one dangle and either deleted are
36  all parts or nothing.
37 
38  Optionally deleted dangles are written to error map.
39 
40  Input map must be opened on level 2 for update.
41 
42  \param Map input map where have to be deleted
43  \param type type of dangles (GV_LINES, GV_LINE or GV_BOUNDARY)
44  \param maxlength maxlength of dangles or -1 for all dangles
45  \param[out] Err vector map where deleted dangles are written or NULL
46 
47  \return
48  */
49 void
50 Vect_remove_dangles(struct Map_info *Map, int type, double maxlength,
51  struct Map_info *Err)
52 {
53  dangles(Map, type, REMOVE_DANGLE, maxlength, Err, NULL);
54 }
55 
56 /*!
57  \brief Change boundary dangles to lines.
58 
59  Change boundary dangles to lines.
60 
61  Boundary is considered to be a dangle if on at least one end node
62  is no other boundary. If a dangle is formed by more boundaries,
63  such string of boundaries is taken as one dangle.
64 
65  Optionally deleted dangles are written to error map.
66 
67  Input map must be opened on level 2 for update at least on GV_BUILD_BASE.
68 
69  \param Map input map where have to be deleted
70  \param maxlength maxlength of dangles or -1 for all dangles
71  \param[out] Err vector map where deleted dangles are written or NULL
72 
73  \return
74  */
75 void
76 Vect_chtype_dangles(struct Map_info *Map, double maxlength,
77  struct Map_info *Err)
78 {
79  dangles(Map, 0, CHTYPE_DANGLE, maxlength, Err, NULL);
80 }
81 
82 /*!
83  \brief Select dangles from vector map.
84 
85  Remove dangles of given type shorter than maxlength from vector map.
86 
87  Line is considered to be a dangle if on at least one end node is no
88  other line of given type(s). If a dangle is formed by more lines,
89  such string of lines is taken as one dangle.
90 
91  Input map must be opened on level 2 for update.
92 
93  \param Map input map where have to be deleted
94  \param type type of dangles (GV_LINES, GV_LINE or GV_BOUNDARY)
95  \param maxlength maxlength of dangles or -1 for all dangles
96  \param[out] List list of selected features
97 
98  \return
99  */
100 void
101 Vect_select_dangles(struct Map_info *Map, int type, double maxlength,
102  struct ilist *List)
103 {
104  dangles(Map, type, SELECT_DANGLE, maxlength, NULL, List);
105 }
106 
107 /*
108  Line is considered to be a dangle if on at least one end node is no
109  other line of given type(s). If a dangle is formed by more lines,
110  such string of lines is taken as one dangle and either deleted are
111  all parts or nothing. Optionally, if chtype is set to 1, only
112  GV_BOUNDARY are checked for dangles, and if dangle is found lines
113  are not deleted but rewritten with type GVLINE. Optionally deleted
114  dangles are written to error map. Input map must be opened on level
115  2 for update at least on GV_BUILD_BASE.
116 
117  Parameters:
118  Map input map where dangles have to be deleted
119  type type of dangles
120  option dangle option (REMOVE_DANGLE, CHTYPE_DANGLE, SELECT_DANGLE)
121  maxlength maxlength of dangles or -1 for all dangles
122  Err vector map where deleted dangles are written or NULL
123  List_dangle list of feature (selected dangles) ids
124  */
125 static void dangles(struct Map_info *Map, int type, int option,
126  double maxlength, struct Map_info *Err,
127  struct ilist *List_dangle)
128 {
129  struct line_pnts *Points;
130  struct line_cats *Cats;
131  int i, line, ltype, next_line = 0, nnodelines;
132  int nnodes, node, node1, node2, next_node;
133  int lcount, tmp_next_line = 0;
134  double length;
135  int dangles_removed; /* number of removed dangles */
136  int lines_removed; /* number of lines removed */
137  struct ilist *List; /* List of lines in chain */
138  char *lmsg;
139 
140  next_line = tmp_next_line = 0;
141  dangles_removed = 0;
142  lines_removed = 0;
143 
144  type &= GV_LINES; /* to work only with lines and boundaries */
145 
146  if (option == CHTYPE_DANGLE) {
147  type = GV_BOUNDARY; /* process boundaries only */
148  lmsg = _("Changed");
149  }
150  else if (option == REMOVE_DANGLE) {
151  lmsg = _("Removed");
152  }
153  else {
154  lmsg = _("Selected");
155  }
156 
157  if (List_dangle)
158  Vect_reset_list(List_dangle);
159 
160  Points = Vect_new_line_struct();
161  Cats = Vect_new_cats_struct();
162  List = Vect_new_list();
163 
164  nnodes = Vect_get_num_nodes(Map);
165  G_debug(2, "nnodes = %d", nnodes);
166 
167  for (node = 1; node <= nnodes; node++) {
168  G_percent(node, nnodes, 1);
169  G_debug(3, "node = %d", node);
170  if (!Vect_node_alive(Map, node))
171  continue;
172 
173  nnodelines = Vect_get_node_n_lines(Map, node);
174 
175  lcount = 0; /* number of lines of given type */
176  for (i = 0; i < nnodelines; i++) {
177  line = Vect_get_node_line(Map, node, i);
178  G_debug(3, " node line %d = %d", i, line);
179 
180  ltype = Vect_read_line(Map, NULL, NULL, abs(line));
181 
182  if (ltype & type) {
183  lcount++;
184  next_line = line;
185  }
186  }
187 
188  Vect_reset_list(List);
189  if (lcount == 1) {
190  G_debug(3, " node %d is dangle -> follow the line %d", node,
191  next_line);
192 
193  while (next_line != 0) {
194  Vect_list_append(List, abs(next_line));
195 
196  /* Look at the next end of the line if just one another line of the type is connected */
197  Vect_get_line_nodes(Map, abs(next_line), &node1, &node2);
198  next_node = next_line > 0 ? node2 : node1;
199 
200  G_debug(3, " next_node = %d", next_node);
201 
202  nnodelines = Vect_get_node_n_lines(Map, next_node);
203 
204  lcount = 0; /* number of lines of given type (except current next_line) */
205  for (i = 0; i < nnodelines; i++) {
206  line = Vect_get_node_line(Map, next_node, i);
207  G_debug(3, " node line %d = %d", i, line);
208 
209  ltype = Vect_read_line(Map, NULL, NULL, abs(line));
210 
211  if (ltype & type && abs(line) != abs(next_line)) {
212  lcount++;
213  tmp_next_line = line;
214  }
215  }
216  if (lcount == 1)
217  next_line = tmp_next_line;
218  else
219  next_line = 0;
220 
221  }
222 
223  /* Length of the chain */
224  length = 0;
225  for (i = 0; i < List->n_values; i++) {
226  G_debug(3, " chain line %d = %d", i, List->value[i]);
227  ltype = Vect_read_line(Map, Points, NULL, List->value[i]);
228  length += Vect_line_length(Points);
229  }
230 
231  if (maxlength < 0 || length < maxlength) { /* delete the chain */
232  G_debug(3, " delete the chain (length=%g)", length);
233 
234  for (i = 0; i < List->n_values; i++) {
235  ltype = Vect_read_line(Map, Points, Cats, List->value[i]);
236 
237  /* Write to Err deleted dangle */
238  if (Err) {
239  Vect_write_line(Err, ltype, Points, Cats);
240  }
241 
242  if (option == REMOVE_DANGLE) {
243  Vect_delete_line(Map, List->value[i]);
244  }
245  else if (option == CHTYPE_DANGLE) {
246  G_debug(3, " rewrite line %d", List->value[i]);
247  Vect_rewrite_line(Map, List->value[i], GV_LINE,
248  Points, Cats);
249  }
250  else {
251  if (List_dangle) {
252  Vect_list_append(List_dangle, List->value[i]);
253  }
254  }
255  lines_removed++;
256  }
257  } /* delete the chain */
258 
259  dangles_removed++;
260  } /* lcount == 1 */
261  } /* node <= nnodes */
262  G_verbose_message(_("%s lines: %d"), lmsg, lines_removed);
263  G_verbose_message(_("%s dangles: %d"), lmsg, dangles_removed);
264 }
plus_t Vect_get_num_nodes(const struct Map_info *)
Get number of nodes in vector map.
Definition: level_two.c:34
int Vect_reset_list(struct ilist *)
Reset ilist structure.
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)
#define SELECT_DANGLE
Definition: dangles.c:22
int n_values
Number of values in the list.
Definition: gis.h:709
double Vect_line_length(const struct line_pnts *)
Calculate line length, 3D-length in case of 3D vector line.
Definition: line.c:576
#define NULL
Definition: ccmath.h:32
void Vect_remove_dangles(struct Map_info *Map, int type, double maxlength, struct Map_info *Err)
Remove dangles from vector map.
Definition: dangles.c:50
int Vect_get_node_n_lines(const struct Map_info *, int)
Get number of lines for node.
Definition: level_two.c:384
void Vect_select_dangles(struct Map_info *Map, int type, double maxlength, struct ilist *List)
Select dangles from vector map.
Definition: dangles.c:101
Feature category info.
Definition: dig_structs.h:1702
#define GV_LINE
Definition: dig_defines.h:183
Feature geometry info - coordinates.
Definition: dig_structs.h:1675
void Vect_chtype_dangles(struct Map_info *Map, double maxlength, struct Map_info *Err)
Change boundary dangles to lines.
Definition: dangles.c:76
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
off_t Vect_write_line(struct Map_info *, int, const struct line_pnts *, const struct line_cats *)
Writes a new feature.
#define CHTYPE_DANGLE
Definition: dangles.c:21
#define GV_BOUNDARY
Definition: dig_defines.h:184
int Vect_get_line_nodes(const struct Map_info *, int, int *, int *)
Get line nodes.
Definition: level_two.c:307
void G_percent(long, long, int)
Print percent complete messages.
Definition: percent.c:62
Vector map info.
Definition: dig_structs.h:1259
struct ilist * Vect_new_list(void)
Creates and initializes a struct ilist.
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.
int Vect_list_append(struct ilist *, int)
Append new item to the end of list if not yet present.
#define _(str)
Definition: glocale.h:10
List of integers.
Definition: gis.h:700
int Vect_node_alive(const struct Map_info *, int)
Check if node is alive or dead (topological level required)
int * value
Array of values.
Definition: gis.h:705
#define GV_LINES
Definition: dig_defines.h:192
#define REMOVE_DANGLE
Definition: dangles.c:20
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