GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
merge_lines.c
Go to the documentation of this file.
1 
18 #include <grass/config.h>
19 #include <stdlib.h>
20 #include <math.h>
21 #include <grass/gis.h>
22 #include <grass/Vect.h>
23 #include <grass/glocale.h>
24 
25 /* compare category structures
26  * return 0 identical
27  * return 1 not identical
28  */
29 static int compare_cats(struct line_cats *ACats, struct line_cats *BCats)
30 {
31  int i, j;
32 
33  if (ACats->n_cats == 0 || BCats->n_cats == 0) {
34  if (ACats->n_cats == 0 && BCats->n_cats == 0)
35  return 0;
36 
37  if (ACats->n_cats == 0 && BCats->n_cats > 0)
38  return 1;
39 
40  if (ACats->n_cats > 0 && BCats->n_cats == 0)
41  return 1;
42  }
43 
44  for (i = 0; i < ACats->n_cats; i++) {
45  int found = 0;
46 
47  for (j = 0; j < BCats->n_cats; j++) {
48  if (ACats->cat[i] == BCats->cat[j] &&
49  ACats->field[i] == BCats->field[j]) {
50  found = 1;
51  break;
52  }
53  }
54  if (!found)
55  return 1;
56  }
57 
58  return 0;
59 }
60 
80 int Vect_merge_lines(struct Map_info *Map, int type, int *new_lines,
81  struct Map_info *Err)
82 {
83  int line, nlines, i, first, last, next_line, curr_line;
84  int merged = 0, newl = 0;
85  int next_node, direction, node_n_lines, ltype, lines_type;
86  struct Plus_head *Plus;
87  struct ilist *List;
88  struct line_pnts *MPoints, *Points;
89  struct line_cats *MCats, *Cats;
90  struct P_line *Line;
91 
92  if (!(type & GV_LINES)) {
93  G_warning
94  ("Merging is done with lines or boundaries only, not with other types");
95  return 0;
96  }
97 
98  Plus = &(Map->plus);
99  nlines = Vect_get_num_lines(Map);
100 
101  Points = Vect_new_line_struct();
102  Cats = Vect_new_cats_struct();
103  MPoints = Vect_new_line_struct();
104  MCats = Vect_new_cats_struct();
105  List = Vect_new_list();
106 
107  for (line = 1; line <= nlines; line++) {
108  G_percent(line, nlines, 2);
109 
110  if (!Vect_line_alive(Map, line))
111  continue;
112 
113  Line = Plus->Line[line];
114  ltype = Line->type;
115 
116  if (!(ltype & type))
117  continue;
118 
119  Vect_read_line(Map, NULL, MCats, line);
120 
121  /* special cases:
122  * - loop back to start boundary via several other boundaries
123  * - one boundary forming closed loop
124  * - node with 3 entries but only 2 boundaries, one of them connecting twice,
125  * the other one must then be topologically incorrect in case of boundary */
126 
127  /* go backward as long as there is only one other line/boundary at the current node */
128  G_debug(3, "go backward");
129  next_node = Line->N1;
130  first = -line;
131  while (1) {
132  node_n_lines = Vect_get_node_n_lines(Map, next_node);
133  /* count lines/boundaries at this node */
134  lines_type = 0;
135  next_line = first;
136  for (i = 0; i < node_n_lines; i++) {
137  curr_line = Vect_get_node_line(Map, next_node, i);
138  if ((Plus->Line[abs(curr_line)]->type & GV_LINES))
139  lines_type++;
140  if ((Plus->Line[abs(curr_line)]->type == ltype)) {
141  if (abs(curr_line) != abs(first)) {
142  Vect_read_line(Map, NULL, Cats, abs(curr_line));
143 
144  /* catgories must be identical */
145  if (compare_cats(MCats, Cats) == 0)
146  next_line = curr_line;
147  }
148  }
149  }
150  if (lines_type == 2 && abs(next_line) != abs(first) &&
151  abs(next_line) != line) {
152  first = next_line;
153 
154  if (first < 0)
155  next_node = Plus->Line[-first]->N1;
156  else
157  next_node = Plus->Line[first]->N2;
158  }
159  else
160  break;
161  }
162 
163  /* go forward as long as there is only one other line/boundary at the current node */
164  G_debug(3, "go forward");
165 
166  /* reverse direction */
167  last = -first;
168 
169  if (last < 0)
170  next_node = Plus->Line[-last]->N1;
171  else
172  next_node = Plus->Line[last]->N2;
173 
174  Vect_reset_list(List);
175  while (1) {
176  Vect_list_append(List, last);
177  node_n_lines = Vect_get_node_n_lines(Map, next_node);
178  lines_type = 0;
179  next_line = last;
180  for (i = 0; i < node_n_lines; i++) {
181  curr_line = Vect_get_node_line(Map, next_node, i);
182  if ((Plus->Line[abs(curr_line)]->type & GV_LINES))
183  lines_type++;
184  if ((Plus->Line[abs(curr_line)]->type == ltype)) {
185  if (abs(curr_line) != abs(last)) {
186  Vect_read_line(Map, NULL, Cats, abs(curr_line));
187 
188  if (compare_cats(MCats, Cats) == 0)
189  next_line = curr_line;
190  }
191  }
192  }
193 
194  if (lines_type == 2 && abs(next_line) != abs(last) &&
195  abs(next_line) != abs(first)) {
196  last = next_line;
197 
198  if (last < 0)
199  next_node = Plus->Line[-last]->N1;
200  else
201  next_node = Plus->Line[last]->N2;
202  }
203  else
204  break;
205  }
206 
207  /* merge lines */
208  if (List->n_values > 1) {
209  G_debug(3, "merge %d lines", List->n_values);
210  Vect_reset_line(MPoints);
211 
212  for (i = 0; i < List->n_values; i++) {
213  Vect_reset_line(Points);
214  Vect_read_line(Map, Points, Cats, abs(List->value[i]));
215  direction = (List->value[i] < 0 ? GV_BACKWARD : GV_FORWARD);
216  Vect_append_points(MPoints, Points, direction);
217  MPoints->n_points--;
218  if (Err) {
219  /* write out lines/boundaries to be merged */
220  Vect_write_line(Err, ltype, Points, Cats);
221  }
222  Vect_delete_line(Map, abs(List->value[i]));
223  }
224  MPoints->n_points++;
225  Vect_write_line(Map, ltype, MPoints, MCats);
226  merged += List->n_values;
227  newl++;
228  }
229 
230  nlines = Vect_get_num_lines(Map);
231  }
232 
233  G_verbose_message(_("%d boundaries merged"), merged);
234  G_verbose_message(_("%d new boundaries"), newl);
235 
236  if (new_lines)
237  *new_lines = newl;
238 
239  Vect_destroy_line_struct(Points);
241  Vect_destroy_line_struct(MPoints);
243  Vect_destroy_list(List);
244 
245  return merged;
246 }
int Vect_destroy_list(struct ilist *list)
Frees all memory associated with a struct ilist, including the struct itself.
int Vect_get_node_line(struct Map_info *Map, int node, int line)
Get line id for node line index.
Definition: level_two.c:316
int Vect_merge_lines(struct Map_info *Map, int type, int *new_lines, struct Map_info *Err)
Merge lines or boundaries in vector map.
Definition: merge_lines.c:80
struct line_pnts * Vect_new_line_struct()
Creates and initializes a struct line_pnts.
Definition: line.c:57
struct ilist * Vect_new_list(void)
Creates and initializes a struct ilist.
int Vect_append_points(struct line_pnts *Points, struct line_pnts *APoints, int direction)
Appends points to the end of a line.
Definition: line.c:312
int Vect_reset_line(struct line_pnts *Points)
Reset line.
Definition: line.c:148
int G_percent(long n, long d, int s)
Print percent complete messages.
Definition: percent.c:63
void G_verbose_message(const char *msg,...)
Print a message to stderr but only if module is in verbose mode.
Definition: lib/gis/error.c:95
int GV_LINES
Definition: vdigit/main.py:24
int Vect_reset_list(struct ilist *list)
Reset ilist structure.
int Vect_destroy_cats_struct(struct line_cats *p)
Frees all memory associated with line_cats structure, including the struct itself.
int Vect_list_append(struct ilist *list, int val)
Append new item to the end of list if not yet present.
int first
Definition: form/open.c:25
int Vect_line_alive(struct Map_info *Map, int line)
Check if feature is alive or dead.
struct line_cats * Vect_new_cats_struct()
Creates and initializes line_cats structure.
return NULL
Definition: dbfopen.c:1394
G_warning("category support for [%s] in mapset [%s] %s", name, mapset, type)
int Vect_get_num_lines(struct Map_info *map)
Fetch number of features (points, lines, boundaries, centroids) in vector map.
Definition: level_two.c:69
tuple Map
Definition: render.py:1310
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: gis/debug.c:51
int Vect_delete_line(struct Map_info *Map, int line)
Delete feature.
long Vect_write_line(struct Map_info *Map, int type, struct line_pnts *points, struct line_cats *cats)
Writes new feature to the end of file (table)
int Vect_destroy_line_struct(struct line_pnts *p)
Frees all memory associated with a struct line_pnts, including the struct itself. ...
Definition: line.c:90
int Vect_read_line(struct Map_info *Map, struct line_pnts *line_p, struct line_cats *line_c, int line)
Read vector feature.
int Vect_get_node_n_lines(struct Map_info *Map, int node)
Get number of lines for node.
Definition: level_two.c:296