GRASS 8 Programmer's Manual 8.6.0dev(2026)-4bb960b182
Loading...
Searching...
No Matches
geos.c
Go to the documentation of this file.
1/*!
2 \file lib/vector/Vlib/geos.c
3
4 \brief Vector library - GEOS support
5
6 Higher level functions for reading/writing/manipulating vectors.
7
8 SPDX-FileCopyrightText: 2009 GRASS Development Team
9 SPDX-License-Identifier: GPL-2.0-or-later
10
11 \author Martin Landa <landa.martin gmail.com>
12 */
13
14#include <stdlib.h>
15#include <grass/vector.h>
16#include <grass/glocale.h>
17
18#ifdef HAVE_GEOS
19
20static GEOSGeometry *Vect__read_line_geos(struct Map_info *, long, int *);
21static GEOSCoordSequence *V1_read_line_geos(struct Map_info *, long, int *);
22static GEOSCoordSequence *V2_read_line_geos(struct Map_info *, int);
23static GEOSCoordSequence *read_polygon_points(struct Map_info *, int, int *);
24
25/*!
26 \brief Read vector feature and stores it as GEOSGeometry instance
27
28 Supported feature types:
29 - GV_POINT -> POINT
30 - GV_LINE -> LINESTRING
31 - GV_BOUNDARY -> LINESTRING / LINEARRING
32
33 You should free allocated memory by GEOSGeom_destroy().
34
35 \param Map pointer to Map_info structure
36 \param line feature id
37 \param[out] type feature type or NULL
38
39 \return pointer to GEOSGeometry instance
40 \return empty GEOSGeometry for unsupported feature type
41 \return NULL on error
42 */
43GEOSGeometry *Vect_read_line_geos(struct Map_info *Map, int line, int *type)
44{
45 struct P_line *Line;
46
47 G_debug(3, "Vect_read_line_geos(): line = %d", line);
48
49 if (!VECT_OPEN(Map))
50 G_fatal_error("Vect_read_line_geos(): %s",
51 _("vector map is not opened"));
52
53 if (line < 1 || line > Map->plus.n_lines)
55 _("Vect_read_line_geos(): feature id %d is not reasonable "
56 "(max features in vector map <%s>: %d)"),
57 line, Vect_get_full_name(Map), Map->plus.n_lines);
58
59 if (Map->format != GV_FORMAT_NATIVE)
60 G_fatal_error("Vect_read_line_geos(): %s",
61 _("only native format supported"));
62
63 Line = Map->plus.Line[line];
64 if (Line == NULL)
65 G_fatal_error("Vect_read_line_geos(): %s %d",
66 _("Attempt to read dead line"), line);
67
68 return Vect__read_line_geos(Map, Line->offset, type);
69}
70
71/*!
72 \brief Read vector area and stores it as GEOSGeometry instance (polygon)
73
74 You should free allocated memory by GEOSGeom_destroy().
75
76 \param Map pointer to Map_info structure
77 \param area area id
78
79 \return pointer to GEOSGeometry instance
80 \return NULL on error
81 */
83{
84 int i, nholes, isle;
85 GEOSGeometry *boundary, *poly, **holes;
86
87 G_debug(3, "Vect_read_area_geos(): area = %d", area);
88
90 if (!boundary) {
91 G_fatal_error(_("Vect_read_area_geos(): unable to read area id %d"),
92 area);
93 }
94
97 for (i = 0; i < nholes; i++) {
98 isle = Vect_get_area_isle(Map, area, i);
99 if (isle < 1) {
100 nholes--;
101 continue;
102 }
103 holes[i] =
105 if (!(holes[i]))
106 G_fatal_error(_("Vect_read_area_geos(): unable to read isle id %d "
107 "of area id %d"),
108 isle, area);
109 }
110
111 poly = GEOSGeom_createPolygon(boundary, holes, nholes);
112 G_free(holes);
113
114 return poly;
115}
116
117/*!
118 \brief Create GEOSGeometry of given type from feature points.
119
120 Supported types:
121 - GV_POINT -> POINT
122 - GV_CENTROID -> POINT
123 - GV_LINE -> LINESTRING
124 - GV_BOUNDARY -> LINEARRING
125
126 You should free allocated memory by GEOSGeom_destroy().
127
128 \param points pointer to line_pnts structure
129 \param type feature type (see supported types)
130 \param with_z Set to 1 if the feature is 3d, 0 otherwise
131
132 \return pointer to GEOSGeometry instance
133 \return NULL on error
134 */
135GEOSGeometry *Vect_line_to_geos(const struct line_pnts *points, int type,
136 int with_z)
137{
138 int i;
141
142 G_debug(3, "Vect_line_to_geos(): type = %d", type);
143
144 /* read only points / lines / boundaries */
145 if (!(type & (GV_POINT | GV_CENTROID | GV_LINES)))
146 return NULL;
147
148 if (type == GV_POINT || type == GV_CENTROID) {
149 if (points->n_points != 1)
150 /* point is not valid */
151 return NULL;
152 }
153 else {
154 if (points->n_points < 2)
155 /* line/boundary is not valid */
156 return NULL;
157 }
158
159 pseq = GEOSCoordSeq_create(points->n_points, with_z ? 3 : 2);
160
161 for (i = 0; i < points->n_points; i++) {
162 GEOSCoordSeq_setX(pseq, i, points->x[i]);
163 GEOSCoordSeq_setY(pseq, i, points->y[i]);
164 if (with_z)
165 GEOSCoordSeq_setZ(pseq, i, points->z[i]);
166 }
167
168 if (type == GV_POINT || type == GV_CENTROID)
170 else if (type == GV_LINE)
172 else { /* boundary */
174 if (GEOSisRing(geom)) {
175 /*GEOSGeom_destroy(geom); */
177 }
178 }
179
180 /* GEOSCoordSeq_destroy(pseq); */
181
182 return geom;
183}
184
185/*!
186 \brief Read line from coor file
187
188 You should free allocated memory by GEOSGeom_destroy().
189
190 \param Map pointer to Map_info
191 \param offset line offset
192 \param[out] type feature type or NULL
193
194 \return pointer to GEOSGeometry
195 \return NULL on error
196 \return NULL dead line
197 \return NULL end of file
198 */
199GEOSGeometry *Vect__read_line_geos(struct Map_info *Map, long offset, int *type)
200{
201 int ftype;
202
205
206 pseq = V1_read_line_geos(Map, offset, &ftype);
207 if (!pseq)
208 G_fatal_error(_("Unable to read line offset %ld"), offset);
209
210 if (ftype & GV_POINT) {
211 G_debug(3, " geos_type = point");
213 }
214 else if (ftype & GV_LINE) {
215 G_debug(3, " geos_type = linestring");
217 }
218 else { /* boundary */
220 if (GEOSisRing(geom)) {
221 /* GEOSGeom_destroy(geom); */
223 G_debug(3, " geos_type = linearring");
224 }
225 else {
226 G_debug(3, " geos_type = linestring");
227 }
228 }
229
230 /* GEOSCoordSeq_destroy(pseq); */
231
232 if (type)
233 *type = ftype;
234
235 return geom;
236}
237
238/*!
239 \brief Read line from coor file into GEOSCoordSequence
240
241 You should free allocated memory by GEOSCoordSeq_destroy().
242
243 \param Map pointer to Map_info
244 \param line line id
245
246 \return pointer to GEOSCoordSequence
247 \return empty GEOSCoordSequence for dead line or unsuppored feature type
248 \return NULL end of file
249 */
250GEOSCoordSequence *V2_read_line_geos(struct Map_info *Map, int line)
251{
252 int ftype;
253 struct P_line *Line;
254
255 G_debug(3, "V2_read_line_geos(): line = %d", line);
256
257 Line = Map->plus.Line[line];
258
259 if (Line == NULL)
260 G_fatal_error("V2_read_line_geos(): %s %d",
261 _("Attempt to read dead line"), line);
262
263 return V1_read_line_geos(Map, Line->offset, &ftype);
264}
265
266/*!
267 \brief Read feature from coor file into GEOSCoordSequence
268
269 Note: Function reads only points, lines and boundaries, other
270 feature types are ignored (empty coord array is returned)!
271
272 You should free allocated memory by GEOSCoordSeq_destroy().
273
274 \param Map pointer to Map_info
275 \param offset line offset
276 \param[out] type feature type
277
278 \return pointer to GEOSCoordSequence
279 \return empty GEOSCoordSequence for dead line or unsuppored feature type
280 \return NULL end of file
281 */
282GEOSCoordSequence *V1_read_line_geos(struct Map_info *Map, long offset,
283 int *type)
284{
285 int i, n_points;
286 int do_cats, n_cats;
287 char rhead, nc;
288 long size;
289 double *x, *y, *z;
290
292
293 G_debug(3, "V1_read_line_geos(): offset = %ld", offset);
294
295 Map->head.last_offset = offset;
296
297 /* reads must set in_head, but writes use default */
298 dig_set_cur_port(&(Map->head.port));
299
300 dig_fseek(&(Map->dig_fp), offset, 0);
301
302 if (0 >= dig__fread_port_C(&rhead, 1, &(Map->dig_fp)))
303 return NULL; /* end of file */
304
305 if (!(rhead & 0x01)) /* dead line */
306 return GEOSCoordSeq_create(0, (Map->head.with_z) ? 3 : 2);
307
308 if (rhead & 0x02) /* categories exists */
309 do_cats =
310 1; /* do not return here let file offset moves forward to next */
311 else /* line */
312 do_cats = 0;
313
314 rhead >>= 2;
316
317 /* read only points / lines / boundaries */
318 if (!(*type & (GV_POINT | GV_LINES)))
319 return GEOSCoordSeq_create(0, (Map->head.with_z) ? 3 : 2);
320
321 /* skip categories */
322 if (do_cats) {
323 if (Map->head.coor_version.minor == 1) { /* coor format 5.1 */
324 if (0 >= dig__fread_port_I(&n_cats, 1, &(Map->dig_fp)))
325 return NULL;
326 }
327 else { /* coor format 5.0 */
328 if (0 >= dig__fread_port_C(&nc, 1, &(Map->dig_fp)))
329 return NULL;
330 n_cats = (int)nc;
331 }
332 G_debug(3, " n_cats = %d", n_cats);
333
334 if (Map->head.coor_version.minor == 1) { /* coor format 5.1 */
335 size = (2 * PORT_INT) * n_cats;
336 }
337 else { /* coor format 5.0 */
338 size = (PORT_SHORT + PORT_INT) * n_cats;
339 }
340 dig_fseek(&(Map->dig_fp), size, SEEK_CUR);
341 }
342
343 if (*type & GV_POINTS) {
344 n_points = 1;
345 }
346 else {
347 if (0 >= dig__fread_port_I(&n_points, 1, &(Map->dig_fp)))
348 return NULL;
349 }
350
351 G_debug(3, " n_points = %d dim = %d", n_points,
352 (Map->head.with_z) ? 3 : 2);
353
354 x = (double *)G_malloc(n_points * sizeof(double));
355 y = (double *)G_malloc(n_points * sizeof(double));
356 if (Map->head.with_z)
357 z = (double *)G_malloc(n_points * sizeof(double));
358 else
359 z = NULL;
360
361 if (0 >= dig__fread_port_D(x, n_points, &(Map->dig_fp))) {
362 goto free_return; /* end of file */
363 }
364
365 if (0 >= dig__fread_port_D(y, n_points, &(Map->dig_fp))) {
366 goto free_return; /* end of file */
367 }
368
369 if (Map->head.with_z) {
370 if (0 >= dig__fread_port_D(z, n_points, &(Map->dig_fp))) {
371 goto free_return; /* end of file */
372 }
373 }
374
375 pseq = GEOSCoordSeq_create(n_points, (Map->head.with_z) ? 3 : 2);
376
377 for (i = 0; i < n_points; i++) {
378 GEOSCoordSeq_setX(pseq, i, x[i]);
379 GEOSCoordSeq_setY(pseq, i, y[i]);
380 if (Map->head.with_z)
381 GEOSCoordSeq_setZ(pseq, i, z[i]);
382 }
383
384 G_debug(3, " off = %ld", (long)dig_ftell(&(Map->dig_fp)));
385
387 G_free((void *)x);
388 G_free((void *)y);
389 if (z)
390 G_free((void *)z);
391
392 return pseq;
393}
394
395/*!
396 \brief Returns the polygon array of points, i.e. outer ring (shell)
397
398 You should free allocated memory by GEOSCoordSeq_destroy().
399
400 See also Vect_get_area_points().
401
402 \param Map pointer to Map_info
403 \param area area id
404
405 \return pointer to GEOSCoordSequence
406 \return empty GEOSCoordSequence for dead area
407 \return NULL on error
408 */
410{
411 struct Plus_head *Plus;
412 struct P_area *Area;
413
414 G_debug(3, "Vect_get_area_points_geos(): area = %d", area);
415
416 Plus = &(Map->plus);
417 Area = Plus->Area[area];
418
419 if (Area == NULL) { /* dead area */
420 G_warning(_("Attempt to read points of nonexistent area id %d"), area);
421 return NULL; /* error , because we should not read dead areas */
422 }
423
424 return read_polygon_points(Map, Area->n_lines, Area->lines);
425}
426
427/*!
428 \brief Returns the polygon (isle) array of points (inner ring)
429
430 You should free allocated memory by GEOSCoordSeq_destroy().
431
432 See also Vect_get_isle_points().
433
434 \param Map pointer to Map_info
435 \param isle isel id
436
437 \return pointer to GEOSGeometry
438 \return NULL on error or dead line
439 */
441{
442 struct Plus_head *Plus;
443 struct P_isle *Isle;
444
445 G_debug(3, "Vect_get_isle_points_geos(): isle = %d", isle);
446
447 Plus = &(Map->plus);
448 Isle = Plus->Isle[isle];
449
450 return read_polygon_points(Map, Isle->n_lines, Isle->lines);
451}
452
453GEOSCoordSequence *read_polygon_points(struct Map_info *Map, int n_lines,
454 int *lines)
455{
456 int i, j, k;
457 int line, aline;
458 unsigned int n_points, n_points_shell;
459 double x, y, z;
460 int *dir;
461
463
464 G_debug(3, " n_lines = %d", n_lines);
465 pseq =
467 dir = (int *)G_malloc(n_lines * sizeof(int));
468
469 n_points_shell = 0;
470 for (i = 0; i < n_lines; i++) {
471 line = lines[i];
472 aline = abs(line);
473 G_debug(3, " append line(%d) = %d", i, line);
474
475 if (line > 0)
476 dir[i] = GV_FORWARD;
477 else
478 dir[i] = GV_BACKWARD;
479
480 pseq[i] = V2_read_line_geos(Map, aline);
481 if (!(pseq[i])) {
482 G_fatal_error(_("Unable to read feature id %d"), aline);
483 }
484
485 GEOSCoordSeq_getSize(pseq[i], &n_points);
486 G_debug(3, " line n_points = %d", n_points);
487 n_points_shell += n_points;
488 }
489
490 /* create shell (outer ring) */
491 pseq_shell = GEOSCoordSeq_create(n_points_shell, Map->head.with_z ? 3 : 2);
492 k = 0;
493 for (i = 0; i < n_lines; i++) {
494 GEOSCoordSeq_getSize(pseq[i], &n_points);
495 if (dir[i] == GV_FORWARD) {
496 for (j = 0; j < (int)n_points; j++, k++) {
497 GEOSCoordSeq_getX(pseq[i], j, &x);
499
500 GEOSCoordSeq_getY(pseq[i], j, &y);
502
503 if (Map->head.with_z) {
504 GEOSCoordSeq_getY(pseq[i], j, &z);
506 }
507 }
508 }
509 else { /* GV_BACKWARD */
510 for (j = (int)n_points - 1; j > -1; j--, k++) {
511 GEOSCoordSeq_getX(pseq[i], j, &x);
513
514 GEOSCoordSeq_getY(pseq[i], j, &y);
516
517 if (Map->head.with_z) {
518 GEOSCoordSeq_getY(pseq[i], j, &z);
520 }
521 }
522 }
524 }
525
526 G_free((void *)pseq);
527 G_free((void *)dir);
528
529 return pseq_shell;
530}
531#endif /* HAVE_GEOS */
#define NULL
Definition ccmath.h:32
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
int G_debug(int, const char *,...) __attribute__((format(printf
int Vect_get_area_isle(struct Map_info *, int, int)
Returns isle id for area.
int Vect_get_area_num_isles(struct Map_info *, int)
Returns number of isles for given area.
const char * Vect_get_full_name(struct Map_info *)
Get fully qualified name of vector map.
#define GV_CENTROID
#define GV_LINE
#define GV_POINT
Feature types used in memory on run time (may change)
#define VECT_OPEN(Map)
Check if vector map is open.
#define GV_LINES
#define PORT_SHORT
Definition dig_defines.h:49
#define PORT_INT
Definition dig_defines.h:48
#define GV_FORWARD
Line direction indicator forward/backward.
#define GV_POINTS
#define GV_BACKWARD
#define GV_FORMAT_NATIVE
Geometry data formats supported by lib Don't change GV_FORMAT_* values, this order is hardcoded in li...
Definition dig_defines.h:83
int dig__fread_port_D(double *, size_t, struct gvfile *)
Read doubles from the Portable Vector Format.
Definition portable.c:77
off_t dig_ftell(struct gvfile *file)
Get struct gvfile position.
Definition file.c:34
int dig_set_cur_port(struct Port_info *)
Set current Port_info structure.
Definition portable.c:994
int dig__fread_port_C(char *, size_t, struct gvfile *)
Read chars from the Portable Vector Format.
Definition portable.c:509
int dig__fread_port_I(int *, size_t, struct gvfile *)
Read integers from the Portable Vector Format.
Definition portable.c:343
int dig_fseek(struct gvfile *file, off_t offset, int whence)
Set struct gvfile position.
Definition file.c:58
int dig_type_from_store(int)
Convert type from store type.
GEOSGeometry * Vect_read_line_geos(struct Map_info *Map, int line, int *type)
Read vector feature and stores it as GEOSGeometry instance.
Definition geos.c:43
GEOSCoordSequence * Vect_get_area_points_geos(struct Map_info *Map, int area)
Returns the polygon array of points, i.e. outer ring (shell)
Definition geos.c:409
GEOSCoordSequence * Vect_get_isle_points_geos(struct Map_info *Map, int isle)
Returns the polygon (isle) array of points (inner ring)
Definition geos.c:440
GEOSGeometry * Vect_line_to_geos(const struct line_pnts *points, int type, int with_z)
Create GEOSGeometry of given type from feature points.
Definition geos.c:135
GEOSGeometry * Vect_read_area_geos(struct Map_info *Map, int area)
Read vector area and stores it as GEOSGeometry instance (polygon)
Definition geos.c:82
#define _(str)
Definition glocale.h:10
Vector map info.
Area (topology) info.
plus_t n_lines
Number of boundary lines.
plus_t * lines
List of boundary lines.
Isle (topology) info.
plus_t * lines
List of boundary lines.
plus_t n_lines
Number of boundary lines.
Vector geometry.
char type
Line type.
off_t offset
Offset in coor file for line.
Basic topology-related 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.
struct GEOSCoordSeq_t GEOSCoordSequence
Definition vector.h:10
struct GEOSGeom_t GEOSGeometry
Definition vector.h:9
#define x