GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
break_lines.c
Go to the documentation of this file.
1 
18 #include <stdlib.h>
19 #include <grass/gis.h>
20 #include <grass/Vect.h>
21 #include <grass/glocale.h>
22 
35 void
36 Vect_break_lines(struct Map_info *Map, int type, struct Map_info *Err)
37 {
38  Vect_break_lines_list(Map, NULL, NULL, type, Err);
39 
40  return;
41 }
42 
65 int
66 Vect_break_lines_list(struct Map_info *Map, struct ilist *List_break,
67  struct ilist *List_ref, int type, struct Map_info *Err)
68 {
69  struct line_pnts *APoints, *BPoints, *Points;
70  struct line_pnts **AXLines, **BXLines;
71  struct line_cats *ACats, *BCats, *Cats;
72  int j, k, l, ret, atype, btype, aline, bline, found, iline, nlines;
73  int naxlines, nbxlines, nx;
74  double *xx = NULL, *yx = NULL, *zx = NULL;
75  BOUND_BOX ABox, BBox;
76  struct ilist *List;
77  int nbreaks;
78  int touch1_n = 0, touch1_s = 0, touch1_e = 0, touch1_w = 0; /* other vertices except node1 touching box */
79  int touch2_n = 0, touch2_s = 0, touch2_e = 0, touch2_w = 0; /* other vertices except node2 touching box */
80  int is3d;
81  int node, anode1, anode2, bnode1, bnode2;
82  double nodex, nodey;
83 
84  APoints = Vect_new_line_struct();
85  BPoints = Vect_new_line_struct();
86  Points = Vect_new_line_struct();
87  ACats = Vect_new_cats_struct();
88  BCats = Vect_new_cats_struct();
89  Cats = Vect_new_cats_struct();
90  List = Vect_new_list();
91 
92  is3d = Vect_is_3d(Map);
93 
94  if (List_break) {
95  nlines = List_break->n_values;
96  }
97  else {
98  nlines = Vect_get_num_lines(Map);
99  }
100  G_debug(3, "nlines = %d", nlines);
101 
102  /* To find intersection of two lines (Vect_line_intersection) is quite slow.
103  * Fortunately usual lines/boundaries in GIS often forms a network where lines
104  * are connected by end points, and touch by MBR. This function checks and occasionaly
105  * skips such cases. This is currently done for 2D only
106  */
107 
108  /* Go through all lines in vector, for each select lines which overlap MBR of
109  * this line exclude those connected by one endpoint (see above)
110  * and try to intersect, if lines intersect write new lines at the end of
111  * the file, and process next line (remaining lines overlapping box are skipped)
112  */
113  nbreaks = 0;
114 
115  for (iline = 0; iline < nlines; iline++) {
116  G_percent(iline, nlines, 1);
117  if (List_break) {
118  aline = List_break->value[iline];
119  }
120  else {
121  aline = iline + 1;
122  }
123 
124  if (List_ref && !Vect_val_in_list(List_ref, aline))
125  continue;
126 
127  G_debug(3, "aline = %d", aline);
128  if (!Vect_line_alive(Map, aline))
129  continue;
130 
131  atype = Vect_read_line(Map, APoints, ACats, aline);
132  if (!(atype & type))
133  continue;
134 
135  Vect_get_line_box(Map, aline, &ABox);
136 
137  /* Find which sides of the box are touched by intermediate (non-end) points of line */
138  if (!is3d) {
139  touch1_n = touch1_s = touch1_e = touch1_w = 0;
140  for (j = 1; j < APoints->n_points; j++) {
141  if (APoints->y[j] == ABox.N)
142  touch1_n = 1;
143  if (APoints->y[j] == ABox.S)
144  touch1_s = 1;
145  if (APoints->x[j] == ABox.E)
146  touch1_e = 1;
147  if (APoints->x[j] == ABox.W)
148  touch1_w = 1;
149  }
150  G_debug(3, "touch1: n = %d s = %d e = %d w = %d", touch1_n,
151  touch1_s, touch1_e, touch1_w);
152  touch2_n = touch2_s = touch2_e = touch2_w = 0;
153  for (j = 0; j < APoints->n_points - 1; j++) {
154  if (APoints->y[j] == ABox.N)
155  touch2_n = 1;
156  if (APoints->y[j] == ABox.S)
157  touch2_s = 1;
158  if (APoints->x[j] == ABox.E)
159  touch2_e = 1;
160  if (APoints->x[j] == ABox.W)
161  touch2_w = 1;
162  }
163  G_debug(3, "touch2: n = %d s = %d e = %d w = %d", touch2_n,
164  touch2_s, touch2_e, touch2_w);
165  }
166 
167  Vect_select_lines_by_box(Map, &ABox, type, List);
168  G_debug(3, " %d lines selected by box", List->n_values);
169 
170  for (j = 0; j < List->n_values; j++) {
171  bline = List->value[j];
172  if (List_break && !Vect_val_in_list(List_break, bline)) {
173  continue;
174  }
175  G_debug(3, " j = %d bline = %d", j, bline);
176 
177  /* Check if thouch by end node only */
178  if (!is3d) {
179  Vect_get_line_nodes(Map, aline, &anode1, &anode2);
180  Vect_get_line_nodes(Map, bline, &bnode1, &bnode2);
181  Vect_get_line_box(Map, bline, &BBox);
182 
183  if (anode1 == bnode1 || anode1 == bnode2)
184  node = anode1;
185  else if (anode2 == bnode1 || anode2 == bnode2)
186  node = anode2;
187  else
188  node = 0;
189 
190  if (node) {
191  Vect_get_node_coor(Map, node, &nodex, &nodey, NULL);
192  if ((node == anode1 && nodey == ABox.N && !touch1_n &&
193  nodey == BBox.S) || (node == anode2 &&
194  nodey == ABox.N && !touch2_n &&
195  nodey == BBox.S) ||
196  (node == anode1 && nodey == ABox.S && !touch1_s &&
197  nodey == BBox.N) || (node == anode2 &&
198  nodey == ABox.S && !touch2_s &&
199  nodey == BBox.N) ||
200  (node == anode1 && nodex == ABox.E && !touch1_e &&
201  nodex == BBox.W) || (node == anode2 &&
202  nodex == ABox.E && !touch2_e &&
203  nodex == BBox.W) ||
204  (node == anode1 && nodex == ABox.W && !touch1_w &&
205  nodex == BBox.E) || (node == anode2 &&
206  nodex == ABox.W && !touch2_w &&
207  nodex == BBox.E)) {
208  G_debug(3,
209  "lines %d and %d touching by end nodes only -> no intersection",
210  aline, bline);
211  continue;
212  }
213  }
214  }
215 
216  btype = Vect_read_line(Map, BPoints, BCats, bline);
217 
218  AXLines = NULL;
219  BXLines = NULL;
220  Vect_line_intersection(APoints, BPoints, &AXLines, &BXLines,
221  &naxlines, &nbxlines, 0);
222  G_debug(3, " naxlines = %d nbxlines = %d", naxlines, nbxlines);
223 
224  /* This part handles a special case when aline == bline, no other intersection was found
225  * and the line is forming collapsed loop, for example 0,0;1,0;0,0 should be broken at 1,0.
226  * ---> */
227  if (aline == bline && naxlines == 0 && nbxlines == 0 &&
228  APoints->n_points >= 3) {
229  int centre;
230  int i;
231 
232  G_debug(3, " Check collapsed loop");
233  if (APoints->n_points % 2) { /* odd number of vertices */
234  centre = APoints->n_points / 2; /* index of centre */
235  if (APoints->x[centre - 1] == APoints->x[centre + 1] && APoints->y[centre - 1] == APoints->y[centre + 1] && APoints->z[centre - 1] == APoints->z[centre + 1]) { /* -> break */
236  AXLines =
237  (struct line_pnts **)G_malloc(2 *
238  sizeof(struct
239  line_pnts
240  *));
241  AXLines[0] = Vect_new_line_struct();
242  AXLines[1] = Vect_new_line_struct();
243 
244  for (i = 0; i <= centre; i++)
245  Vect_append_point(AXLines[0], APoints->x[i],
246  APoints->y[i], APoints->z[i]);
247 
248  for (i = centre; i < APoints->n_points; i++)
249  Vect_append_point(AXLines[1], APoints->x[i],
250  APoints->y[i], APoints->z[i]);
251 
252  naxlines = 2;
253  }
254  }
255  }
256  /* <--- */
257 
258  if (Err) { /* array for intersections (more than needed */
259  xx = (double *)G_malloc((naxlines + nbxlines) *
260  sizeof(double));
261  yx = (double *)G_malloc((naxlines + nbxlines) *
262  sizeof(double));
263  zx = (double *)G_malloc((naxlines + nbxlines) *
264  sizeof(double));
265  }
266  nx = 0; /* number of intersections to be written to Err */
267  if (naxlines > 0) { /* intersection -> write out */
268  Vect_delete_line(Map, aline);
269  for (k = 0; k < naxlines; k++) {
270  /* Write new line segments */
271  /* line may collapse, don't write zero length lines */
272  Vect_line_prune(AXLines[k]);
273  if ((atype & GV_POINTS) || AXLines[k]->n_points > 1) {
274  ret = Vect_write_line(Map, atype, AXLines[k], ACats);
275  if (List_ref) {
276  Vect_list_append(List_ref, ret);
277  }
278  G_debug(3, "Line %d written, npoints = %d", ret,
279  AXLines[k]->n_points);
280  if (List_break) {
281  Vect_list_append(List_break, ret);
282  }
283  }
284 
285  /* Write intersection points */
286  if (Err) {
287  if (k > 0) {
288  xx[nx] = AXLines[k]->x[0];
289  yx[nx] = AXLines[k]->y[0];
290  zx[nx] = AXLines[k]->z[0];
291  nx++;
292  }
293  }
294  Vect_destroy_line_struct(AXLines[k]);
295  }
296  nbreaks += naxlines - 1;
297  }
298  if (AXLines)
299  G_free(AXLines);
300 
301  if (nbxlines > 0) {
302  if (aline != bline) { /* Self intersection, do not write twice, TODO: is it OK? */
303  Vect_delete_line(Map, bline);
304  for (k = 0; k < nbxlines; k++) {
305  /* Write new line segments */
306  /* line may collapse, don't write zero length lines */
307  Vect_line_prune(BXLines[k]);
308  if ((btype & GV_POINTS) || BXLines[k]->n_points > 1) {
309  ret =
310  Vect_write_line(Map, btype, BXLines[k],
311  BCats);
312  G_debug(5, "Line %d written", ret);
313  if (List_break) {
314  Vect_list_append(List_break, ret);
315  }
316  }
317 
318  /* Write intersection points */
319  if (Err) {
320  if (k > 0) {
321  found = 0;
322  for (l = 0; l < nx; l++) {
323  if (xx[l] == BXLines[k]->x[0] &&
324  yx[l] == BXLines[k]->y[0] &&
325  zx[l] == BXLines[k]->z[0]) {
326  found = 1;
327  break;
328  }
329  }
330  if (!found) {
331  xx[nx] = BXLines[k]->x[0];
332  yx[nx] = BXLines[k]->y[0];
333  zx[nx] = BXLines[k]->z[0];
334  nx++;
335  }
336  }
337  }
338  Vect_destroy_line_struct(BXLines[k]);
339  }
340  nbreaks += nbxlines - 1;
341  }
342  else {
343  for (k = 0; k < nbxlines; k++)
344  Vect_destroy_line_struct(BXLines[k]);
345  }
346  }
347  if (BXLines)
348  G_free(BXLines);
349  if (Err) {
350  for (l = 0; l < nx; l++) { /* Write out errors */
351  Vect_reset_line(Points);
352  Vect_append_point(Points, xx[l], yx[l], zx[l]);
353  ret = Vect_write_line(Err, GV_POINT, Points, Cats);
354  }
355 
356  G_free(xx);
357  G_free(yx);
358  G_free(zx);
359  }
360  if (naxlines > 0)
361  break; /* first line was broken and deleted -> take the next one */
362  }
363 
364  if (List_break) {
365  nlines = List_break->n_values;
366  }
367  else {
368  nlines = Vect_get_num_lines(Map);
369  }
370  G_debug(3, "nlines = %d", nlines);
371  } /* for each line */
372  G_percent(nlines, nlines, 1); /* finish it */
373 
374  G_verbose_message(_("Intersections: %5d"), nbreaks);
375 
376  Vect_destroy_list(List);
377 
378  return nbreaks;
379 }
int Vect_destroy_list(struct ilist *list)
Frees all memory associated with a struct ilist, including the struct itself.
void G_free(void *buf)
Free allocated memory.
Definition: gis/alloc.c:142
int l
Definition: dataquad.c:292
int Vect_get_line_nodes(struct Map_info *Map, int line, int *n1, int *n2)
Get line nodes.
Definition: level_two.c:247
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_reset_line(struct line_pnts *Points)
Reset line.
Definition: line.c:148
int y
Definition: plot.c:34
int Vect_append_point(struct line_pnts *Points, double x, double y, double z)
Appends one point to the end of a line.
Definition: line.c:168
int G_percent(long n, long d, int s)
Print percent complete messages.
Definition: percent.c:63
int Vect_is_3d(struct Map_info *Map)
Check if vector map is 3D (with z)
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 Vect_list_append(struct ilist *list, int val)
Append new item to the end of list if not yet present.
int Vect_break_lines_list(struct Map_info *Map, struct ilist *List_break, struct ilist *List_ref, int type, struct Map_info *Err)
Break selected lines in vector map at each intersection.
Definition: break_lines.c:66
int Vect_line_alive(struct Map_info *Map, int line)
Check if feature is alive or dead.
int Vect_select_lines_by_box(struct Map_info *Map, BOUND_BOX *Box, int type, struct ilist *list)
Select lines by box.
struct line_cats * Vect_new_cats_struct()
Creates and initializes line_cats structure.
return NULL
Definition: dbfopen.c:1394
int Vect_line_prune(struct line_pnts *Points)
Remove duplicate points, i.e. zero length segments.
Definition: line.c:255
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_line_intersection(struct line_pnts *APoints, struct line_pnts *BPoints, struct line_pnts ***ALines, struct line_pnts ***BLines, int *nalines, int *nblines, int with_z)
Intersect 2 lines.
int Vect_delete_line(struct Map_info *Map, int line)
Delete feature.
int Vect_get_line_box(struct Map_info *Map, int line, BOUND_BOX *Box)
Get boundary box of line.
Definition: Vlib/box.c:208
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_val_in_list(struct ilist *list, int val)
Find a given item in the list.
int Vect_get_node_coor(struct Map_info *map, int num, double *x, double *y, double *z)
Get node coordinates.
Definition: level_two.c:223
void Vect_break_lines(struct Map_info *Map, int type, struct Map_info *Err)
Break lines in vector map at each intersection.
Definition: break_lines.c:36
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.