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