write_ogr.c 12 KB

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