write_ogr.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. /*!
  2. \file lib/vector/Vlib/write_ogr.c
  3. \brief Vector library - write vector feature (OGR format)
  4. Higher level functions for reading/writing/manipulating vectors.
  5. Partly inspired by v.out.ogr's code.
  6. \todo How to deal with OGRNullFID
  7. (C) 2009-2013 by Martin Landa, and the GRASS Development Team
  8. This program is free software under the GNU General Public License
  9. (>=v2). Read the file COPYING that comes with GRASS for details.
  10. \author Martin Landa <landa.martin gmail.com>
  11. */
  12. #include <grass/vector.h>
  13. #include <grass/dbmi.h>
  14. #include <grass/glocale.h>
  15. #ifdef HAVE_OGR
  16. #include <ogr_api.h>
  17. static off_t write_feature(struct Map_info *, int, const struct line_pnts **, int,
  18. const struct line_cats *);
  19. static int write_attributes(dbDriver *, int, const struct field_info *,
  20. OGRLayerH, OGRFeatureH);
  21. static int sqltype_to_ogrtype(int);
  22. #endif
  23. /*!
  24. \brief Writes feature on level 1 (OGR interface)
  25. Note:
  26. - centroids are not supported in OGR, pseudotopo holds virtual
  27. centroids (it's coordinates determined from spatial index)
  28. - unclosed boundaries are not supported in OGR, pseudotopo treats
  29. polygons as boundaries
  30. Supported feature types:
  31. - GV_POINT (written as wkbPoint)
  32. - GV_LINE (wkbLineString)
  33. - GV_BOUNDARY (wkbPolygon)
  34. - GV_FACE (wkbPolygon25D)
  35. - GV_KERNEL (wkbPoint25D)
  36. \param Map pointer to Map_info structure
  37. \param type feature type
  38. \param points pointer to line_pnts structure (feature geometry)
  39. \param cats pointer to line_cats structure (feature categories)
  40. \return feature index in offset array (related to pseudo-topology)
  41. \return -1 on error
  42. */
  43. off_t V1_write_line_ogr(struct Map_info *Map, int type,
  44. const struct line_pnts *points,
  45. const struct line_cats *cats)
  46. {
  47. #ifdef HAVE_OGR
  48. return write_feature(Map, type, &points, 1, cats);
  49. #else
  50. G_fatal_error(_("GRASS is not compiled with OGR support"));
  51. return -1;
  52. #endif
  53. }
  54. /*!
  55. \brief Rewrites feature at the given offset on level 1 (OGR interface)
  56. This function simply calls V1_delete_line_ogr() and V1_write_line_ogr().
  57. \param Map pointer to Map_info structure
  58. \param offset feature offset
  59. \param type feature type (see V1_write_line_ogr() for supported types)
  60. \param points pointer to line_pnts structure (feature geometry)
  61. \param cats pointer to line_cats structure (feature categories)
  62. \return feature offset (rewriten feature)
  63. \return -1 on error
  64. */
  65. off_t V1_rewrite_line_ogr(struct Map_info *Map,
  66. int line, int type, off_t offset,
  67. const struct line_pnts *points, const struct line_cats *cats)
  68. {
  69. G_debug(3, "V1_rewrite_line_ogr(): line=%d type=%d offset=%"PRI_OFF_T,
  70. line, type, offset);
  71. #ifdef HAVE_OGR
  72. if (type != V1_read_line_ogr(Map, NULL, NULL, offset)) {
  73. G_warning(_("Unable to rewrite feature (incompatible feature types)"));
  74. return -1;
  75. }
  76. /* delete old */
  77. V1_delete_line_ogr(Map, offset);
  78. return V1_write_line_ogr(Map, type, points, cats);
  79. #else
  80. G_fatal_error(_("GRASS is not compiled with OGR support"));
  81. return -1;
  82. #endif
  83. }
  84. /*!
  85. \brief Deletes feature at the given offset on level 1 (OGR interface)
  86. \param Map pointer Map_info structure
  87. \param offset offset of feature to be deleted
  88. \return 0 on success
  89. \return -1 on error
  90. */
  91. int V1_delete_line_ogr(struct Map_info *Map, off_t offset)
  92. {
  93. #ifdef HAVE_OGR
  94. struct Format_info_ogr *ogr_info;
  95. G_debug(3, "V1_delete_line_ogr(), offset = %lu", (unsigned long) offset);
  96. ogr_info = &(Map->fInfo.ogr);
  97. if (!ogr_info->layer) {
  98. G_warning(_("OGR layer not defined"));
  99. return -1;
  100. }
  101. if (offset >= ogr_info->offset.array_num) {
  102. G_warning(_("Invalid offset (%d)"), offset);
  103. return -1;
  104. }
  105. if (OGR_L_DeleteFeature(ogr_info->layer,
  106. ogr_info->offset.array[offset]) != OGRERR_NONE)
  107. G_warning(_("Unable to delete feature"));
  108. return -1;
  109. return 0;
  110. #else
  111. G_fatal_error(_("GRASS is not compiled with OGR support"));
  112. return -1;
  113. #endif
  114. }
  115. #ifdef HAVE_OGR
  116. /*!
  117. \brief Writes area on topological level (OGR Simple Features
  118. interface, internal use only)
  119. \param Map pointer to Map_info structure
  120. \param points feature geometry (exterior + interior rings)
  121. \param nparts number of parts including exterior ring
  122. \param cats feature categories
  123. \return feature offset
  124. \return -1 on error
  125. */
  126. off_t V2__write_area_ogr(struct Map_info *Map,
  127. const struct line_pnts **points, int nparts,
  128. const struct line_cats *cats)
  129. {
  130. return write_feature(Map, GV_BOUNDARY, points, nparts, cats);
  131. }
  132. /*!
  133. \brief Write OGR feature
  134. \param Map pointer to Map_info structure
  135. \param type feature type (GV_POINT, GV_LINE, ...)
  136. \param bpoints feature geometry
  137. \param cats feature categories
  138. \param ipoints isle geometry for polygons on NULL
  139. \param nisles number of isles
  140. \return feature offset into file
  141. \return -1 on error
  142. */
  143. off_t write_feature(struct Map_info *Map, int type,
  144. const struct line_pnts **p_points, int nparts,
  145. const struct line_cats *cats)
  146. {
  147. int i, cat, ret;
  148. struct field_info *Fi;
  149. const struct line_pnts *points;
  150. struct Format_info_ogr *ogr_info;
  151. struct Format_info_offset *offset_info;
  152. off_t offset;
  153. OGRGeometryH Ogr_geometry;
  154. OGRFeatureH Ogr_feature;
  155. OGRFeatureDefnH Ogr_featuredefn;
  156. OGRwkbGeometryType Ogr_geom_type;
  157. ogr_info = &(Map->fInfo.ogr);
  158. offset_info = &(ogr_info->offset);
  159. if (nparts < 1)
  160. return -1;
  161. points = p_points[0]; /* feature geometry */
  162. if (!ogr_info->layer) {
  163. /* create OGR layer if doesn't exist */
  164. if (V2_open_new_ogr(Map, type) < 0)
  165. return -1;
  166. }
  167. cat = -1; /* no attributes to be written */
  168. if (cats->n_cats > 0 && Vect_get_num_dblinks(Map) > 0) {
  169. /* check for attributes */
  170. Fi = Vect_get_dblink(Map, 0);
  171. if (Fi) {
  172. if (!Vect_cat_get(cats, Fi->number, &cat))
  173. G_warning(_("No category defined for layer %d"), Fi->number);
  174. if (cats->n_cats > 1) {
  175. G_warning(_("Feature has more categories, using "
  176. "category %d (from layer %d)"),
  177. cat, cats->field[0]);
  178. }
  179. }
  180. }
  181. Ogr_featuredefn = OGR_L_GetLayerDefn(ogr_info->layer);
  182. Ogr_geom_type = OGR_FD_GetGeomType(Ogr_featuredefn);
  183. /* determine matching OGR feature geometry type */
  184. if (type & (GV_POINT | GV_KERNEL)) {
  185. if (Ogr_geom_type != wkbPoint &&
  186. Ogr_geom_type != wkbPoint25D) {
  187. G_warning(_("Feature is not a point. Skipping."));
  188. return -1;
  189. }
  190. Ogr_geometry = OGR_G_CreateGeometry(wkbPoint);
  191. }
  192. else if (type & GV_LINE) {
  193. if (Ogr_geom_type != wkbLineString &&
  194. Ogr_geom_type != wkbLineString25D) {
  195. G_warning(_("Feature is not a line. Skipping."));
  196. return -1;
  197. }
  198. Ogr_geometry = OGR_G_CreateGeometry(wkbLineString);
  199. }
  200. else if (type & GV_BOUNDARY) {
  201. if (Ogr_geom_type != wkbPolygon) {
  202. G_warning(_("Feature is not a polygon. Skipping."));
  203. return -1;
  204. }
  205. Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon);
  206. }
  207. else if (type & GV_FACE) {
  208. if (Ogr_geom_type != wkbPolygon25D) {
  209. G_warning(_("Feature is not a face. Skipping."));
  210. return -1;
  211. }
  212. Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon25D);
  213. }
  214. else {
  215. G_warning(_("Unsupported feature type (%d)"), type);
  216. return -1;
  217. }
  218. G_debug(3, "V1_write_line_ogr(): type = %d", type);
  219. if (Ogr_geom_type == wkbPolygon || Ogr_geom_type == wkbPolygon25D) {
  220. int iring, npoints;
  221. /* add rings (first is exterior ring) */
  222. for (iring = 0; iring < nparts; iring++) {
  223. OGRGeometryH Ogr_ring;
  224. points = p_points[iring];
  225. npoints = points->n_points - 1;
  226. Ogr_ring = OGR_G_CreateGeometry(wkbLinearRing);
  227. if (points->x[0] != points->x[npoints] ||
  228. points->y[0] != points->y[npoints] ||
  229. points->z[0] != points->z[npoints]) {
  230. G_warning(_("Boundary is not closed. Feature skipped."));
  231. return -1;
  232. }
  233. /* add points */
  234. for (i = 0; i < npoints; i++) {
  235. OGR_G_AddPoint(Ogr_ring, points->x[i], points->y[i],
  236. points->z[i]);
  237. }
  238. G_debug(4, " ring(%d): n_points = %d", iring, npoints);
  239. OGR_G_AddGeometry(Ogr_geometry, Ogr_ring);
  240. }
  241. }
  242. else {
  243. for (i = 0; i < points->n_points; i++) {
  244. OGR_G_AddPoint(Ogr_geometry, points->x[i], points->y[i],
  245. points->z[i]);
  246. }
  247. G_debug(4, " n_points = %d", points->n_points);
  248. }
  249. /* create feature & set geometry */
  250. Ogr_feature = OGR_F_Create(Ogr_featuredefn);
  251. OGR_F_SetGeometry(Ogr_feature, Ogr_geometry);
  252. /* write attributes */
  253. if (cat > -1 && ogr_info->dbdriver) {
  254. if (0 > write_attributes(ogr_info->dbdriver,
  255. cat, Fi, ogr_info->layer, Ogr_feature))
  256. G_warning(_("Unable to writes feature attributes"));
  257. G_free(Fi);
  258. }
  259. /* write feature into layer */
  260. ret = OGR_L_CreateFeature(ogr_info->layer, Ogr_feature);
  261. /* update offset array */
  262. if (offset_info->array_num >= offset_info->array_alloc) {
  263. offset_info->array_alloc += 1000;
  264. offset_info->array = (int *) G_realloc(offset_info->array,
  265. offset_info->array_alloc *
  266. sizeof(int));
  267. }
  268. offset = offset_info->array_num;
  269. offset_info->array[offset_info->array_num++] = (int) OGR_F_GetFID(Ogr_feature);
  270. if (Ogr_geom_type == wkbPolygon || Ogr_geom_type == wkbPolygon25D) {
  271. /* register exterior ring in offset array */
  272. offset_info->array[offset_info->array_num++] = 0;
  273. }
  274. /* destroy */
  275. OGR_G_DestroyGeometry(Ogr_geometry);
  276. OGR_F_Destroy(Ogr_feature);
  277. if (ret != OGRERR_NONE)
  278. return -1;
  279. G_debug(3, "write_feature(): -> offset = %lu offset_num = %d cat = %d",
  280. (unsigned long) offset, offset_info->array_num, cat);
  281. return offset;
  282. }
  283. /*!
  284. \brief Writes attributes
  285. \param driver pointer to dbDriver
  286. \param Fi pointer to field_info struct
  287. \param[in,out] Ogr_layer OGR layer
  288. \param[in,out] Ogr_feature OGR feature to modify
  289. \return 1 on success
  290. \return 0 no attributes
  291. \return -1 on error
  292. */
  293. int write_attributes(dbDriver *driver, int cat, const struct field_info *Fi,
  294. OGRLayerH Ogr_layer, OGRFeatureH Ogr_feature)
  295. {
  296. int j, ogrfieldnum;
  297. char buf[2000];
  298. int ncol, sqltype, ctype, ogrtype, more;
  299. const char *fidcol, *colname;
  300. dbTable *table;
  301. dbString dbstring;
  302. dbColumn *column;
  303. dbCursor cursor;
  304. dbValue *value;
  305. OGRFieldDefnH hFieldDefn;
  306. G_debug(3, "write_attributes(): cat = %d", cat);
  307. if (cat < 0) {
  308. G_warning(_("Feature without category of layer %d"), Fi->number);
  309. return 0;
  310. }
  311. db_init_string(&dbstring);
  312. /* read & set attributes */
  313. sprintf(buf, "SELECT * FROM %s WHERE %s = %d", Fi->table, Fi->key,
  314. cat);
  315. G_debug(4, "SQL: %s", buf);
  316. db_set_string(&dbstring, buf);
  317. /* select data */
  318. if (db_open_select_cursor(driver, &dbstring, &cursor, DB_SEQUENTIAL) != DB_OK) {
  319. G_warning(_("Unable to select attributes for category %d"),
  320. cat);
  321. return -1;
  322. }
  323. if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) {
  324. G_warning(_("Unable to fetch data from table <%s>"),
  325. Fi->table);
  326. return -1;
  327. }
  328. if (!more) {
  329. G_warning(_("No database record for category %d, "
  330. "no attributes will be written"),
  331. cat);
  332. return -1;
  333. }
  334. fidcol = OGR_L_GetFIDColumn(Ogr_layer);
  335. table = db_get_cursor_table(&cursor);
  336. ncol = db_get_table_number_of_columns(table);
  337. for (j = 0; j < ncol; j++) {
  338. column = db_get_table_column(table, j);
  339. colname = db_get_column_name(column);
  340. if (fidcol && *fidcol && strcmp(colname, fidcol) == 0) {
  341. /* skip fid column */
  342. continue;
  343. }
  344. value = db_get_column_value(column);
  345. /* for debug only */
  346. db_convert_column_value_to_string(column, &dbstring);
  347. G_debug(2, "col %d : val = %s", j,
  348. db_get_string(&dbstring));
  349. sqltype = db_get_column_sqltype(column);
  350. ctype = db_sqltype_to_Ctype(sqltype);
  351. ogrtype = sqltype_to_ogrtype(sqltype);
  352. G_debug(2, " colctype = %d", ctype);
  353. ogrfieldnum = OGR_F_GetFieldIndex(Ogr_feature, colname);
  354. if (ogrfieldnum < 0) {
  355. /* create field if not exists */
  356. hFieldDefn = OGR_Fld_Create(colname, ogrtype);
  357. if (OGR_L_CreateField(Ogr_layer, hFieldDefn, TRUE) != OGRERR_NONE)
  358. G_warning(_("Unable to create field <%s>"), colname);
  359. ogrfieldnum = OGR_F_GetFieldIndex(Ogr_feature, colname);
  360. }
  361. /* Reset */
  362. OGR_F_UnsetField(Ogr_feature, ogrfieldnum);
  363. /* prevent writing NULL values */
  364. if (!db_test_value_isnull(value)) {
  365. switch (ctype) {
  366. case DB_C_TYPE_INT:
  367. OGR_F_SetFieldInteger(Ogr_feature, ogrfieldnum,
  368. db_get_value_int(value));
  369. break;
  370. case DB_C_TYPE_DOUBLE:
  371. OGR_F_SetFieldDouble(Ogr_feature, ogrfieldnum,
  372. db_get_value_double(value));
  373. break;
  374. case DB_C_TYPE_STRING:
  375. OGR_F_SetFieldString(Ogr_feature, ogrfieldnum,
  376. db_get_value_string(value));
  377. break;
  378. case DB_C_TYPE_DATETIME:
  379. db_convert_column_value_to_string(column,
  380. &dbstring);
  381. OGR_F_SetFieldString(Ogr_feature, ogrfieldnum,
  382. db_get_string(&dbstring));
  383. break;
  384. default:
  385. G_warning(_("Unsupported column type %d"), ctype);
  386. break;
  387. }
  388. }
  389. }
  390. db_close_cursor (&cursor);
  391. db_free_string(&dbstring);
  392. return 1;
  393. }
  394. int sqltype_to_ogrtype(int sqltype)
  395. {
  396. int ctype, ogrtype;
  397. ctype = db_sqltype_to_Ctype(sqltype);
  398. switch(ctype) {
  399. case DB_C_TYPE_INT:
  400. ogrtype = OFTInteger;
  401. break;
  402. case DB_C_TYPE_DOUBLE:
  403. ogrtype = OFTReal;
  404. break;
  405. case DB_C_TYPE_STRING:
  406. ogrtype = OFTString;
  407. break;
  408. case DB_C_TYPE_DATETIME:
  409. ogrtype = OFTString;
  410. break;
  411. default:
  412. ogrtype = OFTString;
  413. break;
  414. }
  415. return ogrtype;
  416. }
  417. #endif /* HAVE_OGR */