write_ogr.c 11 KB

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