GRASS GIS 7 Programmer's Manual  7.7.svn(2019)-r74103
 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  /* ai - bi is ok because ai and bi are positive integers
115  * -> no integer overflow */
116  return (ai - bi);
117 }
118 
119 static void sort_ilist(struct ilist *List)
120 {
121  int i, j, is_sorted = 1;
122 
123  for (i = 1; i < List->n_values; i++) {
124  if (List->value[i - 1] > List->value[i]) {
125  is_sorted = 0;
126  break;
127  }
128  }
129 
130  if (!is_sorted)
131  qsort(List->value, List->n_values, sizeof(int), cmp);
132 
133  if (List->n_values > 1) {
134  j = 1;
135  for (i = 1; i < List->n_values; i++) {
136  if (List->value[j - 1] != List->value[i]) {
137  List->value[j] = List->value[i];
138  j++;
139  }
140  }
141  List->n_values = j;
142  }
143 }
144 
145 int break_lines(struct Map_info *Map, struct ilist *List_break,
146  struct ilist *List_ref, int type,
147  struct Map_info *Err, int check)
148 {
149  struct line_pnts *APoints, *BPoints, *Points;
150  struct line_pnts **AXLines, **BXLines;
151  struct line_cats *ACats, *BCats, *Cats;
152  int i, j, k, l, ret, atype, btype, aline, bline, found, iline;
153  int nlines, nlines_org;
154  int naxlines, nbxlines, nx;
155  double *xx = NULL, *yx = NULL, *zx = NULL;
156  struct bound_box ABox, *BBox;
157  struct boxlist *List;
158  int nbreaks;
159  int touch1_n = 0, touch1_s = 0, touch1_e = 0, touch1_w = 0; /* other vertices except node1 touching box */
160  int touch2_n = 0, touch2_s = 0, touch2_e = 0, touch2_w = 0; /* other vertices except node2 touching box */
161  int is3d;
162  int node, anode1, anode2, bnode1, bnode2;
163  double nodex, nodey;
164  int a_is_ref, b_is_ref, break_a, break_b;
165 
166  type &= GV_LINES;
167  if (!type)
168  return 0;
169 
170  APoints = Vect_new_line_struct();
171  BPoints = Vect_new_line_struct();
172  Points = Vect_new_line_struct();
173  ACats = Vect_new_cats_struct();
174  BCats = Vect_new_cats_struct();
175  Cats = Vect_new_cats_struct();
176  List = Vect_new_boxlist(1);
177 
178  is3d = Vect_is_3d(Map);
179 
180  if (List_ref)
181  sort_ilist(List_ref);
182  if (List_break)
183  sort_ilist(List_break);
184 
185  if (List_ref) {
186  nlines = List_ref->n_values;
187  nlines_org = List_ref->value[List_ref->n_values - 1];
188  }
189  else if (List_break) {
190  nlines = List_break->n_values;
191  nlines_org = List_break->value[List_break->n_values - 1];
192  }
193  else {
194  nlines = Vect_get_num_lines(Map);
195  nlines_org = nlines;
196  }
197  G_debug(3, "nlines = %d", nlines);
198 
199 
200  /* TODO:
201  * 1. It seems that lines/boundaries are not broken at intersections
202  * with points/centroids. Check if true, if yes, skip GV_POINTS
203  * 2. list of lines to break and list of reference lines
204  * aline: reference line, if List_ref == NULL, use all
205  * break aline only if it is in the list of lines to break
206  * bline: line to break, if List_break == NULL, break all
207  */
208 
209  /* To find intersection of two lines (Vect_line_intersection) is quite slow.
210  * Fortunately usual lines/boundaries in GIS often forms a network where lines
211  * are connected by end points, and touch by MBR. This function checks and occasionaly
212  * skips such cases. This is currently done for 2D only
213  */
214 
215  /* Go through all lines in vector, for each select lines which overlap MBR of
216  * this line exclude those connected by one endpoint (see above)
217  * and try to intersect, if lines intersect write new lines at the end of
218  * the file, and process next line (remaining lines overlapping box are skipped)
219  */
220  nbreaks = 0;
221 
222  for (iline = 0; iline < nlines; iline++) {
223  G_percent(iline, nlines, 1);
224 
225  /* aline: reference line */
226  if (List_ref) {
227  aline = List_ref->value[iline];
228  }
229  else if (List_break) {
230  aline = List_break->value[iline];
231  }
232  else {
233  aline = iline + 1;
234  }
235 
236  G_debug(3, "aline = %d", aline);
237  if (!Vect_line_alive(Map, aline))
238  continue;
239 
240  a_is_ref = 0;
241  break_a = 1;
242  if (List_ref) {
243  a_is_ref = 1;
244  }
245 
246  if (List_break) {
247  break_a = 0;
248  if (bsearch(&aline, List_break->value, List_break->n_values, sizeof(int), cmp)) {
249  break_a = 1;
250  }
251  }
252 
253  atype = Vect_read_line(Map, APoints, ACats, aline);
254  if (!(atype & type))
255  continue;
256 
257  Vect_line_prune(APoints);
258  Vect_line_box(APoints, &ABox);
259 
260  /* Find which sides of the box are touched by intermediate (non-end) points of line */
261  if (!is3d) {
262  touch1_n = touch1_s = touch1_e = touch1_w = 0;
263  for (j = 1; j < APoints->n_points; j++) {
264  if (APoints->y[j] == ABox.N)
265  touch1_n = 1;
266  if (APoints->y[j] == ABox.S)
267  touch1_s = 1;
268  if (APoints->x[j] == ABox.E)
269  touch1_e = 1;
270  if (APoints->x[j] == ABox.W)
271  touch1_w = 1;
272  }
273  G_debug(3, "touch1: n = %d s = %d e = %d w = %d", touch1_n,
274  touch1_s, touch1_e, touch1_w);
275  touch2_n = touch2_s = touch2_e = touch2_w = 0;
276  for (j = 0; j < APoints->n_points - 1; j++) {
277  if (APoints->y[j] == ABox.N)
278  touch2_n = 1;
279  if (APoints->y[j] == ABox.S)
280  touch2_s = 1;
281  if (APoints->x[j] == ABox.E)
282  touch2_e = 1;
283  if (APoints->x[j] == ABox.W)
284  touch2_w = 1;
285  }
286  G_debug(3, "touch2: n = %d s = %d e = %d w = %d", touch2_n,
287  touch2_s, touch2_e, touch2_w);
288  }
289 
290  Vect_select_lines_by_box(Map, &ABox, type, List);
291  G_debug(3, " %d lines selected by box", List->n_values);
292 
293  for (j = -1; j < List->n_values; j++) {
294 
295  /* bline: line to break */
296 
297  if (j == -1) {
298  /* check first for self-intersections */
299  if (aline <= nlines_org)
300  bline = aline;
301  else
302  continue;
303  }
304  else {
305  bline = List->id[j];
306  if (bline == aline)
307  continue;
308  }
309 
310  b_is_ref = 0;
311  break_b = 1;
312  if (List_ref &&
313  bsearch(&bline, List_ref->value, List_ref->n_values, sizeof(int), cmp)) {
314  b_is_ref = 1;
315  /* reference bline will be broken when it is aline */
316  break_b = 0;
317  }
318 
319  if (List_break) {
320  break_b = 0;
321  if (bsearch(&bline, List_break->value, List_break->n_values, sizeof(int), cmp)) {
322  break_b = 1;
323  }
324  }
325 
326  if (!break_a && !break_b)
327  continue;
328 
329  /* check intersection of aline with bline only once
330  * if possible */
331  if (break_a && break_b &&
332  aline > bline &&
333  (!List_ref || b_is_ref)) {
334  continue;
335  }
336 
337  G_debug(3, " j = %d bline = %d", j, bline);
338 
339  btype = Vect_read_line(Map, BPoints, BCats, bline);
340  Vect_line_prune(BPoints);
341 
342  if (j == -1)
343  BBox = &ABox;
344  else
345  BBox = &List->box[j];
346 
347  /* Check if touch by end node only */
348  if (!is3d) {
349  Vect_get_line_nodes(Map, aline, &anode1, &anode2);
350  Vect_get_line_nodes(Map, bline, &bnode1, &bnode2);
351 
352  node = 0;
353  if (anode1 == bnode1 || anode1 == bnode2)
354  node = anode1;
355  else if (anode2 == bnode1 || anode2 == bnode2)
356  node = anode2;
357 
358  if (node) {
359  Vect_get_node_coor(Map, node, &nodex, &nodey, NULL);
360  if ((node == anode1 && nodey == ABox.N &&
361  !touch1_n && nodey == BBox->S) ||
362  (node == anode2 && nodey == ABox.N &&
363  !touch2_n && nodey == BBox->S) ||
364  (node == anode1 && nodey == ABox.S &&
365  !touch1_s && nodey == BBox->N) ||
366  (node == anode2 && nodey == ABox.S &&
367  !touch2_s && nodey == BBox->N) ||
368  (node == anode1 && nodex == ABox.E &&
369  !touch1_e && nodex == BBox->W) ||
370  (node == anode2 && nodex == ABox.E &&
371  !touch2_e && nodex == BBox->W) ||
372  (node == anode1 && nodex == ABox.W &&
373  !touch1_w && nodex == BBox->E) ||
374  (node == anode2 && nodex == ABox.W &&
375  !touch2_w && nodex == BBox->E)) {
376 
377  G_debug(3,
378  "lines %d and %d touching by end nodes only -> no intersection",
379  aline, bline);
380  continue;
381  }
382  }
383  }
384 
385  AXLines = NULL;
386  BXLines = NULL;
387 
388  if (aline != bline) {
389  Vect_line_intersection2(APoints, BPoints, &ABox, BBox,
390  &AXLines, &BXLines,
391  &naxlines, &nbxlines, 0);
392  }
393  else {
394  Vect_line_intersection2(APoints, NULL, &ABox, BBox,
395  &AXLines, &BXLines,
396  &naxlines, &nbxlines, 0);
397  }
398 
399  G_debug(3, " naxlines = %d nbxlines = %d", naxlines, nbxlines);
400 
401  /* This part handles a special case when aline == bline, no other intersection was found
402  * and the line is forming collapsed loop, for example 0,0;1,0;0,0 should be broken at 1,0.
403  * ---> */
404  if (aline == bline && naxlines == 0 && nbxlines == 0 &&
405  APoints->n_points >= 3 && break_a) {
406  int centre;
407 
408  G_debug(3, " Check collapsed loop");
409  if (APoints->n_points % 2) { /* odd number of vertices */
410  centre = APoints->n_points / 2; /* index of centre */
411  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 */
412  AXLines =
413  (struct line_pnts **)G_malloc(2 *
414  sizeof(struct
415  line_pnts
416  *));
417  AXLines[0] = Vect_new_line_struct();
418  AXLines[1] = Vect_new_line_struct();
419 
420  for (i = 0; i <= centre; i++)
421  Vect_append_point(AXLines[0], APoints->x[i],
422  APoints->y[i], APoints->z[i]);
423 
424  for (i = centre; i < APoints->n_points; i++)
425  Vect_append_point(AXLines[1], APoints->x[i],
426  APoints->y[i], APoints->z[i]);
427 
428  naxlines = 2;
429  }
430  }
431  }
432  /* <--- */
433 
434  if (Err) { /* array for intersections (more than needed */
435  xx = (double *)G_malloc((naxlines + nbxlines) *
436  sizeof(double));
437  yx = (double *)G_malloc((naxlines + nbxlines) *
438  sizeof(double));
439  zx = (double *)G_malloc((naxlines + nbxlines) *
440  sizeof(double));
441  }
442  nx = 0; /* number of intersections to be written to Err */
443  if (naxlines > 0) { /* intersection -> write out */
444 
445  G_debug(3, " aline = %d, bline = %d, naxlines = %d",
446  aline, bline, naxlines);
447 
448  if (!check && break_a)
449  Vect_delete_line(Map, aline);
450  for (k = 0; k < naxlines; k++) {
451  /* Write new line segments */
452  /* line may collapse, don't write zero length lines */
453  Vect_line_prune(AXLines[k]);
454  if ((atype & GV_POINTS) || AXLines[k]->n_points > 1) {
455  if (!check && break_a) {
456  ret = Vect_write_line(Map, atype, AXLines[k],
457  ACats);
458  G_debug(3, "Line %d written, npoints = %d", ret,
459  AXLines[k]->n_points);
460  if (List_ref && a_is_ref) {
461  G_ilist_add(List_ref, ret);
462  }
463  if (List_break && break_a) {
464  G_ilist_add(List_break, ret);
465  }
466  }
467  }
468  else
469  G_debug(3, "axline %d has zero length", k);
470 
471  /* Write intersection points */
472  if (Err) {
473  if (k > 0) {
474  xx[nx] = AXLines[k]->x[0];
475  yx[nx] = AXLines[k]->y[0];
476  zx[nx] = AXLines[k]->z[0];
477  nx++;
478  }
479  }
480  Vect_destroy_line_struct(AXLines[k]);
481  }
482  nbreaks += naxlines - 1;
483  }
484  if (AXLines)
485  G_free(AXLines);
486 
487  if (nbxlines > 0) {
488  if (aline != bline) { /* Self intersection, do not write twice, TODO: is it OK? */
489 
490  G_debug(3, " aline = %d, bline = %d, nbxlines = %d",
491  aline, bline, nbxlines);
492 
493  if (!check && break_b)
494  Vect_delete_line(Map, bline);
495  for (k = 0; k < nbxlines; k++) {
496  /* Write new line segments */
497  /* line may collapse, don't write zero length lines */
498  Vect_line_prune(BXLines[k]);
499  if ((btype & GV_POINTS) || BXLines[k]->n_points > 1) {
500  if (!check && break_b) {
501  ret =
502  Vect_write_line(Map, btype, BXLines[k],
503  BCats);
504  G_debug(5, "Line %d written", ret);
505  if (List_ref && b_is_ref) {
506  G_ilist_add(List_ref, ret);
507  }
508  if (List_break) {
509  G_ilist_add(List_break, ret);
510  }
511  }
512  }
513  else
514  G_debug(3, "bxline %d has zero length", k);
515 
516  /* Write intersection points */
517  if (Err) {
518  if (k > 0) {
519  found = 0;
520  for (l = 0; l < nx; l++) {
521  if (xx[l] == BXLines[k]->x[0] &&
522  yx[l] == BXLines[k]->y[0] &&
523  zx[l] == BXLines[k]->z[0]) {
524  found = 1;
525  break;
526  }
527  }
528  if (!found) {
529  xx[nx] = BXLines[k]->x[0];
530  yx[nx] = BXLines[k]->y[0];
531  zx[nx] = BXLines[k]->z[0];
532  nx++;
533  }
534  }
535  }
536  }
537  nbreaks += nbxlines - 1;
538  }
539  for (k = 0; k < nbxlines; k++)
540  Vect_destroy_line_struct(BXLines[k]);
541  }
542  if (BXLines)
543  G_free(BXLines);
544  if (Err) {
545  for (l = 0; l < nx; l++) { /* Write out errors */
546  Vect_reset_line(Points);
547  Vect_append_point(Points, xx[l], yx[l], zx[l]);
548  ret = Vect_write_line(Err, GV_POINT, Points, Cats);
549  }
550 
551  G_free(xx);
552  G_free(yx);
553  G_free(zx);
554  }
555  if (naxlines > 0 && !check && break_a) {
556  G_debug(3, "aline was broken, use next one");
557  break; /* first line was broken and deleted -> take the next one */
558  }
559  }
560 
561  if (List_ref) {
562  nlines = List_ref->n_values;
563  }
564  else if (List_break) {
565  nlines = List_break->n_values;
566  }
567  else {
568  nlines = Vect_get_num_lines(Map);
569  }
570  G_debug(3, "nlines = %d", nlines);
571  } /* for each line */
572  G_percent(nlines, nlines, 1); /* finish it */
573 
574  G_verbose_message(_("Intersections: %d"), nbreaks);
575 
576  Vect_destroy_line_struct(APoints);
577  Vect_destroy_line_struct(BPoints);
578  Vect_destroy_line_struct(Points);
582  Vect_destroy_boxlist(List);
583 
584  return nbreaks;
585 }
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
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:109
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:683
#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
int Vect_line_intersection2(struct line_pnts *APoints, struct line_pnts *BPoints, struct bound_box *pABox, struct bound_box *pBBox, struct line_pnts ***ALines, struct line_pnts ***BLines, int *nalines, int *nblines, int with_z)
Intersect 2 lines.
Definition: intersect2.c:683
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:674
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:679
#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