write_ogr.c 12 KB

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