GRASS 8 Programmer's Manual 8.6.0dev(2026)-1d1e47ad9d
Loading...
Searching...
No Matches
write_ogr.c
Go to the documentation of this file.
1/*!
2 \file lib/vector/Vlib/write_ogr.c
3
4 \brief Vector library - write vector feature (OGR format)
5
6 Higher level functions for reading/writing/manipulating vectors.
7
8 Partly inspired by v.out.ogr's code.
9
10 \todo How to deal with OGRNullFID
11
12 (C) 2009-2013 by Martin Landa, and the GRASS Development Team
13
14 This program is free software under the GNU General Public License
15 (>=v2). Read the file COPYING that comes with GRASS for details.
16
17 \author Martin Landa <landa.martin gmail.com>
18 */
19
20#include <inttypes.h>
21#include <grass/vector.h>
22#include <grass/dbmi.h>
23#include <grass/gprojects.h>
24#include <grass/glocale.h>
25
26#include <ogr_api.h>
27#include <cpl_string.h>
28
29static dbDriver *create_table(OGRLayerH, const struct field_info *);
30static int create_ogr_layer(struct Map_info *, int);
31static off_t write_feature(struct Map_info *, int, const struct line_pnts **,
32 int, const struct line_cats *);
33static int write_attributes(dbDriver *, int, const struct field_info *,
35static int sqltype_to_ogrtype(int);
36
37/*!
38 \brief Writes feature on level 1 (OGR interface)
39
40 Note:
41 - centroids are not supported in OGR, pseudotopo holds virtual
42 centroids (it's coordinates determined from spatial index)
43 - unclosed boundaries are not supported in OGR, pseudotopo treats
44 polygons as boundaries
45
46 Supported feature types:
47 - GV_POINT (written as wkbPoint)
48 - GV_LINE (wkbLineString)
49 - GV_BOUNDARY (wkbPolygon)
50 - GV_FACE (wkbPolygon25D)
51 - GV_KERNEL (wkbPoint25D)
52
53 \param Map pointer to Map_info structure
54 \param type feature type
55 \param points pointer to line_pnts structure (feature geometry)
56 \param cats pointer to line_cats structure (feature categories)
57
58 \return feature index in offset array (related to pseudo-topology)
59 \return -1 on error
60 */
62 const struct line_pnts *points,
63 const struct line_cats *cats)
64{
65 return write_feature(Map, type, &points, 1, cats);
66}
67
68/*!
69 \brief Rewrites feature at the given offset on level 1 (OGR interface)
70
71 This function simply calls V1_delete_line_ogr() and V1_write_line_ogr().
72
73 \param Map pointer to Map_info structure
74 \param offset feature offset
75 \param type feature type (see V1_write_line_ogr() for supported types)
76 \param points pointer to line_pnts structure (feature geometry)
77 \param cats pointer to line_cats structure (feature categories)
78
79 \return feature offset (rewritten feature)
80 \return -1 on error
81 */
82off_t V1_rewrite_line_ogr(struct Map_info *Map, off_t offset, int type,
83 const struct line_pnts *points,
84 const struct line_cats *cats)
85{
86 G_debug(3, "V1_rewrite_line_ogr(): type=%d offset=%" PRId64, type, offset);
87 if (type != V1_read_line_ogr(Map, NULL, NULL, offset)) {
88 G_warning(_("Unable to rewrite feature (incompatible feature types)"));
89 return -1;
90 }
91
92 /* delete old */
93 V1_delete_line_ogr(Map, offset);
94
95 return V1_write_line_ogr(Map, type, points, cats);
96}
97
98/*!
99 \brief Deletes feature at the given offset on level 1 (OGR interface)
100
101 \param Map pointer Map_info structure
102 \param offset offset of feature to be deleted
103
104 \return 0 on success
105 \return -1 on error
106 */
108{
110
111 G_debug(3, "V1_delete_line_ogr(), offset = %lu", (unsigned long)offset);
112
113 ogr_info = &(Map->fInfo.ogr);
114
115 if (!ogr_info->layer) {
116 G_warning(_("OGR layer not defined"));
117 return -1;
118 }
119
120 if (offset >= ogr_info->offset.array_num) {
121 G_warning(_("Invalid offset (%" PRId64 ")"), offset);
122 return -1;
123 }
124
125 if (OGR_L_DeleteFeature(ogr_info->layer, ogr_info->offset.array[offset]) !=
126 OGRERR_NONE) {
127 G_warning(_("Unable to delete feature"));
128 return -1;
129 }
130
131 return 0;
132}
133
134/*!
135 \brief Writes area on topological level (OGR Simple Features
136 interface, internal use only)
137
138 \param Map pointer to Map_info structure
139 \param points feature geometry (exterior + interior rings)
140 \param nparts number of parts including exterior ring
141 \param cats feature categories
142
143 \return feature offset
144 \return -1 on error
145 */
146off_t V2__write_area_ogr(struct Map_info *Map, const struct line_pnts **points,
147 int nparts, const struct line_cats *cats)
148{
149 return write_feature(Map, GV_BOUNDARY, points, nparts, cats);
150}
151
152dbDriver *create_table(OGRLayerH hLayer, const struct field_info *Fi)
153{
154 int col, ncols;
155 int sqltype, ogrtype, length;
156
157 const char *colname;
158
160 dbHandle handle;
162 dbTable *table;
165
168
170 db_init_handle(&handle);
171
172 driver = db_start_driver(Fi->driver);
173 if (!driver) {
174 G_warning(_("Unable to start driver <%s>"), Fi->driver);
175 return NULL;
176 }
177 db_set_handle(&handle, Fi->database, NULL);
178 if (db_open_database(driver, &handle) != DB_OK) {
179 G_warning(_("Unable to open database <%s> by driver <%s>"),
180 Fi->database, Fi->driver);
182 return NULL;
183 }
184
185 /* to get no data */
186 db_set_string(&sql, "select * from ");
187 db_append_string(&sql, Fi->table);
188 db_append_string(&sql, " where 0 = 1");
189
191 G_warning(_("Unable to open select cursor: '%s'"), db_get_string(&sql));
193 return NULL;
194 }
195
196 table = db_get_cursor_table(&cursor);
197 ncols = db_get_table_number_of_columns(table);
198
200
201 for (col = 0; col < ncols; col++) {
205 ogrtype = sqltype_to_ogrtype(sqltype);
207
210 /* field already exists */
211 continue;
212 }
213
215 /* GDAL 1.9.0 (r22968) uses VARCHAR instead of CHAR */
216 if (ogrtype == OFTString && length > 0)
219 G_warning(_("Creating field <%s> failed"), colname);
221 return NULL;
222 }
223
225 }
226
227 return driver;
228}
229
230/*!
231 \brief Create new OGR layer in given OGR datasource (internal use only)
232
233 V1_open_new_ogr() is required to be called before this function.
234
235 List of currently supported types:
236 - GV_POINT (wkbPoint)
237 - GV_LINE (wkbLineString)
238 - GV_BOUNDARY (wkb_Polygon)
239 \param[in,out] Map pointer to Map_info structure
240 \param type feature type (GV_POINT, GV_LINE, ...)
241
242 \return 0 success
243 \return -1 error
244 */
245int create_ogr_layer(struct Map_info *Map, int type)
246{
247 int ndblinks;
250
251 struct field_info *Fi;
252 struct Key_Value *projinfo, *projunits, *projepsg;
254
256 char **Ogr_layer_options;
257
258 ogr_info = &(Map->fInfo.ogr);
259
260 if (!ogr_info->driver_name || !ogr_info->layer_name || !ogr_info->ds)
261 return -1;
262
263 /* get spatial reference */
264 projinfo = G_get_projinfo();
265 projunits = G_get_projunits();
266 projepsg = G_get_projepsg();
267 Ogr_spatial_ref = GPJ_grass_to_osr2(projinfo, projunits, projepsg);
268 G_free_key_value(projinfo);
269 G_free_key_value(projunits);
270
271 /* determine geometry type */
272 switch (type) {
273 case GV_POINT:
275 break;
276 case GV_LINE:
278 break;
279 case GV_BOUNDARY:
281 break;
282 default:
283 G_warning(_("Unsupported geometry type (%d)"), type);
284 return -1;
285 }
286
287 /* check creation options */
288 Ogr_layer_options = ogr_info->layer_options;
289 if (Vect_is_3d(Map)) {
290 if (strcmp(ogr_info->driver_name, "PostgreSQL") == 0) {
292 }
293 }
294 else {
295 if (strcmp(ogr_info->driver_name, "PostgreSQL") == 0) {
297 }
298 }
299
300 /* create new OGR layer */
301 Ogr_layer =
305 if (!Ogr_layer) {
306 G_warning(_("Unable to create OGR layer <%s> in '%s'"),
307 ogr_info->layer_name, ogr_info->dsn);
308 return -1;
309 }
310 ogr_info->layer = Ogr_layer;
311
313 if (ndblinks > 0) {
314 /* write also attributes */
315 Fi = Vect_get_dblink(Map, 0);
316 if (Fi) {
317 if (ndblinks > 1)
318 G_warning(_("More layers defined, using driver <%s> and "
319 "database <%s>"),
320 Fi->driver, Fi->database);
321 ogr_info->dbdriver = create_table(ogr_info->layer, Fi);
322 G_free(Fi);
323 }
324 else
325 G_warning(_("Database connection not defined. "
326 "Unable to write attributes."));
327 }
328
331 G_warning(_("OGR transaction with layer <%s> failed to start"),
332 ogr_info->layer_name);
333 return -1;
334 }
335
336 return 0;
337}
338
339/*!
340 \brief Write OGR feature
341
342 \param Map pointer to Map_info structure
343 \param type feature type (GV_POINT, GV_LINE, ...)
344 \param bpoints feature geometry
345 \param cats feature categories
346 \param ipoints isle geometry for polygons on NULL
347 \param nisles number of isles
348
349 \return feature offset into file
350 \return -1 on error
351 */
352off_t write_feature(struct Map_info *Map, int type,
353 const struct line_pnts **p_points, int nparts,
354 const struct line_cats *cats)
355{
356 int i, cat, ret;
357
358 struct field_info *Fi;
359 const struct line_pnts *points;
362
363 off_t offset;
364
369
370 ogr_info = &(Map->fInfo.ogr);
371 offset_info = &(ogr_info->offset);
372
373 if (nparts < 1)
374 return -1;
375
376 points = p_points[0]; /* feature geometry */
377
378 if (!ogr_info->layer) {
379 /* create OGR layer if doesn't exist */
380 if (create_ogr_layer(Map, type) < 0)
381 return -1;
382 }
383
384 if (!points)
385 return 0;
386
387 cat = -1; /* no attributes to be written */
388 if (cats->n_cats > 0 && Vect_get_num_dblinks(Map) > 0) {
389 /* check for attributes */
390 Fi = Vect_get_dblink(Map, 0);
391 if (Fi) {
392 if (!Vect_cat_get(cats, Fi->number, &cat))
393 G_warning(_("No category defined for layer %d"), Fi->number);
394 if (cats->n_cats > 1) {
395 G_warning(_("Feature has more categories, using "
396 "category %d (from layer %d)"),
397 cat, cats->field[0]);
398 }
399 }
400 }
401
404
405 /* determine matching OGR feature geometry type */
406 if (type & (GV_POINT | GV_KERNEL)) {
408 G_warning(_("Feature is not a point. Skipping."));
409 return -1;
410 }
412 }
413 else if (type & GV_LINE) {
416 G_warning(_("Feature is not a line. Skipping."));
417 return -1;
418 }
420 }
421 else if (type & GV_BOUNDARY) {
422 if (Ogr_geom_type != wkbPolygon) {
423 G_warning(_("Feature is not a polygon. Skipping."));
424 return -1;
425 }
427 }
428 else if (type & GV_FACE) {
430 G_warning(_("Feature is not a face. Skipping."));
431 return -1;
432 }
434 }
435 else {
436 G_warning(_("Unsupported feature type (%d)"), type);
437 return -1;
438 }
439
440 G_debug(3, "V1_write_line_ogr(): type = %d", type);
441
443 int iring, npoints;
444
445 /* add rings (first is exterior ring) */
446 for (iring = 0; iring < nparts; iring++) {
448
449 points = p_points[iring];
450 npoints = points->n_points - 1;
452 if (points->x[0] != points->x[npoints] ||
453 points->y[0] != points->y[npoints] ||
454 points->z[0] != points->z[npoints]) {
455 G_warning(_("Boundary is not closed. Feature skipped."));
456 return -1;
457 }
458
459 /* add points */
460 for (i = 0; i < npoints; i++) {
461 OGR_G_AddPoint(Ogr_ring, points->x[i], points->y[i],
462 points->z[i]);
463 }
464 G_debug(4, " ring(%d): n_points = %d", iring, npoints);
466 }
467 }
468 else {
469 for (i = 0; i < points->n_points; i++) {
470 OGR_G_AddPoint(Ogr_geometry, points->x[i], points->y[i],
471 points->z[i]);
472 }
473 G_debug(4, " n_points = %d", points->n_points);
474 }
475
476 /* create feature & set geometry */
479
480 /* write attributes */
481 if (cat > -1 && ogr_info->dbdriver) {
482 if (0 > write_attributes(ogr_info->dbdriver, cat, Fi, ogr_info->layer,
484 G_warning(_("Unable to writes feature attributes"));
485 G_free(Fi);
486 }
487 /* write feature into layer */
489
490 /* update offset array */
491 if (offset_info->array_num >= offset_info->array_alloc) {
492 offset_info->array_alloc += 1000;
493 offset_info->array = (int *)G_realloc(
494 offset_info->array, offset_info->array_alloc * sizeof(int));
495 }
496
497 offset = offset_info->array_num;
498
499 offset_info->array[offset_info->array_num++] =
502 /* register exterior ring in offset array */
503 offset_info->array[offset_info->array_num++] = 0;
504 }
505
506 /* destroy */
509
510 if (ret != OGRERR_NONE)
511 return -1;
512
513 G_debug(3, "write_feature(): -> offset = %lu offset_num = %d cat = %d",
514 (unsigned long)offset, offset_info->array_num, cat);
515
516 return offset;
517}
518
519/*!
520 \brief Writes attributes
521
522 \param driver pointer to dbDriver
523 \param Fi pointer to field_info struct
524 \param[in,out] Ogr_layer OGR layer
525 \param[in,out] Ogr_feature OGR feature to modify
526
527 \return 1 on success
528 \return 0 no attributes
529 \return -1 on error
530 */
531int write_attributes(dbDriver *driver, int cat, const struct field_info *Fi,
533{
534 int j, ogrfieldnum;
535 char buf[2000];
536 int ncol, sqltype, ctype, ogrtype, more;
537 const char *fidcol, *colname;
538 dbTable *table;
542 dbValue *value;
543
545
546 G_debug(3, "write_attributes(): cat = %d", cat);
547
548 if (cat < 0) {
549 G_warning(_("Feature without category of layer %d"), Fi->number);
550 return 0;
551 }
552
554
555 /* read & set attributes */
556 snprintf(buf, sizeof(buf), "SELECT * FROM %s WHERE %s = %d", Fi->table,
557 Fi->key, cat);
558 G_debug(4, "SQL: %s", buf);
559 db_set_string(&dbstring, buf);
560
561 /* select data */
563 DB_OK) {
564 G_warning(_("Unable to select attributes for category %d"), cat);
565 return -1;
566 }
567
568 if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) {
569 G_warning(_("Unable to fetch data from table <%s>"), Fi->table);
570 return -1;
571 }
572
573 if (!more) {
574 G_warning(_("No database record for category %d, "
575 "no attributes will be written"),
576 cat);
577 return -1;
578 }
579
581
582 table = db_get_cursor_table(&cursor);
584 for (j = 0; j < ncol; j++) {
585 column = db_get_table_column(table, j);
587 if (fidcol && *fidcol && strcmp(colname, fidcol) == 0) {
588 /* skip fid column */
589 continue;
590 }
592 /* for debug only */
594 G_debug(3, "col %d : val = %s", j, db_get_string(&dbstring));
595
598 ogrtype = sqltype_to_ogrtype(sqltype);
599 G_debug(3, " colctype = %d", ctype);
600
602 if (ogrfieldnum < 0) {
603 /* create field if not exists */
606 G_warning(_("Unable to create field <%s>"), colname);
608 }
609
610 /* Reset */
612
613 /* prevent writing NULL values */
614 if (!db_test_value_isnull(value)) {
615 switch (ctype) {
616 case DB_C_TYPE_INT:
618 db_get_value_int(value));
619 break;
620 case DB_C_TYPE_DOUBLE:
622 db_get_value_double(value));
623 break;
624 case DB_C_TYPE_STRING:
626 db_get_value_string(value));
627 break;
632 break;
633 default:
634 G_warning(_("Unsupported column type %d"), ctype);
635 break;
636 }
637 }
638 }
639
641
643
644 return 1;
645}
646
647int sqltype_to_ogrtype(int sqltype)
648{
649 int ctype, ogrtype;
650
652
653 switch (ctype) {
654 case DB_C_TYPE_INT:
656 break;
657 case DB_C_TYPE_DOUBLE:
659 break;
660 case DB_C_TYPE_STRING:
662 break;
665 break;
666 default:
668 break;
669 }
670
671 return ogrtype;
672}
#define NULL
Definition ccmath.h:32
Main header of GRASS DataBase Management Interface.
#define DB_C_TYPE_INT
Definition dbmi.h:108
#define DB_SEQUENTIAL
Definition dbmi.h:123
#define DB_C_TYPE_STRING
Definition dbmi.h:107
#define DB_C_TYPE_DOUBLE
Definition dbmi.h:109
#define DB_OK
Definition dbmi.h:71
#define DB_C_TYPE_DATETIME
Definition dbmi.h:110
#define DB_NEXT
Definition dbmi.h:114
int db_test_value_isnull(dbValue *)
Check of value is null.
Definition value.c:26
int db_get_column_length(dbColumn *)
Get column's length.
dbColumn * db_get_table_column(dbTable *, int)
Returns column structure for given table and column number.
double db_get_value_double(dbValue *)
Get double precision value.
Definition value.c:50
int db_sqltype_to_Ctype(int)
Get C data type based on given SQL data type.
Definition sqlCtype.c:24
dbValue * db_get_column_value(dbColumn *)
Returns column value for given column structure.
int db_get_column_sqltype(dbColumn *)
Returns column sqltype for column.
int db_open_database(dbDriver *, dbHandle *)
Open database connection.
Definition c_opendb.c:27
int db_close_database_shutdown_driver(dbDriver *)
Close driver/database connection.
Definition db.c:61
void db_free_string(dbString *)
Free allocated space for dbString.
Definition string.c:150
char * db_get_string(const dbString *)
Get string.
Definition string.c:140
dbTable * db_get_cursor_table(dbCursor *)
Get table allocated by cursor.
Definition cursor.c:67
int db_set_string(dbString *, const char *)
Inserts string to dbString (enlarge string)
Definition string.c:41
const char * db_get_column_name(dbColumn *)
Returns column name for given column.
int db_set_handle(dbHandle *, const char *, const char *)
Set handle (database and schema name)
Definition handle.c:39
int db_get_value_int(dbValue *)
Get integer value.
Definition value.c:38
dbDriver * db_start_driver(const char *)
Initialize a new dbDriver for db transaction.
Definition start.c:51
void db_init_handle(dbHandle *)
Initialize handle (i.e database/schema)
Definition handle.c:23
void db_init_string(dbString *)
Initialize dbString.
Definition string.c:25
int db_close_cursor(dbCursor *)
Close cursor.
Definition c_close_cur.c:27
int db_open_select_cursor(dbDriver *, dbString *, dbCursor *, int)
Open select cursor.
int db_append_string(dbString *, const char *)
Append string to dbString.
Definition string.c:205
int db_convert_column_value_to_string(dbColumn *, dbString *)
?
Definition columnfmt.c:62
const char * db_get_value_string(dbValue *)
Get string value.
Definition value.c:92
int db_fetch(dbCursor *, int, int *)
Fetch data from open cursor.
Definition c_fetch.c:28
int db_get_table_number_of_columns(dbTable *)
Return the number of columns of the table.
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:147
#define G_realloc(p, n)
Definition defs/gis.h:141
struct Key_Value * G_get_projinfo(void)
Gets projection information for location.
void G_warning(const char *,...) __attribute__((format(printf
struct Key_Value * G_get_projepsg(void)
Gets EPSG information for the current location.
void G_free_key_value(struct Key_Value *)
Free allocated Key_Value structure.
Definition key_value1.c:104
struct Key_Value * G_get_projunits(void)
Gets units information for location.
int G_debug(int, const char *,...) __attribute__((format(printf
OGRSpatialReferenceH GPJ_grass_to_osr2(const struct Key_Value *, const struct Key_Value *, const struct Key_Value *)
Converts a GRASS co-ordinate system to an OGRSpatialReferenceH object. EPSG code is preferred if avai...
Definition convert.c:347
int Vect_cat_get(const struct line_cats *, int, int *)
Get first found category of given field.
int V1_read_line_ogr(struct Map_info *, struct line_pnts *, struct line_cats *, off_t)
Read feature from OGR layer at given offset (level 1 without topology)
Definition read_ogr.c:167
struct field_info * Vect_get_dblink(struct Map_info *, int)
Get information about link to database.
Definition field.c:470
int Vect_get_num_dblinks(struct Map_info *)
Get number of defined dblinks.
Definition level_two.c:159
int Vect_is_3d(struct Map_info *)
Check if vector map is 3D.
#define GV_LINE
#define GV_POINT
Feature types used in memory on run time (may change)
#define GV_BOUNDARY
#define GV_FACE
#define GV_KERNEL
#define TRUE
Definition gis.h:78
#define _(str)
Definition glocale.h:10
Data structure used for building pseudo-topology.
Non-native format info (OGR)
OGRSFDriverH driver
Pointer to OGRDriver.
struct Format_info_offset offset
Offset list used for building pseudo-topology.
Vector map info.
Layer (old: field) information.
Feature category info.
int * field
Array of layers (fields)
int n_cats
Number of categories attached to element.
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.
int V1_delete_line_ogr(struct Map_info *Map, off_t offset)
Deletes feature at the given offset on level 1 (OGR interface)
Definition write_ogr.c:107
off_t V2__write_area_ogr(struct Map_info *Map, const struct line_pnts **points, int nparts, const struct line_cats *cats)
Writes area on topological level (OGR Simple Features interface, internal use only)
Definition write_ogr.c:146
off_t V1_write_line_ogr(struct Map_info *Map, int type, const struct line_pnts *points, const struct line_cats *cats)
Writes feature on level 1 (OGR interface)
Definition write_ogr.c:61
off_t V1_rewrite_line_ogr(struct Map_info *Map, off_t offset, int type, const struct line_pnts *points, const struct line_cats *cats)
Rewrites feature at the given offset on level 1 (OGR interface)
Definition write_ogr.c:82