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