GRASS GIS 7 Programmer's Manual  7.5.svn(2017)-r71759
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
break_lines.c
Go to the documentation of this file.
1 /*!
2  * \file lib/vector/Vlib/break_lines.c
3  *
4  * \brief Vector library - Clean vector map (break lines)
5  *
6  * (C) 2001-2009 by the GRASS Development Team
7  *
8  * This program is free software under the
9  * GNU General Public License (>=v2).
10  * Read the file COPYING that comes with GRASS
11  * 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 static int break_lines(struct Map_info *, struct ilist *, struct ilist *,
21  int, struct Map_info *, int);
22 
23 
24 /*!
25  \brief Break lines in vector map at each intersection.
26 
27  For details see Vect_break_lines_list().
28 
29  \param Map input vector map
30  \param type feature type
31  \param[out] Err vector map where points at intersections will be written or NULL
32 */
33 void Vect_break_lines(struct Map_info *Map, int type, struct Map_info *Err)
34 {
35  break_lines(Map, NULL, NULL, type, Err, 0);
36 
37  return;
38 }
39 
40 /*!
41  \brief Break selected lines in vector map at each intersection.
42 
43  Breaks selected lines specified by type in vector map. Points at
44  intersections may be optionally written to error map. Input vector map
45  must be opened on level 2 for update at least on GV_BUILD_BASE.
46 
47  The function also breaks lines forming collapsed loop, for example
48  0,0;1,0;0,0 is broken at 1,0.
49 
50  If reference lines are given (<i>List_ref</i>) break only lines
51  which intersect reference lines.
52 
53  \param Map input vector map
54  \param List_break list of lines (NULL for all lines in vector map)
55  \param List_ref list of reference lines or NULL
56  \param type feature type
57  \param[out] Err vector map where points at intersections will be written or NULL
58 
59  \return number of intersections
60 */
61 
62 int Vect_break_lines_list(struct Map_info *Map, struct ilist *List_break,
63  struct ilist *List_ref, int type,
64  struct Map_info *Err)
65 {
66  return break_lines(Map, List_break, List_ref, type, Err, 0);
67 }
68 
69 /*!
70  \brief Check for and count intersecting lines, do not break.
71 
72  For details see Vect_check_line_breaks_list().
73 
74  \param Map input vector map
75  \param type feature type
76  \param[out] Err vector map where points at intersections will be written or NULL
77 
78  \return number for intersections
79 */
80 int Vect_check_line_breaks(struct Map_info *Map, int type, struct Map_info *Err)
81 {
82  return break_lines(Map, NULL, NULL, type, Err, 1);
83 }
84 
85 /*!
86  \brief Check for and count intersecting lines, do not break.
87 
88  If <i>List_break</i> is given, only lines in the list are checked for
89  intersections.
90 
91  If reference lines are given (<i>List_ref</i>) break only lines
92  which intersect reference lines.
93 
94  \param Map input vector map
95  \param List_break list of lines (NULL for all lines in vector map)
96  \param List_ref list of reference lines or NULL
97  \param type feature type
98  \param[out] Err vector map where points at intersections will be written or NULL
99 
100  \return number of intersections
101 */
102 int Vect_check_line_breaks_list(struct Map_info *Map, struct ilist *List_break,
103  struct ilist *List_ref, int type,
104  struct Map_info *Err)
105 {
106  return break_lines(Map, List_break, List_ref, type, Err, 1);
107 }
108 
109 static int cmp(const void *a, const void *b)
110 {
111  int ai = *(int *)a;
112  int bi = *(int *)b;
113 
114  return (ai - bi);
115 }
116 
117 static void sort_ilist(struct ilist *List)
118 {
119  int i, j, is_sorted = 1;
120 
121  for (i = 1; i < List->n_values; i++) {
122  if (List->value[i - 1] > List->value[i]) {
123  is_sorted = 0;
124  break;
125  }
126  }
127 
128  if (!is_sorted)
129  qsort(List->value, List->n_values, sizeof(int), cmp);
130 
131  if (List->n_values > 1) {
132  j = 1;
133  for (i = 1; i < List->n_values; i++) {
134  if (List->value[j - 1] != List->value[i]) {
135  List->value[j] = List->value[i];
136  j++;
137  }
138  }
139  List->n_values = j;
140  }
141 }
142 
143 int break_lines(struct Map_info *Map, struct ilist *List_break,
144  struct ilist *List_ref, int type,
145  struct Map_info *Err, int check)
146 {
147  struct line_pnts *APoints, *BPoints, *Points;
148  struct line_pnts **AXLines, **BXLines;
149  struct line_cats *ACats, *BCats, *Cats;
150  int i, j, k, l, ret, atype, btype, aline, bline, found, iline;
151  int nlines, nlines_org;
152  int naxlines, nbxlines, nx;
153  double *xx = NULL, *yx = NULL, *zx = NULL;
154  struct bound_box ABox, *BBox;
155  struct boxlist *List;
156  int nbreaks;
157  int touch1_n = 0, touch1_s = 0, touch1_e = 0, touch1_w = 0; /* other vertices except node1 touching box */
158  int touch2_n = 0, touch2_s = 0, touch2_e = 0, touch2_w = 0; /* other vertices except node2 touching box */
159  int is3d;
160  int node, anode1, anode2, bnode1, bnode2;
161  double nodex, nodey;
162  int a_is_ref, b_is_ref, break_a, break_b;
163 
164  type &= GV_LINES;
165  if (!type)
166  return 0;
167 
168  APoints = Vect_new_line_struct();
169  BPoints = Vect_new_line_struct();
170  Points = Vect_new_line_struct();
171  ACats = Vect_new_cats_struct();
172  BCats = Vect_new_cats_struct();
173  Cats = Vect_new_cats_struct();
174  List = Vect_new_boxlist(1);
175 
176  is3d = Vect_is_3d(Map);
177 
178  if (List_ref)
179  sort_ilist(List_ref);
180  if (List_break)
181  sort_ilist(List_break);
182 
183  if (List_ref) {
184  nlines = List_ref->n_values;
185  nlines_org = List_ref->value[List_ref->n_values - 1];
186  }
187  else if (List_break) {
188  nlines = List_break->n_values;
189  nlines_org = List_break->value[List_break->n_values - 1];
190  }
191  else {
192  nlines = Vect_get_num_lines(Map);
193  nlines_org = nlines;
194  }
195  G_debug(3, "nlines = %d", nlines);
196 
197 
198  /* TODO:
199  * 1. It seems that lines/boundaries are not broken at intersections
200  * with points/centroids. Check if true, if yes, skip GV_POINTS
201  * 2. list of lines to break and list of reference lines
202  * aline: reference line, if List_ref == NULL, use all
203  * break aline only if it is in the list of lines to break
204  * bline: line to break, if List_break == NULL, break all
205  */
206 
207  /* To find intersection of two lines (Vect_line_intersection) is quite slow.
208  * Fortunately usual lines/boundaries in GIS often forms a network where lines
209  * are connected by end points, and touch by MBR. This function checks and occasionaly
210  * skips such cases. This is currently done for 2D only
211  */
212 
213  /* Go through all lines in vector, for each select lines which overlap MBR of
214  * this line exclude those connected by one endpoint (see above)
215  * and try to intersect, if lines intersect write new lines at the end of
216  * the file, and process next line (remaining lines overlapping box are skipped)
217  */
218  nbreaks = 0;
219 
220  for (iline = 0; iline < nlines; iline++) {
221  G_percent(iline, nlines, 1);
222 
223  /* aline: reference line */
224  if (List_ref) {
225  aline = List_ref->value[iline];
226  }
227  else if (List_break) {
228  aline = List_break->value[iline];
229  }
230  else {
231  aline = iline + 1;
232  }
233 
234  G_debug(3, "aline = %d", aline);
235  if (!Vect_line_alive(Map, aline))
236  continue;
237 
238  a_is_ref = 0;
239  break_a = 1;
240  if (List_ref) {
241  a_is_ref = 1;
242  }
243 
244  if (List_break) {
245  break_a = 0;
246  if (bsearch(&aline, List_break->value, List_break->n_values, sizeof(int), cmp)) {
247  break_a = 1;
248  }
249  }
250 
251  atype = Vect_read_line(Map, APoints, ACats, aline);
252  if (!(atype & type))
253  continue;
254 
255  Vect_line_prune(APoints);
256  Vect_line_box(APoints, &ABox);
257 
258  /* Find which sides of the box are touched by intermediate (non-end) points of line */
259  if (!is3d) {
260  touch1_n = touch1_s = touch1_e = touch1_w = 0;
261  for (j = 1; j < APoints->n_points; j++) {
262  if (APoints->y[j] == ABox.N)
263  touch1_n = 1;
264  if (APoints->y[j] == ABox.S)
265  touch1_s = 1;
266  if (APoints->x[j] == ABox.E)
267  touch1_e = 1;
268  if (APoints->x[j] == ABox.W)
269  touch1_w = 1;
270  }
271  G_debug(3, "touch1: n = %d s = %d e = %d w = %d", touch1_n,
272  touch1_s, touch1_e, touch1_w);
273  touch2_n = touch2_s = touch2_e = touch2_w = 0;
274  for (j = 0; j < APoints->n_points - 1; j++) {
275  if (APoints->y[j] == ABox.N)
276  touch2_n = 1;
277  if (APoints->y[j] == ABox.S)
278  touch2_s = 1;
279  if (APoints->x[j] == ABox.E)
280  touch2_e = 1;
281  if (APoints->x[j] == ABox.W)
282  touch2_w = 1;
283  }
284  G_debug(3, "touch2: n = %d s = %d e = %d w = %d", touch2_n,
285  touch2_s, touch2_e, touch2_w);
286  }
287 
288  Vect_select_lines_by_box(Map, &ABox, type, List);
289  G_debug(3, " %d lines selected by box", List->n_values);
290 
291  for (j = -1; j < List->n_values; j++) {
292 
293  /* bline: line to break */
294 
295  if (j == -1) {
296  /* check first for self-intersections */
297  if (aline <= nlines_org)
298  bline = aline;
299  else
300  continue;
301  }
302  else {
303  bline = List->id[j];
304  if (bline == aline)
305  continue;
306  }
307 
308  b_is_ref = 0;
309  break_b = 1;
310  if (List_ref &&
311  bsearch(&bline, List_ref->value, List_ref->n_values, sizeof(int), cmp)) {
312  b_is_ref = 1;
313  /* reference bline will be broken when it is aline */
314  break_b = 0;
315  }
316 
317  if (List_break) {
318  break_b = 0;
319  if (bsearch(&bline, List_break->value, List_break->n_values, sizeof(int), cmp)) {
320  break_b = 1;
321  }
322  }
323 
324  if (!break_a && !break_b)
325  continue;
326 
327  /* check intersection of aline with bline only once
328  * if possible */
329  if (break_a && break_b &&
330  aline > bline &&
331  (!List_ref || b_is_ref)) {
332  continue;
333  }
334 
335  G_debug(3, " j = %d bline = %d", j, bline);
336 
337  btype = Vect_read_line(Map, BPoints, BCats, bline);
338  Vect_line_prune(BPoints);
339 
340  if (j == -1)
341  BBox = &ABox;
342  else
343  BBox = &List->box[j];
344 
345  /* Check if touch by end node only */
346  if (!is3d) {
347  Vect_get_line_nodes(Map, aline, &anode1, &anode2);
348  Vect_get_line_nodes(Map, bline, &bnode1, &bnode2);
349 
350  node = 0;
351  if (anode1 == bnode1 || anode1 == bnode2)
352  node = anode1;
353  else if (anode2 == bnode1 || anode2 == bnode2)
354  node = anode2;
355 
356  if (node) {
357  Vect_get_node_coor(Map, node, &nodex, &nodey, NULL);
358  if ((node == anode1 && nodey == ABox.N &&
359  !touch1_n && nodey == BBox->S) ||
360  (node == anode2 && nodey == ABox.N &&
361  !touch2_n && nodey == BBox->S) ||
362  (node == anode1 && nodey == ABox.S &&
363  !touch1_s && nodey == BBox->N) ||
364  (node == anode2 && nodey == ABox.S &&
365  !touch2_s && nodey == BBox->N) ||
366  (node == anode1 && nodex == ABox.E &&
367  !touch1_e && nodex == BBox->W) ||
368  (node == anode2 && nodex == ABox.E &&
369  !touch2_e && nodex == BBox->W) ||
370  (node == anode1 && nodex == ABox.W &&
371  !touch1_w && nodex == BBox->E) ||
372  (node == anode2 && nodex == ABox.W &&
373  !touch2_w && nodex == BBox->E)) {
374 
375  G_debug(3,
376  "lines %d and %d touching by end nodes only -> no intersection",
377  aline, bline);
378  continue;
379  }
380  }
381  }
382 
383  AXLines = NULL;
384  BXLines = NULL;
385 
386  if (aline != bline) {
387  Vect_line_intersection2(APoints, BPoints, &ABox, BBox,
388  &AXLines, &BXLines,
389  &naxlines, &nbxlines, 0);
390  }
391  else {
392  Vect_line_intersection2(APoints, NULL, &ABox, BBox,
393  &AXLines, &BXLines,
394  &naxlines, &nbxlines, 0);
395  }
396 
397  G_debug(3, " naxlines = %d nbxlines = %d", naxlines, nbxlines);
398 
399  /* This part handles a special case when aline == bline, no other intersection was found
400  * and the line is forming collapsed loop, for example 0,0;1,0;0,0 should be broken at 1,0.
401  * ---> */
402  if (aline == bline && naxlines == 0 && nbxlines == 0 &&
403  APoints->n_points >= 3 && break_a) {
404  int centre;
405 
406  G_debug(3, " Check collapsed loop");
407  if (APoints->n_points % 2) { /* odd number of vertices */
408  centre = APoints->n_points / 2; /* index of centre */
409  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 */
410  AXLines =
411  (struct line_pnts **)G_malloc(2 *
412  sizeof(struct
413  line_pnts
414  *));
415  AXLines[0] = Vect_new_line_struct();
416  AXLines[1] = Vect_new_line_struct();
417 
418  for (i = 0; i <= centre; i++)
419  Vect_append_point(AXLines[0], APoints->x[i],
420  APoints->y[i], APoints->z[i]);
421 
422  for (i = centre; i < APoints->n_points; i++)
423  Vect_append_point(AXLines[1], APoints->x[i],
424  APoints->y[i], APoints->z[i]);
425 
426  naxlines = 2;
427  }
428  }
429  }
430  /* <--- */
431 
432  if (Err) { /* array for intersections (more than needed */
433  xx = (double *)G_malloc((naxlines + nbxlines) *
434  sizeof(double));
435  yx = (double *)G_malloc((naxlines + nbxlines) *
436  sizeof(double));
437  zx = (double *)G_malloc((naxlines + nbxlines) *
438  sizeof(double));
439  }
440  nx = 0; /* number of intersections to be written to Err */
441  if (naxlines > 0) { /* intersection -> write out */
442 
443  G_debug(3, " aline = %d, bline = %d, naxlines = %d",
444  aline, bline, naxlines);
445 
446  if (!check && break_a)
447  Vect_delete_line(Map, aline);
448  for (k = 0; k < naxlines; k++) {
449  /* Write new line segments */
450  /* line may collapse, don't write zero length lines */
451  Vect_line_prune(AXLines[k]);
452  if ((atype & GV_POINTS) || AXLines[k]->n_points > 1) {
453  if (!check && break_a) {
454  ret = Vect_write_line(Map, atype, AXLines[k],
455  ACats);
456  G_debug(3, "Line %d written, npoints = %d", ret,
457  AXLines[k]->n_points);
458  if (List_ref && a_is_ref) {
459  G_ilist_add(List_ref, ret);
460  }
461  if (List_break && break_a) {
462  G_ilist_add(List_break, ret);
463  }
464  }
465  }
466  else
467  G_debug(3, "axline %d has zero length", k);
468 
469  /* Write intersection points */
470  if (Err) {
471  if (k > 0) {
472  xx[nx] = AXLines[k]->x[0];
473  yx[nx] = AXLines[k]->y[0];
474  zx[nx] = AXLines[k]->z[0];
475  nx++;
476  }
477  }
478  Vect_destroy_line_struct(AXLines[k]);
479  }
480  nbreaks += naxlines - 1;
481  }
482  if (AXLines)
483  G_free(AXLines);
484 
485  if (nbxlines > 0) {
486  if (aline != bline) { /* Self intersection, do not write twice, TODO: is it OK? */
487 
488  G_debug(3, " aline = %d, bline = %d, nbxlines = %d",
489  aline, bline, nbxlines);
490 
491  if (!check && break_b)
492  Vect_delete_line(Map, bline);
493  for (k = 0; k < nbxlines; k++) {
494  /* Write new line segments */
495  /* line may collapse, don't write zero length lines */
496  Vect_line_prune(BXLines[k]);
497  if ((btype & GV_POINTS) || BXLines[k]->n_points > 1) {
498  if (!check && break_b) {
499  ret =
500  Vect_write_line(Map, btype, BXLines[k],
501  BCats);
502  G_debug(5, "Line %d written", ret);
503  if (List_ref && b_is_ref) {
504  G_ilist_add(List_ref, ret);
505  }
506  if (List_break) {
507  G_ilist_add(List_break, ret);
508  }
509  }
510  }
511  else
512  G_debug(3, "bxline %d has zero length", k);
513 
514  /* Write intersection points */
515  if (Err) {
516  if (k > 0) {
517  found = 0;
518  for (l = 0; l < nx; l++) {
519  if (xx[l] == BXLines[k]->x[0] &&
520  yx[l] == BXLines[k]->y[0] &&
521  zx[l] == BXLines[k]->z[0]) {
522  found = 1;
523  break;
524  }
525  }
526  if (!found) {
527  xx[nx] = BXLines[k]->x[0];
528  yx[nx] = BXLines[k]->y[0];
529  zx[nx] = BXLines[k]->z[0];
530  nx++;
531  }
532  }
533  }
534  }
535  nbreaks += nbxlines - 1;
536  }
537  for (k = 0; k < nbxlines; k++)
538  Vect_destroy_line_struct(BXLines[k]);
539  }
540  if (BXLines)
541  G_free(BXLines);
542  if (Err) {
543  for (l = 0; l < nx; l++) { /* Write out errors */
544  Vect_reset_line(Points);
545  Vect_append_point(Points, xx[l], yx[l], zx[l]);
546  ret = Vect_write_line(Err, GV_POINT, Points, Cats);
547  }
548 
549  G_free(xx);
550  G_free(yx);
551  G_free(zx);
552  }
553  if (naxlines > 0 && !check && break_a) {
554  G_debug(3, "aline was broken, use next one");
555  break; /* first line was broken and deleted -> take the next one */
556  }
557  }
558 
559  if (List_ref) {
560  nlines = List_ref->n_values;
561  }
562  else if (List_break) {
563  nlines = List_break->n_values;
564  }
565  else {
566  nlines = Vect_get_num_lines(Map);
567  }
568  G_debug(3, "nlines = %d", nlines);
569  } /* for each line */
570  G_percent(nlines, nlines, 1); /* finish it */
571 
572  G_verbose_message(_("Intersections: %d"), nbreaks);
573 
574  Vect_destroy_line_struct(APoints);
575  Vect_destroy_line_struct(BPoints);
576  Vect_destroy_line_struct(Points);
580  Vect_destroy_boxlist(List);
581 
582  return nbreaks;
583 }
struct boxlist * Vect_new_boxlist(int have_boxes)
Creates and initializes a struct boxlist.
int Vect_select_lines_by_box(struct Map_info *Map, const struct bound_box *Box, int type, struct boxlist *list)
Select lines with bounding boxes by box.
Definition: sindex.c:34
Bounding box.
Definition: dig_structs.h:65
int Vect_line_intersection2(struct line_pnts *APoints, struct line_pnts *BPoints, struct bound_box *ABox, struct bound_box *BBox, struct line_pnts ***ALines, struct line_pnts ***BLines, int *nalines, int *nblines, int with_z)
Intersect 2 lines.
Definition: intersect2.c:582
void G_free(void *buf)
Free allocated memory.
Definition: gis/alloc.c:149
int * id
Array of ids.
Definition: dig_structs.h:1755
double W
West.
Definition: dig_structs.h:82
int Vect_get_node_coor(const struct Map_info *Map, int num, double *x, double *y, double *z)
Get node coordinates.
Definition: level_two.c:278
void G_verbose_message(const char *msg,...)
Print a message to stderr but only if module is in verbose mode.
Definition: gis/error.c:108
void Vect_line_box(const struct line_pnts *Points, struct bound_box *Box)
Get bounding box of line.
Definition: line.c:922
struct line_pnts * Vect_new_line_struct()
Creates and initializes a line_pnts structure.
Definition: line.c:45
off_t Vect_write_line(struct Map_info *Map, int type, const struct line_pnts *points, const struct line_cats *cats)
Writes a new feature.
int n_points
Number of points.
Definition: dig_structs.h:1692
void Vect_destroy_boxlist(struct boxlist *list)
Frees all memory associated with a struct boxlist, including the struct itself.
int Vect_line_alive(const struct Map_info *Map, int line)
Check if feature is alive or dead (topological level required)
int n_values
Number of values in the list.
Definition: gis.h:659
#define GV_POINTS
Definition: dig_defines.h:191
void Vect_destroy_line_struct(struct line_pnts *p)
Frees all memory associated with a line_pnts structure, including the structure itself.
Definition: line.c:77
double E
East.
Definition: dig_structs.h:78
void Vect_destroy_cats_struct(struct line_cats *p)
Frees all memory associated with line_cats structure, including the struct itself.
#define NULL
Definition: ccmath.h:32
int Vect_delete_line(struct Map_info *Map, off_t line)
Delete existing feature (topological level required)
#define x
int n_values
Number of items in the list.
Definition: dig_structs.h:1767
#define GV_POINT
Feature types used in memory on run time (may change)
Definition: dig_defines.h:182
struct bound_box * box
Array of bounding boxes.
Definition: dig_structs.h:1759
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:149
Feature category info.
Definition: dig_structs.h:1702
double N
North.
Definition: dig_structs.h:70
double * x
Array of X coordinates.
Definition: dig_structs.h:1680
double l
Definition: r_raster.c:39
Feature geometry info - coordinates.
Definition: dig_structs.h:1675
int Vect_is_3d(const struct Map_info *Map)
Check if vector map is 3D.
double b
Definition: r_raster.c:39
int Vect_check_line_breaks(struct Map_info *Map, int type, struct Map_info *Err)
Check for and count intersecting lines, do not break.
Definition: break_lines.c:80
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: debug.c:65
int Vect_check_line_breaks_list(struct Map_info *Map, struct ilist *List_break, struct ilist *List_ref, int type, struct Map_info *Err)
Check for and count intersecting lines, do not break.
Definition: break_lines.c:102
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:62
void G_percent(long n, long d, int s)
Print percent complete messages.
Definition: percent.c:62
Vector map info.
Definition: dig_structs.h:1259
double * y
Array of Y coordinates.
Definition: dig_structs.h:1684
int Vect_get_line_nodes(const struct Map_info *Map, int line, int *n1, int *n2)
Get line nodes.
Definition: level_two.c:307
struct line_cats * Vect_new_cats_struct()
Creates and initializes line_cats structure.
int Vect_line_prune(struct line_pnts *Points)
Remove duplicate points, i.e. zero length segments.
Definition: line.c:281
plus_t Vect_get_num_lines(const struct Map_info *Map)
Fetch number of features (points, lines, boundaries, centroids) in vector map.
Definition: level_two.c:74
List of bounding boxes with id.
Definition: dig_structs.h:1750
double S
South.
Definition: dig_structs.h:74
double * z
Array of Z coordinates.
Definition: dig_structs.h:1688
#define _(str)
Definition: glocale.h:13
List of integers.
Definition: gis.h:650
int Vect_read_line(const struct Map_info *Map, struct line_pnts *line_p, struct line_cats *line_c, int line)
Read vector feature (topological level required)
void Vect_reset_line(struct line_pnts *Points)
Reset line.
Definition: line.c:130
int * value
Array of values.
Definition: gis.h:655
#define GV_LINES
Definition: dig_defines.h:192
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:33
void G_ilist_add(struct ilist *list, int val)
Add item to ilist.
Definition: ilist.c:77