GRASS Programmer's Manual  6.4.2(2012)
 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 
44 int Vect_merge_lines(struct Map_info *Map, int type, int *new_lines,
45  struct Map_info *Err)
46 {
47  int line, nlines, i, c, first, last, next_line, curr_line;
48  int merged = 0, newl = 0;
49  int next_node, direction, node_n_lines, same_type;
50  struct Plus_head *Plus;
51  struct ilist *List;
52  struct line_pnts *MPoints, *Points;
53  struct line_cats *MCats, *Cats;
54  struct P_line *Line;
55 
56  if ((type & GV_BOUNDARY) && (type & GV_LINE)) {
57  G_warning
58  ("Merging is done only with either lines or boundaries, not both types at the same time");
59  return 0;
60  }
61  if (!(type & GV_BOUNDARY) && !(type & GV_LINE)) {
62  G_warning
63  ("Merging is done with lines or boundaries only, not with other types");
64  return 0;
65  }
66 
67  Plus = &(Map->plus);
68  nlines = Vect_get_num_lines(Map);
69 
70  Points = Vect_new_line_struct();
71  Cats = Vect_new_cats_struct();
72  MPoints = Vect_new_line_struct();
73  MCats = Vect_new_cats_struct();
74  List = Vect_new_list();
75 
76  for (line = 1; line <= nlines; line++) {
77  G_percent(line, nlines, 2);
78 
79  if (!Vect_line_alive(Map, line))
80  continue;
81 
82  Line = Plus->Line[line];
83 
84  if (!(Line->type & type))
85  continue;
86 
87  /* special cases:
88  * - loop back to start boundary via several other boundaries
89  * - one boundary forming closed loop
90  * - node with 3 entries but only 2 boundaries, one of them connecting twice,
91  * the other one must then be topologically incorrect in case of boundary */
92 
93  /* go backward as long as there is only one other line/boundary at the current node */
94  G_debug(3, "go backward");
95  next_node = Line->N1;
96  first = -line;
97  while (1) {
98  node_n_lines = Vect_get_node_n_lines(Map, next_node);
99  same_type = 0;
100  next_line = first;
101  for (i = 0; i < node_n_lines; i++) {
102  curr_line = Vect_get_node_line(Map, next_node, i);
103  if ((Plus->Line[abs(curr_line)]->type & type)) {
104  same_type++;
105  if (abs(curr_line) != abs(first))
106  next_line = curr_line;
107  }
108  }
109  if (same_type == 2 && abs(next_line) != abs(first) &&
110  abs(next_line) != line) {
111  first = next_line;
112 
113  if (first < 0)
114  next_node = Plus->Line[-first]->N1;
115  else
116  next_node = Plus->Line[first]->N2;
117  }
118  else
119  break;
120  }
121 
122  /* go forward as long as there is only one other line/boundary at the current node */
123  G_debug(3, "go forward");
124 
125  /* reverse direction */
126  last = -first;
127 
128  if (last < 0)
129  next_node = Plus->Line[-last]->N1;
130  else
131  next_node = Plus->Line[last]->N2;
132 
133  Vect_reset_list(List);
134  while (1) {
135  Vect_list_append(List, last);
136  node_n_lines = Vect_get_node_n_lines(Map, next_node);
137  same_type = 0;
138  next_line = last;
139  for (i = 0; i < node_n_lines; i++) {
140  curr_line = Vect_get_node_line(Map, next_node, i);
141  if ((Plus->Line[abs(curr_line)]->type & type)) {
142  same_type++;
143  if (abs(curr_line) != abs(last))
144  next_line = curr_line;
145  }
146  }
147 
148  if (same_type == 2 && abs(next_line) != abs(last) &&
149  abs(next_line) != abs(first)) {
150  last = next_line;
151 
152  if (last < 0)
153  next_node = Plus->Line[-last]->N1;
154  else
155  next_node = Plus->Line[last]->N2;
156  }
157  else
158  break;
159  }
160 
161  /* merge lines */
162  if (List->n_values > 1) {
163  G_debug(3, "merge %d lines", List->n_values);
164  Vect_reset_line(MPoints);
165  Vect_reset_cats(MCats);
166 
167  for (i = 0; i < List->n_values; i++) {
168  Vect_reset_line(Points);
169  Vect_reset_cats(Cats);
170  Vect_read_line(Map, Points, Cats, abs(List->value[i]));
171  direction = (List->value[i] < 0 ? GV_BACKWARD : GV_FORWARD);
172  Vect_append_points(MPoints, Points, direction);
173  MPoints->n_points--;
174  for (c = 0; c < Cats->n_cats; c++) {
175  Vect_cat_set(MCats, Cats->field[c], Cats->cat[c]);
176  }
177  if (Err) {
178  /* write out lines/boundaries to be merged */
179  Vect_write_line(Err, type, Points, Cats);
180  }
181  Vect_delete_line(Map, abs(List->value[i]));
182  }
183  MPoints->n_points++;
184  Vect_write_line(Map, type, MPoints, MCats);
185  merged += List->n_values;
186  newl++;
187  }
188 
189  nlines = Vect_get_num_lines(Map);
190  }
191 
192  G_verbose_message(_("%d boundaries merged"), merged);
193  G_verbose_message(_("%d new boundaries"), newl);
194 
195  if (new_lines)
196  *new_lines = newl;
197 
198  return merged;
199 }