write_ogr.c 12 KB

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