GRASS 8 Programmer's Manual 8.6.0dev(2026)-5a31d549cc
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 G_UNUSED,
75 void *arg G_UNUSED)
76{
77 fpoint = id;
78
79 return 0; /* stop searching */
80}
81
82/* function used by binary tree to compare items */
83static int compare_xpnts(const void *Xpnta, const void *Xpntb)
84{
85 XPNT *a, *b;
86
87 a = (XPNT *)Xpnta;
88 b = (XPNT *)Xpntb;
89
90 if (a->x > b->x)
91 return 1;
92 else if (a->x < b->x)
93 return -1;
94 else {
95 if (a->y > b->y)
96 return 1;
97 else if (a->y < b->y)
98 return -1;
99 else
100 return 0;
101 }
102
103 G_warning(_("Break polygons: Bug in binary tree!"));
104 return 1;
105}
106
107/* break polygons using a file-based search index */
108void Vect_break_polygons_file(struct Map_info *Map, int type,
109 struct Map_info *Err)
110{
111 struct line_pnts *BPoints, *Points;
112 struct line_cats *Cats, *ErrCats;
113 int i, j, k, ret, ltype, broken, last, nlines;
114 int nbreaks;
115 struct RTree *RTree;
116 int npoints;
117 XPNT2 XPnt;
118 double dx, dy, a1 = 0, a2 = 0;
119 int closed, last_point;
120 char cross;
121 int fd, xpntfd;
122 char *filename;
123 static struct RTree_Rect rect;
124 static int rect_init = 0;
125
126 if (!rect_init) {
127 rect.boundary = G_malloc(6 * sizeof(RectReal));
128 rect_init = 6;
129 }
130
131 G_debug(1, "File-based version of Vect_break_polygons()");
132
133 filename = G_tempfile();
134 fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
135 RTree = RTreeCreateTree(fd, 0, 2);
136 (void)remove(filename);
137 G_free(filename);
138
139 filename = G_tempfile();
140 xpntfd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
141 if (xpntfd < 0) {
142 close(RTree->fd);
143 G_free(filename);
144 G_fatal_error(_("Failed to create xpnt temporary file: %s"),
145 strerror(errno));
146 }
147 (void)remove(filename);
148 G_free(filename);
149
151 Points = Vect_new_line_struct();
154
155 nlines = Vect_get_num_lines(Map);
156
157 G_debug(3, "nlines = %d", nlines);
158 /* Go through all lines in vector, and add each point to structure of
159 * points, if such point already exists check angles of segments and if
160 * differ mark for break */
161
162 npoints = 1; /* index starts from 1 ! */
163 XPnt.used = 0;
164
165 G_message(_("Breaking polygons (pass 1: select break points)..."));
166
167 for (i = 1; i <= nlines; i++) {
168 G_percent(i, nlines, 1);
169 G_debug(3, "i = %d", i);
170 if (!Vect_line_alive(Map, i))
171 continue;
172
173 ltype = Vect_read_line(Map, Points, Cats, i);
174 if (!(ltype & type))
175 continue;
176
177 /* This would be confused by duplicate coordinates (angle cannot be
178 * calculated) -> prune line first */
179 Vect_line_prune(Points);
180
181 /* If first and last point are identical it is close polygon, we don't
182 * need to register last point and we can calculate angle for first. If
183 * first and last point are not identical we have to mark for break both
184 */
185 last_point = Points->n_points - 1;
186 if (Points->x[0] == Points->x[last_point] &&
187 Points->y[0] == Points->y[last_point])
188 closed = 1;
189 else
190 closed = 0;
191
192 for (j = 0; j < Points->n_points; j++) {
193 G_debug(3, "j = %d", j);
194
195 if (j == last_point && closed)
196 continue; /* do not register last of close polygon */
197
198 /* Box */
199 rect.boundary[0] = Points->x[j];
200 rect.boundary[3] = Points->x[j];
201 rect.boundary[1] = Points->y[j];
202 rect.boundary[4] = Points->y[j];
203 rect.boundary[2] = 0;
204 rect.boundary[5] = 0;
205
206 /* Already in DB? */
207 fpoint = -1;
208 RTreeSearch(RTree, &rect, srch, NULL);
209 G_debug(3, "fpoint = %d", fpoint);
210
211 if (Points->n_points <= 2 ||
212 (!closed && (j == 0 || j == last_point))) {
213 cross = 1; /* mark for cross in any case */
214 }
215 else { /* calculate angles */
216 cross = 0;
217 if (j == 0 && closed) { /* closed polygon */
218 dx = Points->x[last_point] - Points->x[0];
219 dy = Points->y[last_point] - Points->y[0];
220 a1 = atan2(dy, dx);
221 dx = Points->x[1] - Points->x[0];
222 dy = Points->y[1] - Points->y[0];
223 a2 = atan2(dy, dx);
224 }
225 else {
226 dx = Points->x[j - 1] - Points->x[j];
227 dy = Points->y[j - 1] - Points->y[j];
228 a1 = atan2(dy, dx);
229 dx = Points->x[j + 1] - Points->x[j];
230 dy = Points->y[j + 1] - Points->y[j];
231 a2 = atan2(dy, dx);
232 }
233 }
234
235 if (fpoint > 0) { /* Found */
236 /* read point */
237 if (lseek(xpntfd, (off_t)(fpoint - 1) * sizeof(XPNT2),
238 SEEK_SET) == -1) {
239 int err = errno;
241 _("File read/write operation failed: %s (%d)"),
242 strerror(err), err);
243 }
244 if (read(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
245 G_fatal_error(_("File reading error in %s() %d:%s"),
247 if (XPnt.cross == 1)
248 continue; /* already marked */
249
250 /* Check angles */
251 if (cross) {
252 XPnt.cross = 1;
253 /* write point */
254 if (lseek(xpntfd, (off_t)(fpoint - 1) * sizeof(XPNT2),
255 SEEK_SET) == -1) {
256 int err = errno;
258 _("File read/write operation failed: %s (%d)"),
259 strerror(err), err);
260 }
261 if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
262 G_fatal_error(_("File writing error in %s() %d:%s"),
264 }
265 else {
266 G_debug(3, "a1 = %f xa1 = %f a2 = %f xa2 = %f", a1, XPnt.a1,
267 a2, XPnt.a2);
268 if ((a1 == XPnt.a1 && a2 == XPnt.a2) ||
269 (a1 == XPnt.a2 && a2 == XPnt.a1)) { /* identical */
270 }
271 else {
272 XPnt.cross = 1;
273 /* write point */
274 if (lseek(xpntfd, (off_t)(fpoint - 1) * sizeof(XPNT2),
275 SEEK_SET) == -1) {
276 int err = errno;
278 _("File read/write operation failed: %s (%d)"),
279 strerror(err), err);
280 }
281 if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
282 G_fatal_error(_("File writing error in %s() %d:%s"),
284 }
285 }
286 }
287 else {
288 /* Add to tree and to structure */
289 RTreeInsertRect(&rect, npoints, RTree);
290 if (j == 0 || j == (Points->n_points - 1) ||
291 Points->n_points < 3) {
292 XPnt.a1 = 0;
293 XPnt.a2 = 0;
294 XPnt.cross = 1;
295 }
296 else {
297 XPnt.a1 = a1;
298 XPnt.a2 = a2;
299 XPnt.cross = 0;
300 }
301 /* write point */
302 if (lseek(xpntfd, (off_t)(npoints - 1) * sizeof(XPNT2),
303 SEEK_SET) == -1) {
304 int err = errno;
306 _("File read/write operation failed: %s (%d)"),
307 strerror(err), err);
308 }
309 if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
310 G_fatal_error(_("File writing error in %s() %d:%s"),
312
313 npoints++;
314 }
315 }
316 }
317
318 nbreaks = 0;
319
320 /* Second loop through lines (existing when loop is started, no need to
321 * process lines written again) and break at points marked for break */
322
323 G_message(_("Breaking polygons (pass 2: break at selected points)..."));
324
325 for (i = 1; i <= nlines; i++) {
326 int n_orig_points;
327
328 G_percent(i, nlines, 1);
329 G_debug(3, "i = %d", i);
330 if (!Vect_line_alive(Map, i))
331 continue;
332
333 ltype = Vect_read_line(Map, Points, Cats, i);
334 if (!(ltype & type))
335 continue;
336 if (!(ltype & GV_LINES))
337 continue; /* Nonsense to break points */
338
339 /* Duplicates would result in zero length lines -> prune line first */
340 n_orig_points = Points->n_points;
341 Vect_line_prune(Points);
342
343 broken = 0;
344 last = 0;
345 G_debug(3, "n_points = %d", Points->n_points);
346 for (j = 1; j < Points->n_points; j++) {
347 G_debug(3, "j = %d", j);
348
349 /* Box */
350 rect.boundary[0] = Points->x[j];
351 rect.boundary[3] = Points->x[j];
352 rect.boundary[1] = Points->y[j];
353 rect.boundary[4] = Points->y[j];
354 rect.boundary[2] = 0;
355 rect.boundary[5] = 0;
356
357 if (Points->n_points <= 1 ||
358 (j == (Points->n_points - 1) && !broken))
359 break;
360 /* One point only or
361 * last point and line is not broken, do nothing */
362
363 RTreeSearch(RTree, &rect, srch, NULL);
364 G_debug(3, "fpoint = %d", fpoint);
365
366 /* read point */
367 if (lseek(xpntfd, (off_t)(fpoint - 1) * sizeof(XPNT2), SEEK_SET) ==
368 -1) {
369 int err = errno;
370 G_fatal_error(_("File read/write operation failed: %s (%d)"),
371 strerror(err), err);
372 }
373 if (read(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
374 G_fatal_error(_("File reading error in %s() %d:%s"), __func__,
376
377 /* break or write last segment of broken line */
378 if ((j == (Points->n_points - 1) && broken) || XPnt.cross) {
380 for (k = last; k <= j; k++) {
381 Vect_append_point(BPoints, Points->x[k], Points->y[k],
382 Points->z[k]);
383 }
384
385 /* Result may collapse to one point */
387 if (BPoints->n_points > 1) {
389 G_debug(3,
390 "Line %d written j = %d n_points(orig,pruned) = %d "
391 "n_points(new) = %d",
392 ret, j, Points->n_points, BPoints->n_points);
393 }
394
395 if (!broken)
396 Vect_delete_line(Map, i); /* not yet deleted */
397
398 /* Write points on breaks */
399 if (Err) {
400 if (XPnt.cross && !XPnt.used) {
402 Vect_append_point(BPoints, Points->x[j], Points->y[j],
403 0);
405 }
406 if (!XPnt.used) {
407 XPnt.used = 1;
408 /* write point */
409 if (lseek(xpntfd, (off_t)(fpoint - 1) * sizeof(XPNT2),
410 SEEK_SET) == -1) {
411 int err = errno;
413 _("File read/write operation failed: %s (%d)"),
414 strerror(err), err);
415 }
416 if (write(xpntfd, &XPnt, sizeof(XPNT2)) < 0)
417 G_fatal_error(_("File writing error in %s() %d:%s"),
419 }
420 }
421
422 last = j;
423 broken = 1;
424 nbreaks++;
425 }
426 }
427 if (!broken &&
429 Points->n_points) { /* was pruned before -> rewrite */
430 if (Points->n_points > 1) {
431 Vect_rewrite_line(Map, i, ltype, Points, Cats);
432 G_debug(3, "Line %d pruned, npoints = %d", i, Points->n_points);
433 }
434 else {
436 G_debug(3, "Line %d was deleted", i);
437 }
438 }
439 else {
440 G_debug(3, "Line %d was not changed", i);
441 }
442 }
443
444 close(RTree->fd);
446 close(xpntfd);
451 G_verbose_message(_("Breaks: %d"), nbreaks);
452}
453
454/* break polygons using a memory-based search index */
455void Vect_break_polygons_mem(struct Map_info *Map, int type,
456 struct Map_info *Err)
457{
458 struct line_pnts *BPoints, *Points;
459 struct line_cats *Cats, *ErrCats;
460 int i, j, k, ret, ltype, broken, last, nlines;
461 int nbreaks;
462 struct RB_TREE *RBTree;
463 XPNT *XPnt_found, XPnt_search;
464 double dx, dy, a1 = 0, a2 = 0;
465 int closed, last_point, cross;
466
467 G_debug(1, "Memory-based version of Vect_break_polygons()");
468
469 RBTree = rbtree_create(compare_xpnts, sizeof(XPNT));
470
472 Points = Vect_new_line_struct();
475
476 nlines = Vect_get_num_lines(Map);
477
478 G_debug(3, "nlines = %d", nlines);
479 /* Go through all lines in vector, and add each point to structure of
480 * points, if such point already exists check angles of segments and if
481 * differ mark for break */
482
483 XPnt_search.used = 0;
484
485 G_message(_("Breaking polygons (pass 1: select break points)..."));
486
487 for (i = 1; i <= nlines; i++) {
488 G_percent(i, nlines, 1);
489 G_debug(3, "i = %d", i);
490 if (!Vect_line_alive(Map, i))
491 continue;
492
493 ltype = Vect_read_line(Map, Points, Cats, i);
494 if (!(ltype & type))
495 continue;
496
497 /* This would be confused by duplicate coordinates (angle cannot be
498 * calculated) -> prune line first */
499 Vect_line_prune(Points);
500
501 /* If first and last point are identical it is close polygon, we don't
502 * need to register last point and we can calculate angle for first. If
503 * first and last point are not identical we have to mark for break both
504 */
505 last_point = Points->n_points - 1;
506 if (Points->x[0] == Points->x[last_point] &&
507 Points->y[0] == Points->y[last_point])
508 closed = 1;
509 else
510 closed = 0;
511
512 for (j = 0; j < Points->n_points; j++) {
513 G_debug(3, "j = %d", j);
514
515 if (j == last_point && closed)
516 continue; /* do not register last of close polygon */
517
518 XPnt_search.x = Points->x[j];
519 XPnt_search.y = Points->y[j];
520
521 /* Already in DB? */
523
524 if (Points->n_points <= 2 ||
525 (!closed && (j == 0 || j == last_point))) {
526 cross = 1; /* mark for cross in any case */
527 }
528 else { /* calculate angles */
529 cross = 0;
530 if (j == 0 && closed) { /* closed polygon */
531 dx = Points->x[last_point] - Points->x[0];
532 dy = Points->y[last_point] - Points->y[0];
533 a1 = atan2(dy, dx);
534 dx = Points->x[1] - Points->x[0];
535 dy = Points->y[1] - Points->y[0];
536 a2 = atan2(dy, dx);
537 }
538 else {
539 dx = Points->x[j - 1] - Points->x[j];
540 dy = Points->y[j - 1] - Points->y[j];
541 a1 = atan2(dy, dx);
542 dx = Points->x[j + 1] - Points->x[j];
543 dy = Points->y[j + 1] - Points->y[j];
544 a2 = atan2(dy, dx);
545 }
546 }
547
548 if (XPnt_found) { /* found */
549 if (XPnt_found->cross == 1)
550 continue; /* already marked */
551
552 /* check angles */
553 if (cross) {
554 XPnt_found->cross = 1;
555 }
556 else {
557 G_debug(3, "a1 = %f xa1 = %f a2 = %f xa2 = %f", a1,
558 XPnt_found->a1, a2, XPnt_found->a2);
559 if ((a1 == XPnt_found->a1 && a2 == XPnt_found->a2) ||
560 (a1 == XPnt_found->a2 &&
561 a2 == XPnt_found->a1)) { /* identical */
562 }
563 else {
564 XPnt_found->cross = 1;
565 }
566 }
567 }
568 else {
569 if (j == 0 || j == (Points->n_points - 1) ||
570 Points->n_points < 3) {
571 XPnt_search.a1 = 0;
572 XPnt_search.a2 = 0;
573 XPnt_search.cross = 1;
574 }
575 else {
576 XPnt_search.a1 = a1;
577 XPnt_search.a2 = a2;
578 XPnt_search.cross = 0;
579 }
580
581 /* Add to tree */
583 }
584 }
585 }
586
587 nbreaks = 0;
588 G_debug(2, "Break polygons: unique vertices: %ld", (long int)RBTree->count);
589
590 /* uncomment to check if search tree is healthy */
591 /* if (rbtree_debug(RBTree, RBTree->root) == 0)
592 G_warning("Break polygons: RBTree not ok"); */
593
594 /* Second loop through lines (existing when loop is started, no need to
595 * process lines written again) and break at points marked for break */
596
597 G_message(_("Breaking polygons (pass 2: break at selected points)..."));
598
599 for (i = 1; i <= nlines; i++) {
600 int n_orig_points;
601
602 G_percent(i, nlines, 1);
603 G_debug(3, "i = %d", i);
604 if (!Vect_line_alive(Map, i))
605 continue;
606
607 ltype = Vect_read_line(Map, Points, Cats, i);
608 if (!(ltype & type))
609 continue;
610 if (!(ltype & GV_LINES))
611 continue; /* Nonsense to break points */
612
613 /* Duplicates would result in zero length lines -> prune line first */
614 n_orig_points = Points->n_points;
615 Vect_line_prune(Points);
616
617 broken = 0;
618 last = 0;
619 G_debug(3, "n_points = %d", Points->n_points);
620 for (j = 1; j < Points->n_points; j++) {
621 G_debug(3, "j = %d", j);
622
623 if (Points->n_points <= 1 ||
624 (j == (Points->n_points - 1) && !broken))
625 break;
626 /* One point only or
627 * last point and line is not broken, do nothing */
628
629 XPnt_search.x = Points->x[j];
630 XPnt_search.y = Points->y[j];
631
633
634 /* all points must be in the search tree, without duplicates */
635 if (XPnt_found == NULL)
636 G_fatal_error(_("Point not in search tree!"));
637
638 /* break or write last segment of broken line */
639 if ((j == (Points->n_points - 1) && broken) || XPnt_found->cross) {
641 for (k = last; k <= j; k++) {
642 Vect_append_point(BPoints, Points->x[k], Points->y[k],
643 Points->z[k]);
644 }
645
646 /* Result may collapse to one point */
648 if (BPoints->n_points > 1) {
650 G_debug(3,
651 "Line %d written j = %d n_points(orig,pruned) = %d "
652 "n_points(new) = %d",
653 ret, j, Points->n_points, BPoints->n_points);
654 }
655
656 if (!broken)
657 Vect_delete_line(Map, i); /* not yet deleted */
658
659 /* Write points on breaks */
660 if (Err) {
661 if (XPnt_found->cross && !XPnt_found->used) {
663 Vect_append_point(BPoints, Points->x[j], Points->y[j],
664 0);
666 }
667 XPnt_found->used = 1;
668 }
669
670 last = j;
671 broken = 1;
672 nbreaks++;
673 }
674 }
675 if (!broken &&
677 Points->n_points) { /* was pruned before -> rewrite */
678 if (Points->n_points > 1) {
679 Vect_rewrite_line(Map, i, ltype, Points, Cats);
680 G_debug(3, "Line %d pruned, npoints = %d", i, Points->n_points);
681 }
682 else {
684 G_debug(3, "Line %d was deleted", i);
685 }
686 }
687 else {
688 G_debug(3, "Line %d was not changed", i);
689 }
690 }
691
697 G_verbose_message(_("Breaks: %d"), nbreaks);
698}
699
700/*!
701 \brief Break polygons in vector map
702
703 Breaks lines specified by type in vector map. Points at
704 intersections may be optionally written to error map. Input vector
705 map must be opened on level 2 for update at least on GV_BUILD_BASE.
706
707 Function is optimized for closed polygons rings (e.g. imported from
708 OGR) but with clean geometry - adjacent polygons mostly have
709 identical boundary. Function creates database of ALL points in the
710 vector map, and then is looking for those where polygons should be
711 broken. Lines may be broken only at points existing in input
712 vector map!
713
714 \param Map input map where polygons will be broken
715 \param type type of line to be broken (GV_LINE or GV_BOUNDARY)
716 \param Err vector map where points at intersections will be written or NULL
717 */
718void Vect_break_polygons(struct Map_info *Map, int type, struct Map_info *Err)
719{
720 if (getenv("GRASS_VECTOR_LOWMEM"))
722 else
724}
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 G_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