write_ogr.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  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. Inspired by v.out.ogr's code.
  6. (C) 2009-2010 by the GRASS Development Team
  7. This program is free software under the GNU General Public License
  8. (>=v2). Read the file COPYING that comes with GRASS for details.
  9. \author Martin Landa <landa.martin gmail.com>
  10. */
  11. #include <grass/config.h>
  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 int write_attributes(int, const struct field_info *,
  18. OGRLayerH, OGRFeatureH);
  19. /* TODO:
  20. * OGR version of V2__delete_area_cats_from_cidx_nat()
  21. * function to delete corresponding entry in fidx
  22. * OGR version of V2__add_area_cats_to_cidx_nat
  23. * OGR version of V2__add_line_to_topo_nat
  24. */
  25. void V2__add_line_to_topo_ogr(struct Map_info *Map, int line,
  26. const struct line_pnts *points, const struct line_cats *cats)
  27. {
  28. /* recycle code from build_ogr */
  29. G_warning("feature not yet implemented, coming soon...");
  30. return;
  31. }
  32. /*!
  33. \brief Writes feature on level 1 (OGR interface)
  34. \param Map pointer to Map_info structure
  35. \param type feature type
  36. \param points pointer to line_pnts structure (feature geometry)
  37. \param cats pointer to line_cats structure (feature categories)
  38. \return feature offset into file
  39. \return -1 on error
  40. */
  41. off_t V1_write_line_ogr(struct Map_info *Map,
  42. int type, const struct line_pnts *points, const struct line_cats *cats)
  43. {
  44. int i, cat, ret;
  45. struct field_info *Fi;
  46. OGRGeometryH Ogr_geometry;
  47. OGRFeatureH Ogr_feature;
  48. OGRFeatureDefnH Ogr_featuredefn;
  49. OGRwkbGeometryType Ogr_geom_type;
  50. if (!Map->fInfo.ogr.layer) {
  51. if (V2_open_new_ogr(Map, type) < 0)
  52. return -1;
  53. }
  54. Ogr_featuredefn = OGR_L_GetLayerDefn(Map->fInfo.ogr.layer);
  55. Ogr_geom_type = OGR_FD_GetGeomType(Ogr_featuredefn);
  56. /* determine matching OGR feature geometry type */
  57. /* NOTE: centroids are not supported in OGR,
  58. * pseudotopo holds virtual centroids */
  59. /* NOTE: boundaries are not supported in OGR,
  60. * pseudotopo treats polygons as boundaries */
  61. if (type & (GV_POINT | GV_KERNEL)) {
  62. if (Ogr_geom_type != wkbPoint &&
  63. Ogr_geom_type != wkbPoint25D) {
  64. G_warning(_("Feature is not a point. Skipping."));
  65. return -1;
  66. }
  67. Ogr_geometry = OGR_G_CreateGeometry(wkbPoint);
  68. }
  69. else if (type & GV_LINE) {
  70. if (Ogr_geom_type != wkbLineString &&
  71. Ogr_geom_type != wkbLineString25D) {
  72. G_warning(_("Feature is not a line Skipping."));
  73. return -1;
  74. }
  75. Ogr_geometry = OGR_G_CreateGeometry(wkbLineString);
  76. }
  77. else if (type & GV_FACE) {
  78. if (Ogr_geom_type != wkbPolygon25D) {
  79. G_warning(_("Feature is not a face. Skipping."));
  80. return -1;
  81. }
  82. Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon25D);
  83. }
  84. else {
  85. G_warning(_("Unsupported feature type (%d)"), type);
  86. return -1;
  87. }
  88. G_debug(3, "V1_write_line_ogr(): type = %d", type);
  89. for (i = 0; i < points->n_points; i++) {
  90. OGR_G_AddPoint(Ogr_geometry, points->x[i], points->y[i],
  91. points->z[i]);
  92. }
  93. G_debug(4, " n_points = %d", points->n_points);
  94. /* create feature & set geometry */
  95. Ogr_feature = OGR_F_Create(Ogr_featuredefn);
  96. OGR_F_SetGeometry(Ogr_feature, Ogr_geometry);
  97. /* write attributes */
  98. Fi = Vect_get_field(Map, cats->field[0]);
  99. if (Fi && cats->n_cats > 0) {
  100. cat = cats->cat[0];
  101. if (cats->n_cats > 1) {
  102. G_warning(_("Feature has more categories, using "
  103. "category %d (from layer %d)"),
  104. cat, cats->field[0]);
  105. }
  106. write_attributes(cat, Fi, Map->fInfo.ogr.layer, Ogr_feature);
  107. }
  108. /* write feature into layer */
  109. ret = OGR_L_CreateFeature(Map->fInfo.ogr.layer, Ogr_feature);
  110. /* destroy */
  111. OGR_G_DestroyGeometry(Ogr_geometry);
  112. OGR_F_Destroy(Ogr_feature);
  113. if (ret != OGRERR_NONE)
  114. return -1;
  115. return Map->fInfo.ogr.offset_num++;
  116. }
  117. /*!
  118. \brief Writes feature on level 2
  119. \param Map pointer to Map_info structure
  120. \param type feature type
  121. \param points pointer to line_pnts structure (feature geometry)
  122. \param cats pointer to line_cats structure (feature categories)
  123. \return feature offset into file
  124. \return -1 on error
  125. */
  126. off_t V2_write_line_ogr(struct Map_info *Map, int type,
  127. const struct line_pnts *points, const struct line_cats *cats)
  128. {
  129. int line;
  130. off_t offset;
  131. struct Plus_head *plus;
  132. struct bound_box box;
  133. line = 0;
  134. G_debug(3, "V2_write_line_ogr()");
  135. offset = V1_write_line_ogr(Map, type, points, cats);
  136. if (offset < 0)
  137. return -1;
  138. /* Update topology */
  139. plus = &(Map->plus);
  140. /* Add line */
  141. if (plus->built >= GV_BUILD_BASE) {
  142. line = dig_add_line(plus, type, points, offset);
  143. G_debug(3, " line added to topo with id = %d", line);
  144. dig_line_box(points, &box);
  145. dig_line_set_box(plus, line, &box);
  146. if (line == 1)
  147. Vect_box_copy(&(plus->box), &box);
  148. else
  149. Vect_box_extend(&(plus->box), &box);
  150. V2__add_line_to_topo_ogr(Map, line, points, cats);
  151. }
  152. G_debug(3, "updated lines : %d , updated nodes : %d", plus->n_uplines,
  153. plus->n_upnodes);
  154. /* returns int line, but is defined as off_t for compatibility with
  155. * Write_line_array in write.c */
  156. return line;
  157. }
  158. /*!
  159. \brief Rewrites feature at the given offset (level 1)
  160. \param Map pointer to Map_info structure
  161. \param offset feature offset
  162. \param type feature type
  163. \param points feature geometry
  164. \param cats feature categories
  165. \return feature offset (rewriten feature)
  166. \return -1 on error
  167. */
  168. off_t V1_rewrite_line_ogr(struct Map_info *Map,
  169. int line,
  170. int type,
  171. off_t offset,
  172. const struct line_pnts *points, const struct line_cats *cats)
  173. {
  174. if (type != V1_read_line_ogr(Map, NULL, NULL, offset)) {
  175. G_warning(_("Unable to rewrite feature (incompatible feature types)"));
  176. return -1;
  177. }
  178. /* delete old */
  179. V1_delete_line_ogr(Map, offset);
  180. return V1_write_line_ogr(Map, type, points, cats);
  181. }
  182. /*!
  183. \brief Rewrites feature to 'coor' file (topology level) - internal use only
  184. \param Map pointer to Map_info structure
  185. \param type feature type
  186. \param line feature id
  187. \param points feature geometry
  188. \param cats feature categories
  189. \return offset where line was rewritten
  190. \return -1 on error
  191. */
  192. off_t V2_rewrite_line_ogr(struct Map_info *Map, int line, int type, off_t offset,
  193. const struct line_pnts *points, const struct line_cats *cats)
  194. {
  195. V2_delete_line_ogr(Map, line);
  196. return (V2_write_line_ogr(Map, type, points, cats));
  197. }
  198. /*!
  199. \brief Deletes feature at the given offset (level 1)
  200. \param Map pointer Map_info structure
  201. \param offset feature offset
  202. \return 0 on success
  203. \return -1 on error
  204. */
  205. int V1_delete_line_ogr(struct Map_info *Map, off_t offset)
  206. {
  207. G_debug(3, "V1_delete_line_ogr(), offset = %lu", (unsigned long) offset);
  208. if (!Map->fInfo.ogr.layer) {
  209. G_warning(_("OGR layer not defined"));
  210. return -1;
  211. }
  212. if (offset >= Map->fInfo.ogr.offset_num)
  213. return -1;
  214. if (OGR_L_DeleteFeature(Map->fInfo.ogr.layer, Map->fInfo.ogr.offset[offset]) != OGRERR_NONE)
  215. return -1;
  216. return 0;
  217. }
  218. /*!
  219. \brief Deletes feature (topology level) -- internal use only
  220. \param pointer to Map_info structure
  221. \param line feature id
  222. \return 0 on success
  223. \return -1 on error
  224. */
  225. int V2_delete_line_ogr(struct Map_info *Map, off_t line)
  226. {
  227. int ret, i, type, first;
  228. struct P_line *Line;
  229. struct Plus_head *plus;
  230. static struct line_cats *Cats = NULL;
  231. G_debug(3, "V2_delete_line_nat(), line = %d", (int) line);
  232. type = first = 0;
  233. Line = NULL;
  234. plus = &(Map->plus);
  235. if (plus->built >= GV_BUILD_BASE) {
  236. Line = Map->plus.Line[line];
  237. if (Line == NULL)
  238. G_fatal_error(_("Attempt to delete dead feature"));
  239. type = Line->type;
  240. }
  241. if (!Cats) {
  242. Cats = Vect_new_cats_struct();
  243. }
  244. /* Update category index */
  245. if (plus->update_cidx) {
  246. type = V2_read_line_ogr(Map, NULL, Cats, line);
  247. for (i = 0; i < Cats->n_cats; i++) {
  248. dig_cidx_del_cat(plus, Cats->field[i], Cats->cat[i], line, type);
  249. }
  250. }
  251. /* Update fidx */
  252. /* delete the line from coor */
  253. ret = V1_delete_line_ogr(Map, Line->offset);
  254. if (ret == -1) {
  255. return ret;
  256. }
  257. /* Update topology */
  258. if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
  259. /* TODO */
  260. /* remove centroid together with boundary (is really an OGR polygon) */
  261. }
  262. /* Delete reference from area */
  263. if (plus->built >= GV_BUILD_CENTROIDS && type == GV_CENTROID) {
  264. /* for OGR mapsets, virtual centroid will be removed when polygon is removed */
  265. }
  266. /* delete the line from topo */
  267. dig_del_line(plus, line);
  268. /* Rebuild areas/isles and attach centroids and isles */
  269. if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
  270. /* maybe not needed VERIFY */
  271. }
  272. return ret;
  273. }
  274. int write_attributes(int cat, const struct field_info *Fi,
  275. OGRLayerH Ogr_layer, OGRFeatureH Ogr_feature)
  276. {
  277. int j, ogrfieldnum;
  278. char buf[2000];
  279. int ncol, colsqltype, colctype, more;
  280. const char *fidcol;
  281. dbDriver *Driver;
  282. dbTable *Table;
  283. dbString dbstring;
  284. dbColumn *Column;
  285. dbCursor cursor;
  286. dbValue *Value;
  287. G_debug(3, "write_attributes(): cat = %d", cat);
  288. if (cat < 0) {
  289. G_warning ("Feature without category of layer %d", Fi->number);
  290. return 0;
  291. }
  292. db_init_string(&dbstring);
  293. /* read & set attributes */
  294. sprintf(buf, "SELECT * FROM %s WHERE %s = %d", Fi->table, Fi->key,
  295. cat);
  296. G_debug(4, "SQL: %s", buf);
  297. db_set_string(&dbstring, buf);
  298. /* open driver & select data */
  299. Driver = db_start_driver_open_database(Fi->driver, Fi->database);
  300. if (!Driver)
  301. G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
  302. Fi->database, Fi->driver);
  303. if (db_open_select_cursor(Driver, &dbstring, &cursor, DB_SEQUENTIAL) != DB_OK) {
  304. G_fatal_error(_("Unable to select attributes for category %d"),
  305. cat);
  306. }
  307. if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) {
  308. G_fatal_error(_("Unable to fetch data from table <%s>"),
  309. Fi->table);
  310. }
  311. if (!more) {
  312. G_warning (_("No database record for category %d - export of 'cat' disabled"),
  313. cat);
  314. return -1;
  315. }
  316. fidcol = OGR_L_GetFIDColumn(Ogr_layer);
  317. Table = db_get_cursor_table(&cursor);
  318. ncol = db_get_table_number_of_columns(Table);
  319. for (j = 0; j < ncol; j++) {
  320. Column = db_get_table_column(Table, j);
  321. if (fidcol && strcmp(db_get_column_name(Column), fidcol) == 0) {
  322. /* skip fid column */
  323. continue;
  324. }
  325. Value = db_get_column_value(Column);
  326. db_convert_column_value_to_string(Column, &dbstring); /* for debug only */
  327. G_debug(2, "col %d : val = %s", j,
  328. db_get_string(&dbstring));
  329. colsqltype = db_get_column_sqltype(Column);
  330. colctype = db_sqltype_to_Ctype(colsqltype);
  331. G_debug(2, " colctype = %d", colctype);
  332. ogrfieldnum = OGR_F_GetFieldIndex(Ogr_feature,
  333. db_get_column_name(Column));
  334. if (ogrfieldnum < 0) {
  335. G_warning(_("Uknown column <%s>"),
  336. db_get_column_name(Column));
  337. continue;
  338. }
  339. /* Reset */
  340. OGR_F_UnsetField(Ogr_feature, ogrfieldnum);
  341. /* prevent writing NULL values */
  342. if (!db_test_value_isnull(Value)) {
  343. switch (colctype) {
  344. case DB_C_TYPE_INT:
  345. OGR_F_SetFieldInteger(Ogr_feature, ogrfieldnum,
  346. db_get_value_int(Value));
  347. break;
  348. case DB_C_TYPE_DOUBLE:
  349. OGR_F_SetFieldDouble(Ogr_feature, ogrfieldnum,
  350. db_get_value_double(Value));
  351. break;
  352. case DB_C_TYPE_STRING:
  353. OGR_F_SetFieldString(Ogr_feature, ogrfieldnum,
  354. db_get_value_string(Value));
  355. break;
  356. case DB_C_TYPE_DATETIME:
  357. db_convert_column_value_to_string(Column,
  358. &dbstring);
  359. OGR_F_SetFieldString(Ogr_feature, ogrfieldnum,
  360. db_get_string(&dbstring));
  361. break;
  362. }
  363. }
  364. }
  365. db_close_cursor (&cursor);
  366. db_close_database(Driver);
  367. db_shutdown_driver(Driver);
  368. db_free_string(&dbstring);
  369. return 1;
  370. }
  371. #endif /* HAVE_OGR */