GRASS GIS 8 Programmer's Manual  8.5.0dev(2024)-d6dec75dd4
break_polygons.c
Go to the documentation of this file.
1 /*!
2  \file lib/vector/Vlib/break_polygons.c
3 
4  \brief Vector library - clean geometry (break polygons)
5 
6  Higher level functions for reading/writing/manipulating vectors.
7 
8  (C) 2001-2009 by the GRASS Development Team
9 
10  This program is free software under the GNU General Public License
11  (>=v2). Read the file COPYING that comes with GRASS for details.
12 
13  \author Radim Blazek
14  \author Update for GRASS 7 Markus Metz
15  */
16 
17 #include <stdlib.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <math.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <grass/vector.h>
25 #include <grass/glocale.h>
26 
27 /* TODO: 3D support
28  *
29  * atan2() gives angle from x-axis
30  * this is unambiguous only in 2D, not in 3D
31  *
32  * one possibility would be to store unit vectors of length 1
33  * in struct XPNT
34  * double a1[3], a2[3];
35  *
36  * length = sqrt(dx * dx + dy * dy + dz * dz);
37  * dx /= length; dy /= length; dz /=length;
38  * a1[0] = dx; a1[1] = dy; a1[2] = dz;
39  *
40  * get second dx, dy, dz
41  * length = sqrt(dx * dx + dy * dy + dz * dz);
42  * dx /= length; dy /= length; dz /=length;
43  * a2[0] = dx; a2[1] = dy; a2[2] = dz;
44  *
45  * equal angles
46  * if (a1[0] == a2[0] && a1[1] == a2[1] && a1[2] == a2[2])
47  *
48  * disadvantage: increased memory consumption
49  *
50  * new function Vect_break_faces() ?
51  *
52  */
53 
54 typedef struct {
55  double x, y; /* coords */
56  double a1, a2; /* angles */
57  char cross; /* 0 - do not break, 1 - break */
58  char used; /* 0 - was not used to break line, 1 - was used to break line
59  * this is stored because points are automatically marked as
60  * cross, even if not used later to break lines */
61 } XPNT;
62 
63 typedef struct {
64  double a1, a2; /* angles */
65  char cross; /* 0 - do not break, 1 - break */
66  char used; /* 0 - was not used to break line, 1 - was used to break line
67  * this is stored because points are automatically marked as
68  * cross, even if not used later to break lines */
69 } XPNT2;
70 
71 static int fpoint;
72 
73 /* Function called from RTreeSearch for point found */
74 static int srch(int id, const struct RTree_Rect *rect UNUSED, void *arg UNUSED)
75 {
76  fpoint = id;
77 
78  return 0; /* stop searching */
79 }
80 
81 /* function used by binary tree to compare items */
82 static int compare_xpnts(const void *Xpnta, const void *Xpntb)
83 {
84  XPNT *a, *b;
85 
86  a = (XPNT *)Xpnta;
87  b = (XPNT *)Xpntb;
88 
89  if (a->x > b->x)
90  return 1;
91  else if (a->x < b->x)
92  return -1;
93  else {
94  if (a->y > b->y)
95  return 1;
96  else if (a->y < b->y)
97  return -1;
98  else
99  return 0;
100  }
101 
102  G_warning(_("Break polygons: Bug in binary tree!"));
103  return 1;
104 }
105 
106 /* break polygons using a file-based search index */
107 void Vect_break_polygons_file(struct Map_info *Map, int type,
108  struct Map_info *Err)
109 {
110  struct line_pnts *BPoints, *Points;
111  struct line_cats *Cats, *ErrCats;
112  int i, j, k, ret, ltype, broken, last, nlines;
113  int nbreaks;
114  struct RTree *RTree;
115  int npoints;
116  XPNT2 XPnt;
117  double dx, dy, a1 = 0, a2 = 0;
118  int closed, last_point;
119  char cross;
120  int fd, xpntfd;
121  char *filename;
122  static struct RTree_Rect rect;
123  static int rect_init = 0;
124 
125  if (!rect_init) {
126  rect.boundary = G_malloc(6 * sizeof(RectReal));
127  rect_init = 6;
128  }
129 
130  G_debug(1, "File-based version of Vect_break_polygons()");
131 
132  filename = G_tempfile();
133  fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
134  RTree = RTreeCreateTree(fd, 0, 2);
135  (void)remove(filename);
136  G_free(filename);
137 
138  filename = G_tempfile();
139  xpntfd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
140  if (xpntfd < 0) {
141  close(RTree->fd);
142  G_free(filename);
143  G_fatal_error(_("Failed to create xpnt temporary file: %s"),
144  strerror(errno));
145  }
146  (void)remove(filename);
147  G_free(filename);
148 
149  BPoints = Vect_new_line_struct();
150  Points = Vect_new_line_struct();
151  Cats = Vect_new_cats_struct();
152  ErrCats = Vect_new_cats_struct();
153 
154  nlines = Vect_get_num_lines(Map);
155 
156  G_debug(3, "nlines = %d", nlines);
157  /* Go through all lines in vector, and add each point to structure of
158  * points, if such point already exists check angles of segments and if
159  * differ mark for break */
160 
161  npoints = 1; /* index starts from 1 ! */
162  XPnt.used = 0;
163 
164  G_message(_("Breaking polygons (pass 1: select break points)..."));
165 
166  for (i = 1; i <= nlines; i++) {
167  G_percent(i, nlines, 1);
168  G_debug(3, "i = %d", i);
169  if (!Vect_line_alive(Map, i))
170  continue;
171 
172  ltype = Vect_read_line(Map, Points, Cats, i);
173  if (!(ltype & type))
174  continue;
175 
176  /* This would be confused by duplicate coordinates (angle cannot be
177  * calculated) -> prune line first */
178  Vect_line_prune(Points);
179 
180  /* If first and last point are identical it is close polygon, we don't
181  * need to register last point and we can calculate angle for first. If
182  * first and last point are not identical we have to mark for break both
183  */
184  last_point = Points->n_points - 1;
185  if (Points->x[0] == Points->x[last_point] &&
186  Points->y[0] == Points->y[last_point])
187  closed = 1;
188  else
189  closed = 0;
190 
191  for (j = 0; j < Points->n_points; j++) {
192  G_debug(3, "j = %d", j);
193 
194  if (j == last_point && closed)
195  continue; /* do not register last of close polygon */
196 
197  /* Box */
198  rect.boundary[0] = Points->x[j];
199  rect.boundary[3] = Points->x[j];
200  rect.boundary[1] = Points->y[j];
201  rect.boundary[4] = Points->y[j];
202  rect.boundary[2] = 0;
203  rect.boundary[5] = 0;
204 
205  /* Already in DB? */
206  fpoint = -1;
207  RTreeSearch(RTree, &rect, srch, NULL);
208  G_debug(3, "fpoint = %d", fpoint);
209 
210  if (Points->n_points <= 2 ||
211  (!closed && (j == 0 || j == last_point))) {
212  cross = 1; /* mark for cross in any case */
213  }
214  else { /* calculate angles */
215  cross = 0;
216  if (j == 0 && closed) { /* closed polygon */
217  dx = Points->x[last_point] - Points->x[0];
218  dy = Points->y[last_point] - Points->y[0];
219  a1 = atan2(dy, dx);
220  dx = Points->x[1] - Points->x[0];
221  dy = Points->y[1] - Points->y[0];
222  a2 = atan2(dy, dx);
223  }
224  else {
225  dx = Points->x[j - 1] - Points->x[j];
226  dy = Points->y[j - 1] - Points->y[j];
227  a1 = atan2(dy, dx);
228  dx = Points->x[j + 1] - Points->x[j];
229  dy = Points->y[j + 1] - Points->y[j];
230  a2 = atan2(dy, dx);
231  }
232  }
233 
234  if (fpoint > 0) { /* Found */
235  /* read point */
236  lseek(xpntfd, (off_t)(fpoint - 1) * sizeof(XPNT2), SEEK_SET);
237  if (read(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
238  G_fatal_error(_("File reading error in %s() %d:%s"),
239  __func__, errno, strerror(errno));
240  if (XPnt.cross == 1)
241  continue; /* already marked */
242 
243  /* Check angles */
244  if (cross) {
245  XPnt.cross = 1;
246  /* write point */
247  lseek(xpntfd, (off_t)(fpoint - 1) * sizeof(XPNT2),
248  SEEK_SET);
249  if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
250  G_fatal_error(_("File writing error in %s() %d:%s"),
251  __func__, errno, strerror(errno));
252  }
253  else {
254  G_debug(3, "a1 = %f xa1 = %f a2 = %f xa2 = %f", a1, XPnt.a1,
255  a2, XPnt.a2);
256  if ((a1 == XPnt.a1 && a2 == XPnt.a2) ||
257  (a1 == XPnt.a2 && a2 == XPnt.a1)) { /* identical */
258  }
259  else {
260  XPnt.cross = 1;
261  /* write point */
262  lseek(xpntfd, (off_t)(fpoint - 1) * sizeof(XPNT2),
263  SEEK_SET);
264  if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
265  G_fatal_error(_("File writing error in %s() %d:%s"),
266  __func__, errno, strerror(errno));
267  }
268  }
269  }
270  else {
271  /* Add to tree and to structure */
272  RTreeInsertRect(&rect, npoints, RTree);
273  if (j == 0 || j == (Points->n_points - 1) ||
274  Points->n_points < 3) {
275  XPnt.a1 = 0;
276  XPnt.a2 = 0;
277  XPnt.cross = 1;
278  }
279  else {
280  XPnt.a1 = a1;
281  XPnt.a2 = a2;
282  XPnt.cross = 0;
283  }
284  /* write point */
285  lseek(xpntfd, (off_t)(npoints - 1) * sizeof(XPNT2), SEEK_SET);
286  if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
287  G_fatal_error(_("File writing error in %s() %d:%s"),
288  __func__, errno, strerror(errno));
289 
290  npoints++;
291  }
292  }
293  }
294 
295  nbreaks = 0;
296 
297  /* Second loop through lines (existing when loop is started, no need to
298  * process lines written again) and break at points marked for break */
299 
300  G_message(_("Breaking polygons (pass 2: break at selected points)..."));
301 
302  for (i = 1; i <= nlines; i++) {
303  int n_orig_points;
304 
305  G_percent(i, nlines, 1);
306  G_debug(3, "i = %d", i);
307  if (!Vect_line_alive(Map, i))
308  continue;
309 
310  ltype = Vect_read_line(Map, Points, Cats, i);
311  if (!(ltype & type))
312  continue;
313  if (!(ltype & GV_LINES))
314  continue; /* Nonsense to break points */
315 
316  /* Duplicates would result in zero length lines -> prune line first */
317  n_orig_points = Points->n_points;
318  Vect_line_prune(Points);
319 
320  broken = 0;
321  last = 0;
322  G_debug(3, "n_points = %d", Points->n_points);
323  for (j = 1; j < Points->n_points; j++) {
324  G_debug(3, "j = %d", j);
325 
326  /* Box */
327  rect.boundary[0] = Points->x[j];
328  rect.boundary[3] = Points->x[j];
329  rect.boundary[1] = Points->y[j];
330  rect.boundary[4] = Points->y[j];
331  rect.boundary[2] = 0;
332  rect.boundary[5] = 0;
333 
334  if (Points->n_points <= 1 ||
335  (j == (Points->n_points - 1) && !broken))
336  break;
337  /* One point only or
338  * last point and line is not broken, do nothing */
339 
340  RTreeSearch(RTree, &rect, srch, NULL);
341  G_debug(3, "fpoint = %d", fpoint);
342 
343  /* read point */
344  lseek(xpntfd, (off_t)(fpoint - 1) * sizeof(XPNT2), SEEK_SET);
345  if (read(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
346  G_fatal_error(_("File reading error in %s() %d:%s"), __func__,
347  errno, strerror(errno));
348 
349  /* break or write last segment of broken line */
350  if ((j == (Points->n_points - 1) && broken) || XPnt.cross) {
351  Vect_reset_line(BPoints);
352  for (k = last; k <= j; k++) {
353  Vect_append_point(BPoints, Points->x[k], Points->y[k],
354  Points->z[k]);
355  }
356 
357  /* Result may collapse to one point */
358  Vect_line_prune(BPoints);
359  if (BPoints->n_points > 1) {
360  ret = Vect_write_line(Map, ltype, BPoints, Cats);
361  G_debug(3,
362  "Line %d written j = %d n_points(orig,pruned) = %d "
363  "n_points(new) = %d",
364  ret, j, Points->n_points, BPoints->n_points);
365  }
366 
367  if (!broken)
368  Vect_delete_line(Map, i); /* not yet deleted */
369 
370  /* Write points on breaks */
371  if (Err) {
372  if (XPnt.cross && !XPnt.used) {
373  Vect_reset_line(BPoints);
374  Vect_append_point(BPoints, Points->x[j], Points->y[j],
375  0);
376  Vect_write_line(Err, GV_POINT, BPoints, ErrCats);
377  }
378  if (!XPnt.used) {
379  XPnt.used = 1;
380  /* write point */
381  lseek(xpntfd, (off_t)(fpoint - 1) * sizeof(XPNT2),
382  SEEK_SET);
383  if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
384  G_fatal_error(_("File writing error in %s() %d:%s"),
385  __func__, errno, strerror(errno));
386  }
387  }
388 
389  last = j;
390  broken = 1;
391  nbreaks++;
392  }
393  }
394  if (!broken &&
395  n_orig_points >
396  Points->n_points) { /* was pruned before -> rewrite */
397  if (Points->n_points > 1) {
398  Vect_rewrite_line(Map, i, ltype, Points, Cats);
399  G_debug(3, "Line %d pruned, npoints = %d", i, Points->n_points);
400  }
401  else {
402  Vect_delete_line(Map, i);
403  G_debug(3, "Line %d was deleted", i);
404  }
405  }
406  else {
407  G_debug(3, "Line %d was not changed", i);
408  }
409  }
410 
411  close(RTree->fd);
413  close(xpntfd);
414  Vect_destroy_line_struct(Points);
415  Vect_destroy_line_struct(BPoints);
417  Vect_destroy_cats_struct(ErrCats);
418  G_verbose_message(_("Breaks: %d"), nbreaks);
419 }
420 
421 /* break polygons using a memory-based search index */
422 void Vect_break_polygons_mem(struct Map_info *Map, int type,
423  struct Map_info *Err)
424 {
425  struct line_pnts *BPoints, *Points;
426  struct line_cats *Cats, *ErrCats;
427  int i, j, k, ret, ltype, broken, last, nlines;
428  int nbreaks;
429  struct RB_TREE *RBTree;
430  XPNT *XPnt_found, XPnt_search;
431  double dx, dy, a1 = 0, a2 = 0;
432  int closed, last_point, cross;
433 
434  G_debug(1, "Memory-based version of Vect_break_polygons()");
435 
436  RBTree = rbtree_create(compare_xpnts, sizeof(XPNT));
437 
438  BPoints = Vect_new_line_struct();
439  Points = Vect_new_line_struct();
440  Cats = Vect_new_cats_struct();
441  ErrCats = Vect_new_cats_struct();
442 
443  nlines = Vect_get_num_lines(Map);
444 
445  G_debug(3, "nlines = %d", nlines);
446  /* Go through all lines in vector, and add each point to structure of
447  * points, if such point already exists check angles of segments and if
448  * differ mark for break */
449 
450  XPnt_search.used = 0;
451 
452  G_message(_("Breaking polygons (pass 1: select break points)..."));
453 
454  for (i = 1; i <= nlines; i++) {
455  G_percent(i, nlines, 1);
456  G_debug(3, "i = %d", i);
457  if (!Vect_line_alive(Map, i))
458  continue;
459 
460  ltype = Vect_read_line(Map, Points, Cats, i);
461  if (!(ltype & type))
462  continue;
463 
464  /* This would be confused by duplicate coordinates (angle cannot be
465  * calculated) -> prune line first */
466  Vect_line_prune(Points);
467 
468  /* If first and last point are identical it is close polygon, we don't
469  * need to register last point and we can calculate angle for first. If
470  * first and last point are not identical we have to mark for break both
471  */
472  last_point = Points->n_points - 1;
473  if (Points->x[0] == Points->x[last_point] &&
474  Points->y[0] == Points->y[last_point])
475  closed = 1;
476  else
477  closed = 0;
478 
479  for (j = 0; j < Points->n_points; j++) {
480  G_debug(3, "j = %d", j);
481 
482  if (j == last_point && closed)
483  continue; /* do not register last of close polygon */
484 
485  XPnt_search.x = Points->x[j];
486  XPnt_search.y = Points->y[j];
487 
488  /* Already in DB? */
489  XPnt_found = rbtree_find(RBTree, &XPnt_search);
490 
491  if (Points->n_points <= 2 ||
492  (!closed && (j == 0 || j == last_point))) {
493  cross = 1; /* mark for cross in any case */
494  }
495  else { /* calculate angles */
496  cross = 0;
497  if (j == 0 && closed) { /* closed polygon */
498  dx = Points->x[last_point] - Points->x[0];
499  dy = Points->y[last_point] - Points->y[0];
500  a1 = atan2(dy, dx);
501  dx = Points->x[1] - Points->x[0];
502  dy = Points->y[1] - Points->y[0];
503  a2 = atan2(dy, dx);
504  }
505  else {
506  dx = Points->x[j - 1] - Points->x[j];
507  dy = Points->y[j - 1] - Points->y[j];
508  a1 = atan2(dy, dx);
509  dx = Points->x[j + 1] - Points->x[j];
510  dy = Points->y[j + 1] - Points->y[j];
511  a2 = atan2(dy, dx);
512  }
513  }
514 
515  if (XPnt_found) { /* found */
516  if (XPnt_found->cross == 1)
517  continue; /* already marked */
518 
519  /* check angles */
520  if (cross) {
521  XPnt_found->cross = 1;
522  }
523  else {
524  G_debug(3, "a1 = %f xa1 = %f a2 = %f xa2 = %f", a1,
525  XPnt_found->a1, a2, XPnt_found->a2);
526  if ((a1 == XPnt_found->a1 && a2 == XPnt_found->a2) ||
527  (a1 == XPnt_found->a2 &&
528  a2 == XPnt_found->a1)) { /* identical */
529  }
530  else {
531  XPnt_found->cross = 1;
532  }
533  }
534  }
535  else {
536  if (j == 0 || j == (Points->n_points - 1) ||
537  Points->n_points < 3) {
538  XPnt_search.a1 = 0;
539  XPnt_search.a2 = 0;
540  XPnt_search.cross = 1;
541  }
542  else {
543  XPnt_search.a1 = a1;
544  XPnt_search.a2 = a2;
545  XPnt_search.cross = 0;
546  }
547 
548  /* Add to tree */
549  rbtree_insert(RBTree, &XPnt_search);
550  }
551  }
552  }
553 
554  nbreaks = 0;
555  G_debug(2, "Break polygons: unique vertices: %ld", (long int)RBTree->count);
556 
557  /* uncomment to check if search tree is healthy */
558  /* if (rbtree_debug(RBTree, RBTree->root) == 0)
559  G_warning("Break polygons: RBTree not ok"); */
560 
561  /* Second loop through lines (existing when loop is started, no need to
562  * process lines written again) and break at points marked for break */
563 
564  G_message(_("Breaking polygons (pass 2: break at selected points)..."));
565 
566  for (i = 1; i <= nlines; i++) {
567  int n_orig_points;
568 
569  G_percent(i, nlines, 1);
570  G_debug(3, "i = %d", i);
571  if (!Vect_line_alive(Map, i))
572  continue;
573 
574  ltype = Vect_read_line(Map, Points, Cats, i);
575  if (!(ltype & type))
576  continue;
577  if (!(ltype & GV_LINES))
578  continue; /* Nonsense to break points */
579 
580  /* Duplicates would result in zero length lines -> prune line first */
581  n_orig_points = Points->n_points;
582  Vect_line_prune(Points);
583 
584  broken = 0;
585  last = 0;
586  G_debug(3, "n_points = %d", Points->n_points);
587  for (j = 1; j < Points->n_points; j++) {
588  G_debug(3, "j = %d", j);
589 
590  if (Points->n_points <= 1 ||
591  (j == (Points->n_points - 1) && !broken))
592  break;
593  /* One point only or
594  * last point and line is not broken, do nothing */
595 
596  XPnt_search.x = Points->x[j];
597  XPnt_search.y = Points->y[j];
598 
599  XPnt_found = rbtree_find(RBTree, &XPnt_search);
600 
601  /* all points must be in the search tree, without duplicates */
602  if (XPnt_found == NULL)
603  G_fatal_error(_("Point not in search tree!"));
604 
605  /* break or write last segment of broken line */
606  if ((j == (Points->n_points - 1) && broken) || XPnt_found->cross) {
607  Vect_reset_line(BPoints);
608  for (k = last; k <= j; k++) {
609  Vect_append_point(BPoints, Points->x[k], Points->y[k],
610  Points->z[k]);
611  }
612 
613  /* Result may collapse to one point */
614  Vect_line_prune(BPoints);
615  if (BPoints->n_points > 1) {
616  ret = Vect_write_line(Map, ltype, BPoints, Cats);
617  G_debug(3,
618  "Line %d written j = %d n_points(orig,pruned) = %d "
619  "n_points(new) = %d",
620  ret, j, Points->n_points, BPoints->n_points);
621  }
622 
623  if (!broken)
624  Vect_delete_line(Map, i); /* not yet deleted */
625 
626  /* Write points on breaks */
627  if (Err) {
628  if (XPnt_found->cross && !XPnt_found->used) {
629  Vect_reset_line(BPoints);
630  Vect_append_point(BPoints, Points->x[j], Points->y[j],
631  0);
632  Vect_write_line(Err, GV_POINT, BPoints, ErrCats);
633  }
634  XPnt_found->used = 1;
635  }
636 
637  last = j;
638  broken = 1;
639  nbreaks++;
640  }
641  }
642  if (!broken &&
643  n_orig_points >
644  Points->n_points) { /* was pruned before -> rewrite */
645  if (Points->n_points > 1) {
646  Vect_rewrite_line(Map, i, ltype, Points, Cats);
647  G_debug(3, "Line %d pruned, npoints = %d", i, Points->n_points);
648  }
649  else {
650  Vect_delete_line(Map, i);
651  G_debug(3, "Line %d was deleted", i);
652  }
653  }
654  else {
655  G_debug(3, "Line %d was not changed", i);
656  }
657  }
658 
659  rbtree_destroy(RBTree);
660  Vect_destroy_line_struct(Points);
661  Vect_destroy_line_struct(BPoints);
663  Vect_destroy_cats_struct(ErrCats);
664  G_verbose_message(_("Breaks: %d"), nbreaks);
665 }
666 
667 /*!
668  \brief Break polygons in vector map
669 
670  Breaks lines specified by type in vector map. Points at
671  intersections may be optionally written to error map. Input vector
672  map must be opened on level 2 for update at least on GV_BUILD_BASE.
673 
674  Function is optimized for closed polygons rings (e.g. imported from
675  OGR) but with clean geometry - adjacent polygons mostly have
676  identical boundary. Function creates database of ALL points in the
677  vector map, and then is looking for those where polygons should be
678  broken. Lines may be broken only at points existing in input
679  vector map!
680 
681  \param Map input map where polygons will be broken
682  \param type type of line to be broken (GV_LINE or GV_BOUNDARY)
683  \param Err vector map where points at intersections will be written or NULL
684  */
685 void Vect_break_polygons(struct Map_info *Map, int type, struct Map_info *Err)
686 {
687  if (getenv("GRASS_VECTOR_LOWMEM"))
688  Vect_break_polygons_file(Map, type, Err);
689  else
690  Vect_break_polygons_mem(Map, type, Err);
691 }
void Vect_break_polygons_mem(struct Map_info *Map, int type, struct Map_info *Err)
void Vect_break_polygons_file(struct Map_info *Map, int type, struct Map_info *Err)
void Vect_break_polygons(struct Map_info *Map, int type, struct Map_info *Err)
Break polygons in vector map.
#define NULL
Definition: ccmath.h:32
void G_percent(long, long, int)
Print percent complete messages.
Definition: percent.c:61
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition: defs/gis.h:94
void void G_verbose_message(const char *,...) __attribute__((format(printf
char * G_tempfile(void)
Returns a temporary file name.
Definition: tempfile.c:62
void G_message(const char *,...) __attribute__((format(printf
int G_debug(int, const char *,...) __attribute__((format(printf
int rbtree_insert(struct RB_TREE *, void *)
Definition: rbtree.c:73
void * rbtree_find(struct RB_TREE *, const void *)
Definition: rbtree.c:243
void rbtree_destroy(struct RB_TREE *)
Definition: rbtree.c:520
struct RB_TREE * rbtree_create(rb_compare_fn *, size_t)
Definition: rbtree.c:49
void Vect_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
Definition: line.c:77
off_t Vect_rewrite_line(struct Map_info *, off_t, int, const struct line_pnts *, const struct line_cats *)
Rewrites existing feature (topological level required)
plus_t Vect_get_num_lines(struct Map_info *)
Fetch number of features (points, lines, boundaries, centroids) in vector map.
Definition: level_two.c:75
void Vect_destroy_cats_struct(struct line_cats *)
Frees all memory associated with line_cats structure, including the struct itself.
int Vect_read_line(struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
int Vect_line_alive(struct Map_info *, int)
Check if feature is alive or dead (topological level required)
int Vect_delete_line(struct Map_info *, off_t)
Delete existing feature (topological level required)
off_t Vect_write_line(struct Map_info *, int, const struct line_pnts *, const struct line_cats *)
Writes a new feature.
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition: line.c:45
void Vect_reset_line(struct line_pnts *)
Reset line.
Definition: line.c:129
int Vect_line_prune(struct line_pnts *)
Remove duplicate points, i.e. zero length segments.
Definition: line.c:279
struct line_cats * Vect_new_cats_struct(void)
Creates and initializes line_cats structure.
int Vect_append_point(struct line_pnts *, double, double, double)
Appends one point to the end of a line.
Definition: line.c:148
#define GV_POINT
Feature types used in memory on run time (may change)
Definition: dig_defines.h:183
#define GV_LINES
Definition: dig_defines.h:193
#define UNUSED
A macro for an attribute, if attached to a variable, indicating that the variable is not used.
Definition: gis.h:47
#define _(str)
Definition: glocale.h:10
double b
Definition: r_raster.c:39
double RectReal
Definition: rtree.h:26
Vector map info.
Definition: dig_structs.h:1243
Definition: rbtree.h:85
size_t count
Definition: rbtree.h:88
RectReal * boundary
Definition: rtree.h:55
Definition: rtree.h:123
int fd
Definition: rtree.h:125
Feature category info.
Definition: dig_structs.h:1677
Feature geometry info - coordinates.
Definition: dig_structs.h:1651
double * y
Array of Y coordinates.
Definition: dig_structs.h:1659
double * x
Array of X coordinates.
Definition: dig_structs.h:1655
int n_points
Number of points.
Definition: dig_structs.h:1667
double * z
Array of Z coordinates.
Definition: dig_structs.h:1663
int RTreeInsertRect(struct RTree_Rect *r, int tid, struct RTree *t)
Insert an item into a R*-Tree.
void RTreeDestroyTree(struct RTree *t)
Destroy an R*-Tree.
int RTreeSearch(struct RTree *t, struct RTree_Rect *r, SearchHitCallback *shcb, void *cbarg)
Search an R*-Tree.
struct RTree * RTreeCreateTree(int fd, off_t rootpos, int ndims)
Create new empty R*-Tree.
#define x