GRASS 8 Programmer's Manual 8.6.0dev(2026)-1d1e47ad9d
Loading...
Searching...
No Matches
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
54typedef 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
63typedef 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
71static int fpoint;
72
73/* Function called from RTreeSearch for point found */
74static 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 */
82static 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 */
107void 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
150 Points = Vect_new_line_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 if (lseek(xpntfd, (off_t)(fpoint - 1) * sizeof(XPNT2),
237 SEEK_SET) == -1) {
238 int err = errno;
240 _("File read/write operation failed: %s (%d)"),
241 strerror(err), err);
242 }
243 if (read(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
244 G_fatal_error(_("File reading error in %s() %d:%s"),
246 if (XPnt.cross == 1)
247 continue; /* already marked */
248
249 /* Check angles */
250 if (cross) {
251 XPnt.cross = 1;
252 /* write point */
253 if (lseek(xpntfd, (off_t)(fpoint - 1) * sizeof(XPNT2),
254 SEEK_SET) == -1) {
255 int err = errno;
257 _("File read/write operation failed: %s (%d)"),
258 strerror(err), err);
259 }
260 if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
261 G_fatal_error(_("File writing error in %s() %d:%s"),
263 }
264 else {
265 G_debug(3, "a1 = %f xa1 = %f a2 = %f xa2 = %f", a1, XPnt.a1,
266 a2, XPnt.a2);
267 if ((a1 == XPnt.a1 && a2 == XPnt.a2) ||
268 (a1 == XPnt.a2 && a2 == XPnt.a1)) { /* identical */
269 }
270 else {
271 XPnt.cross = 1;
272 /* write point */
273 if (lseek(xpntfd, (off_t)(fpoint - 1) * sizeof(XPNT2),
274 SEEK_SET) == -1) {
275 int err = errno;
277 _("File read/write operation failed: %s (%d)"),
278 strerror(err), err);
279 }
280 if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
281 G_fatal_error(_("File writing error in %s() %d:%s"),
283 }
284 }
285 }
286 else {
287 /* Add to tree and to structure */
288 RTreeInsertRect(&rect, npoints, RTree);
289 if (j == 0 || j == (Points->n_points - 1) ||
290 Points->n_points < 3) {
291 XPnt.a1 = 0;
292 XPnt.a2 = 0;
293 XPnt.cross = 1;
294 }
295 else {
296 XPnt.a1 = a1;
297 XPnt.a2 = a2;
298 XPnt.cross = 0;
299 }
300 /* write point */
301 if (lseek(xpntfd, (off_t)(npoints - 1) * sizeof(XPNT2),
302 SEEK_SET) == -1) {
303 int err = errno;
305 _("File read/write operation failed: %s (%d)"),
306 strerror(err), err);
307 }
308 if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
309 G_fatal_error(_("File writing error in %s() %d:%s"),
311
312 npoints++;
313 }
314 }
315 }
316
317 nbreaks = 0;
318
319 /* Second loop through lines (existing when loop is started, no need to
320 * process lines written again) and break at points marked for break */
321
322 G_message(_("Breaking polygons (pass 2: break at selected points)..."));
323
324 for (i = 1; i <= nlines; i++) {
325 int n_orig_points;
326
327 G_percent(i, nlines, 1);
328 G_debug(3, "i = %d", i);
329 if (!Vect_line_alive(Map, i))
330 continue;
331
332 ltype = Vect_read_line(Map, Points, Cats, i);
333 if (!(ltype & type))
334 continue;
335 if (!(ltype & GV_LINES))
336 continue; /* Nonsense to break points */
337
338 /* Duplicates would result in zero length lines -> prune line first */
339 n_orig_points = Points->n_points;
340 Vect_line_prune(Points);
341
342 broken = 0;
343 last = 0;
344 G_debug(3, "n_points = %d", Points->n_points);
345 for (j = 1; j < Points->n_points; j++) {
346 G_debug(3, "j = %d", j);
347
348 /* Box */
349 rect.boundary[0] = Points->x[j];
350 rect.boundary[3] = Points->x[j];
351 rect.boundary[1] = Points->y[j];
352 rect.boundary[4] = Points->y[j];
353 rect.boundary[2] = 0;
354 rect.boundary[5] = 0;
355
356 if (Points->n_points <= 1 ||
357 (j == (Points->n_points - 1) && !broken))
358 break;
359 /* One point only or
360 * last point and line is not broken, do nothing */
361
362 RTreeSearch(RTree, &rect, srch, NULL);
363 G_debug(3, "fpoint = %d", fpoint);
364
365 /* read point */
366 if (lseek(xpntfd, (off_t)(fpoint - 1) * sizeof(XPNT2), SEEK_SET) ==
367 -1) {
368 int err = errno;
369 G_fatal_error(_("File read/write operation failed: %s (%d)"),
370 strerror(err), err);
371 }
372 if (read(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
373 G_fatal_error(_("File reading error in %s() %d:%s"), __func__,
375
376 /* break or write last segment of broken line */
377 if ((j == (Points->n_points - 1) && broken) || XPnt.cross) {
379 for (k = last; k <= j; k++) {
380 Vect_append_point(BPoints, Points->x[k], Points->y[k],
381 Points->z[k]);
382 }
383
384 /* Result may collapse to one point */
386 if (BPoints->n_points > 1) {
388 G_debug(3,
389 "Line %d written j = %d n_points(orig,pruned) = %d "
390 "n_points(new) = %d",
391 ret, j, Points->n_points, BPoints->n_points);
392 }
393
394 if (!broken)
395 Vect_delete_line(Map, i); /* not yet deleted */
396
397 /* Write points on breaks */
398 if (Err) {
399 if (XPnt.cross && !XPnt.used) {
401 Vect_append_point(BPoints, Points->x[j], Points->y[j],
402 0);
404 }
405 if (!XPnt.used) {
406 XPnt.used = 1;
407 /* write point */
408 if (lseek(xpntfd, (off_t)(fpoint - 1) * sizeof(XPNT2),
409 SEEK_SET) == -1) {
410 int err = errno;
412 _("File read/write operation failed: %s (%d)"),
413 strerror(err), err);
414 }
415 if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
416 G_fatal_error(_("File writing error in %s() %d:%s"),
418 }
419 }
420
421 last = j;
422 broken = 1;
423 nbreaks++;
424 }
425 }
426 if (!broken &&
428 Points->n_points) { /* was pruned before -> rewrite */
429 if (Points->n_points > 1) {
430 Vect_rewrite_line(Map, i, ltype, Points, Cats);
431 G_debug(3, "Line %d pruned, npoints = %d", i, Points->n_points);
432 }
433 else {
435 G_debug(3, "Line %d was deleted", i);
436 }
437 }
438 else {
439 G_debug(3, "Line %d was not changed", i);
440 }
441 }
442
443 close(RTree->fd);
445 close(xpntfd);
450 G_verbose_message(_("Breaks: %d"), nbreaks);
451}
452
453/* break polygons using a memory-based search index */
454void Vect_break_polygons_mem(struct Map_info *Map, int type,
455 struct Map_info *Err)
456{
457 struct line_pnts *BPoints, *Points;
458 struct line_cats *Cats, *ErrCats;
459 int i, j, k, ret, ltype, broken, last, nlines;
460 int nbreaks;
461 struct RB_TREE *RBTree;
462 XPNT *XPnt_found, XPnt_search;
463 double dx, dy, a1 = 0, a2 = 0;
464 int closed, last_point, cross;
465
466 G_debug(1, "Memory-based version of Vect_break_polygons()");
467
468 RBTree = rbtree_create(compare_xpnts, sizeof(XPNT));
469
471 Points = Vect_new_line_struct();
474
475 nlines = Vect_get_num_lines(Map);
476
477 G_debug(3, "nlines = %d", nlines);
478 /* Go through all lines in vector, and add each point to structure of
479 * points, if such point already exists check angles of segments and if
480 * differ mark for break */
481
482 XPnt_search.used = 0;
483
484 G_message(_("Breaking polygons (pass 1: select break points)..."));
485
486 for (i = 1; i <= nlines; i++) {
487 G_percent(i, nlines, 1);
488 G_debug(3, "i = %d", i);
489 if (!Vect_line_alive(Map, i))
490 continue;
491
492 ltype = Vect_read_line(Map, Points, Cats, i);
493 if (!(ltype & type))
494 continue;
495
496 /* This would be confused by duplicate coordinates (angle cannot be
497 * calculated) -> prune line first */
498 Vect_line_prune(Points);
499
500 /* If first and last point are identical it is close polygon, we don't
501 * need to register last point and we can calculate angle for first. If
502 * first and last point are not identical we have to mark for break both
503 */
504 last_point = Points->n_points - 1;
505 if (Points->x[0] == Points->x[last_point] &&
506 Points->y[0] == Points->y[last_point])
507 closed = 1;
508 else
509 closed = 0;
510
511 for (j = 0; j < Points->n_points; j++) {
512 G_debug(3, "j = %d", j);
513
514 if (j == last_point && closed)
515 continue; /* do not register last of close polygon */
516
517 XPnt_search.x = Points->x[j];
518 XPnt_search.y = Points->y[j];
519
520 /* Already in DB? */
522
523 if (Points->n_points <= 2 ||
524 (!closed && (j == 0 || j == last_point))) {
525 cross = 1; /* mark for cross in any case */
526 }
527 else { /* calculate angles */
528 cross = 0;
529 if (j == 0 && closed) { /* closed polygon */
530 dx = Points->x[last_point] - Points->x[0];
531 dy = Points->y[last_point] - Points->y[0];
532 a1 = atan2(dy, dx);
533 dx = Points->x[1] - Points->x[0];
534 dy = Points->y[1] - Points->y[0];
535 a2 = atan2(dy, dx);
536 }
537 else {
538 dx = Points->x[j - 1] - Points->x[j];
539 dy = Points->y[j - 1] - Points->y[j];
540 a1 = atan2(dy, dx);
541 dx = Points->x[j + 1] - Points->x[j];
542 dy = Points->y[j + 1] - Points->y[j];
543 a2 = atan2(dy, dx);
544 }
545 }
546
547 if (XPnt_found) { /* found */
548 if (XPnt_found->cross == 1)
549 continue; /* already marked */
550
551 /* check angles */
552 if (cross) {
553 XPnt_found->cross = 1;
554 }
555 else {
556 G_debug(3, "a1 = %f xa1 = %f a2 = %f xa2 = %f", a1,
557 XPnt_found->a1, a2, XPnt_found->a2);
558 if ((a1 == XPnt_found->a1 && a2 == XPnt_found->a2) ||
559 (a1 == XPnt_found->a2 &&
560 a2 == XPnt_found->a1)) { /* identical */
561 }
562 else {
563 XPnt_found->cross = 1;
564 }
565 }
566 }
567 else {
568 if (j == 0 || j == (Points->n_points - 1) ||
569 Points->n_points < 3) {
570 XPnt_search.a1 = 0;
571 XPnt_search.a2 = 0;
572 XPnt_search.cross = 1;
573 }
574 else {
575 XPnt_search.a1 = a1;
576 XPnt_search.a2 = a2;
577 XPnt_search.cross = 0;
578 }
579
580 /* Add to tree */
582 }
583 }
584 }
585
586 nbreaks = 0;
587 G_debug(2, "Break polygons: unique vertices: %ld", (long int)RBTree->count);
588
589 /* uncomment to check if search tree is healthy */
590 /* if (rbtree_debug(RBTree, RBTree->root) == 0)
591 G_warning("Break polygons: RBTree not ok"); */
592
593 /* Second loop through lines (existing when loop is started, no need to
594 * process lines written again) and break at points marked for break */
595
596 G_message(_("Breaking polygons (pass 2: break at selected points)..."));
597
598 for (i = 1; i <= nlines; i++) {
599 int n_orig_points;
600
601 G_percent(i, nlines, 1);
602 G_debug(3, "i = %d", i);
603 if (!Vect_line_alive(Map, i))
604 continue;
605
606 ltype = Vect_read_line(Map, Points, Cats, i);
607 if (!(ltype & type))
608 continue;
609 if (!(ltype & GV_LINES))
610 continue; /* Nonsense to break points */
611
612 /* Duplicates would result in zero length lines -> prune line first */
613 n_orig_points = Points->n_points;
614 Vect_line_prune(Points);
615
616 broken = 0;
617 last = 0;
618 G_debug(3, "n_points = %d", Points->n_points);
619 for (j = 1; j < Points->n_points; j++) {
620 G_debug(3, "j = %d", j);
621
622 if (Points->n_points <= 1 ||
623 (j == (Points->n_points - 1) && !broken))
624 break;
625 /* One point only or
626 * last point and line is not broken, do nothing */
627
628 XPnt_search.x = Points->x[j];
629 XPnt_search.y = Points->y[j];
630
632
633 /* all points must be in the search tree, without duplicates */
634 if (XPnt_found == NULL)
635 G_fatal_error(_("Point not in search tree!"));
636
637 /* break or write last segment of broken line */
638 if ((j == (Points->n_points - 1) && broken) || XPnt_found->cross) {
640 for (k = last; k <= j; k++) {
641 Vect_append_point(BPoints, Points->x[k], Points->y[k],
642 Points->z[k]);
643 }
644
645 /* Result may collapse to one point */
647 if (BPoints->n_points > 1) {
649 G_debug(3,
650 "Line %d written j = %d n_points(orig,pruned) = %d "
651 "n_points(new) = %d",
652 ret, j, Points->n_points, BPoints->n_points);
653 }
654
655 if (!broken)
656 Vect_delete_line(Map, i); /* not yet deleted */
657
658 /* Write points on breaks */
659 if (Err) {
660 if (XPnt_found->cross && !XPnt_found->used) {
662 Vect_append_point(BPoints, Points->x[j], Points->y[j],
663 0);
665 }
666 XPnt_found->used = 1;
667 }
668
669 last = j;
670 broken = 1;
671 nbreaks++;
672 }
673 }
674 if (!broken &&
676 Points->n_points) { /* was pruned before -> rewrite */
677 if (Points->n_points > 1) {
678 Vect_rewrite_line(Map, i, ltype, Points, Cats);
679 G_debug(3, "Line %d pruned, npoints = %d", i, Points->n_points);
680 }
681 else {
683 G_debug(3, "Line %d was deleted", i);
684 }
685 }
686 else {
687 G_debug(3, "Line %d was not changed", i);
688 }
689 }
690
696 G_verbose_message(_("Breaks: %d"), nbreaks);
697}
698
699/*!
700 \brief Break polygons in vector map
701
702 Breaks lines specified by type in vector map. Points at
703 intersections may be optionally written to error map. Input vector
704 map must be opened on level 2 for update at least on GV_BUILD_BASE.
705
706 Function is optimized for closed polygons rings (e.g. imported from
707 OGR) but with clean geometry - adjacent polygons mostly have
708 identical boundary. Function creates database of ALL points in the
709 vector map, and then is looking for those where polygons should be
710 broken. Lines may be broken only at points existing in input
711 vector map!
712
713 \param Map input map where polygons will be broken
714 \param type type of line to be broken (GV_LINE or GV_BOUNDARY)
715 \param Err vector map where points at intersections will be written or NULL
716 */
717void Vect_break_polygons(struct Map_info *Map, int type, struct Map_info *Err)
718{
719 if (getenv("GRASS_VECTOR_LOWMEM"))
721 else
723}
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:147
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:139
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
struct RB_TREE * rbtree_create(rb_compare_fn *, size_t)
Definition rbtree.c:49
void * rbtree_find(struct RB_TREE *, const void *)
Definition rbtree.c:243
void rbtree_destroy(struct RB_TREE *)
Definition rbtree.c:520
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)
struct line_cats * Vect_new_cats_struct(void)
Creates and initializes line_cats structure.
off_t Vect_write_line(struct Map_info *, int, const struct line_pnts *, const struct line_cats *)
Writes a new feature.
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_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition line.c:45
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)
#define GV_LINES
Header file for msvc/fcntl.c.
#define open
Definition fcntl.h:33
#define UNUSED
A macro for an attribute, if attached to a variable, indicating that the variable is not used.
Definition gis.h:46
#define _(str)
Definition glocale.h:10
double b
Definition r_raster.c:39
Vector map info.
RectReal * boundary
Definition rtree.h:55
Definition rtree.h:123
int fd
Definition rtree.h:125
Feature category info.
Feature geometry info - coordinates.
double * y
Array of Y coordinates.
double * x
Array of X coordinates.
int n_points
Number of points.
double * z
Array of Z coordinates.
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)
#define read
Definition unistd.h:5
#define close
Definition unistd.h:8
#define write
Definition unistd.h:6
struct RTree * RTreeCreateTree(int fd, off_t rootpos, int ndims)
Create new empty R*-Tree.
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.
#define x