write_ogr.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  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. \todo OGR version of V2__delete_area_cats_from_cidx_nat()
  7. \todo function to delete corresponding entry in fidx
  8. \todo OGR version of V2__add_area_cats_to_cidx_nat
  9. \todo OGR version of V2__add_line_to_topo_nat
  10. (C) 2009-2011 by the GRASS Development Team
  11. This program is free software under the GNU General Public License
  12. (>=v2). Read the file COPYING that comes with GRASS for details.
  13. \author Martin Landa <landa.martin gmail.com>
  14. */
  15. #include <grass/vector.h>
  16. #include <grass/dbmi.h>
  17. #include <grass/glocale.h>
  18. #ifdef HAVE_OGR
  19. #include <ogr_api.h>
  20. static int sqltype_to_ogrtype(int);
  21. static int write_attributes(dbDriver *, int, const struct field_info *,
  22. OGRLayerH, OGRFeatureH);
  23. static void V2__add_line_to_topo_ogr(struct Map_info *Map, int line,
  24. const struct line_pnts *points,
  25. 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, int type,
  41. const struct line_pnts *points,
  42. const struct line_cats *cats)
  43. {
  44. int i, cat, ret;
  45. struct field_info *Fi;
  46. struct Format_info_ogr *fInfo;
  47. OGRGeometryH Ogr_geometry;
  48. OGRFeatureH Ogr_feature;
  49. OGRFeatureDefnH Ogr_featuredefn;
  50. OGRwkbGeometryType Ogr_geom_type;
  51. if (!Map->fInfo.ogr.layer) {
  52. if (V2_open_new_ogr(Map, type) < 0)
  53. return -1;
  54. }
  55. cat = -1; /* no attributes to be written */
  56. if (cats->n_cats > 0) {
  57. /* check for attributes */
  58. Fi = Vect_get_dblink(Map, 0);
  59. if (Fi) {
  60. if (!Vect_cat_get(cats, Fi->number, &cat))
  61. G_warning(_("No category defined for layer %d"), Fi->number);
  62. if (cats->n_cats > 1) {
  63. G_warning(_("Feature has more categories, using "
  64. "category %d (from layer %d)"),
  65. cat, cats->field[0]);
  66. }
  67. }
  68. }
  69. fInfo = &(Map->fInfo.ogr);
  70. Ogr_featuredefn = OGR_L_GetLayerDefn(fInfo->layer);
  71. Ogr_geom_type = OGR_FD_GetGeomType(Ogr_featuredefn);
  72. /* determine matching OGR feature geometry type */
  73. /* NOTE: centroids are not supported in OGR,
  74. * pseudotopo holds virtual centroids */
  75. /* NOTE: boundaries are not supported in OGR,
  76. * pseudotopo treats polygons as boundaries */
  77. if (type & (GV_POINT | GV_KERNEL)) {
  78. if (Ogr_geom_type != wkbPoint &&
  79. Ogr_geom_type != wkbPoint25D) {
  80. G_warning(_("Feature is not a point. Skipping."));
  81. return -1;
  82. }
  83. Ogr_geometry = OGR_G_CreateGeometry(wkbPoint);
  84. }
  85. else if (type & GV_LINE) {
  86. if (Ogr_geom_type != wkbLineString &&
  87. Ogr_geom_type != wkbLineString25D) {
  88. G_warning(_("Feature is not a line. Skipping."));
  89. return -1;
  90. }
  91. Ogr_geometry = OGR_G_CreateGeometry(wkbLineString);
  92. }
  93. else if (type & GV_BOUNDARY) {
  94. if (Ogr_geom_type != wkbPolygon) {
  95. G_warning(_("Feature is not a polygon. Skipping."));
  96. return -1;
  97. }
  98. Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon);
  99. }
  100. else if (type & GV_FACE) {
  101. if (Ogr_geom_type != wkbPolygon25D) {
  102. G_warning(_("Feature is not a face. Skipping."));
  103. return -1;
  104. }
  105. Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon25D);
  106. }
  107. else {
  108. G_warning(_("Unsupported feature type (%d)"), type);
  109. return -1;
  110. }
  111. G_debug(3, "V1_write_line_ogr(): type = %d", type);
  112. if (Ogr_geom_type == wkbPolygon || Ogr_geom_type == wkbPolygon25D) {
  113. /* create exterior ring */
  114. OGRGeometryH Ogr_ring;
  115. int npoints;
  116. npoints = points->n_points - 1;
  117. Ogr_ring = OGR_G_CreateGeometry(wkbLinearRing);
  118. if (points->x[0] != points->x[npoints] ||
  119. points->y[0] != points->y[npoints] ||
  120. points->z[0] != points->z[npoints]) {
  121. G_warning(_("Boundary is not closed. Skipping."));
  122. return -1;
  123. }
  124. /* add points */
  125. for (i = 0; i < points->n_points; i++) {
  126. OGR_G_AddPoint(Ogr_ring, points->x[i], points->y[i],
  127. points->z[i]);
  128. }
  129. OGR_G_AddGeometry(Ogr_geometry, Ogr_ring);
  130. }
  131. else {
  132. for (i = 0; i < points->n_points; i++) {
  133. OGR_G_AddPoint(Ogr_geometry, points->x[i], points->y[i],
  134. points->z[i]);
  135. }
  136. }
  137. G_debug(4, " n_points = %d", points->n_points);
  138. /* create feature & set geometry */
  139. Ogr_feature = OGR_F_Create(Ogr_featuredefn);
  140. OGR_F_SetGeometry(Ogr_feature, Ogr_geometry);
  141. /* write attributes */
  142. if (cat > -1 && fInfo->dbdriver) {
  143. write_attributes(fInfo->dbdriver,
  144. cat, Fi, fInfo->layer, Ogr_feature);
  145. G_free(Fi);
  146. }
  147. /* write feature into layer */
  148. ret = OGR_L_CreateFeature(fInfo->layer, Ogr_feature);
  149. /* update offset array */
  150. if (fInfo->offset_num >= fInfo->offset_alloc) {
  151. fInfo->offset_alloc += 1000;
  152. fInfo->offset = (int *) G_realloc(fInfo->offset,
  153. fInfo->offset_alloc *
  154. sizeof(int));
  155. }
  156. /* how to deal with OGRNullFID ? */
  157. fInfo->offset[fInfo->offset_num] = (int)OGR_F_GetFID(Ogr_feature);
  158. /* destroy */
  159. OGR_G_DestroyGeometry(Ogr_geometry);
  160. OGR_F_Destroy(Ogr_feature);
  161. if (ret != OGRERR_NONE)
  162. return -1;
  163. return fInfo->offset_num++;
  164. }
  165. /*!
  166. \brief Writes feature on level 2
  167. \param Map pointer to Map_info structure
  168. \param type feature type
  169. \param points pointer to line_pnts structure (feature geometry)
  170. \param cats pointer to line_cats structure (feature categories)
  171. \return feature offset into file
  172. \return -1 on error
  173. */
  174. off_t V2_write_line_ogr(struct Map_info *Map, int type,
  175. const struct line_pnts *points, const struct line_cats *cats)
  176. {
  177. int line;
  178. off_t offset;
  179. struct Plus_head *plus;
  180. struct bound_box box;
  181. line = 0;
  182. G_debug(3, "V2_write_line_ogr()");
  183. offset = V1_write_line_ogr(Map, type, points, cats);
  184. if (offset < 0)
  185. return -1;
  186. /* Update topology */
  187. plus = &(Map->plus);
  188. /* Add line */
  189. if (plus->built >= GV_BUILD_BASE) {
  190. dig_line_box(points, &box);
  191. line = dig_add_line(plus, type, points, &box, offset);
  192. G_debug(3, " line added to topo with id = %d", line);
  193. if (line == 1)
  194. Vect_box_copy(&(plus->box), &box);
  195. else
  196. Vect_box_extend(&(plus->box), &box);
  197. V2__add_line_to_topo_ogr(Map, line, points, cats);
  198. }
  199. G_debug(3, "updated lines : %d , updated nodes : %d", plus->n_uplines,
  200. plus->n_upnodes);
  201. /* returns int line, but is defined as off_t for compatibility with
  202. * Write_line_array in write.c */
  203. return line;
  204. }
  205. /*!
  206. \brief Rewrites feature at the given offset (level 1)
  207. \param Map pointer to Map_info structure
  208. \param offset feature offset
  209. \param type feature type
  210. \param points feature geometry
  211. \param cats feature categories
  212. \return feature offset (rewriten feature)
  213. \return -1 on error
  214. */
  215. off_t V1_rewrite_line_ogr(struct Map_info *Map,
  216. int line,
  217. int type,
  218. off_t offset,
  219. const struct line_pnts *points, const struct line_cats *cats)
  220. {
  221. if (type != V1_read_line_ogr(Map, NULL, NULL, offset)) {
  222. G_warning(_("Unable to rewrite feature (incompatible feature types)"));
  223. return -1;
  224. }
  225. /* delete old */
  226. V1_delete_line_ogr(Map, offset);
  227. return V1_write_line_ogr(Map, type, points, cats);
  228. }
  229. /*!
  230. \brief Rewrites feature to 'coor' file (topology level) - internal use only
  231. \param Map pointer to Map_info structure
  232. \param line feature id
  233. \param type feature type
  234. \param offset unused
  235. \param points feature geometry
  236. \param cats feature categories
  237. \return offset where line was rewritten
  238. \return -1 on error
  239. */
  240. off_t V2_rewrite_line_ogr(struct Map_info *Map, int line, int type, off_t offset,
  241. const struct line_pnts *points, const struct line_cats *cats)
  242. {
  243. if (type != V2_read_line_ogr(Map, NULL, NULL, line)) {
  244. G_warning(_("Unable to rewrite feature (incompatible feature types)"));
  245. return -1;
  246. }
  247. V2_delete_line_ogr(Map, line);
  248. return V2_write_line_ogr(Map, type, points, cats);
  249. }
  250. /*!
  251. \brief Deletes feature at the given offset (level 1)
  252. \param Map pointer Map_info structure
  253. \param offset feature offset
  254. \return 0 on success
  255. \return -1 on error
  256. */
  257. int V1_delete_line_ogr(struct Map_info *Map, off_t offset)
  258. {
  259. G_debug(3, "V1_delete_line_ogr(), offset = %lu", (unsigned long) offset);
  260. if (!Map->fInfo.ogr.layer) {
  261. G_warning(_("OGR layer not defined"));
  262. return -1;
  263. }
  264. if (offset >= Map->fInfo.ogr.offset_num)
  265. return -1;
  266. if (OGR_L_DeleteFeature(Map->fInfo.ogr.layer, Map->fInfo.ogr.offset[offset]) != OGRERR_NONE)
  267. return -1;
  268. return 0;
  269. }
  270. /*!
  271. \brief Deletes feature (topology level) -- internal use only
  272. \param pointer to Map_info structure
  273. \param line feature id
  274. \return 0 on success
  275. \return -1 on error
  276. */
  277. int V2_delete_line_ogr(struct Map_info *Map, off_t line)
  278. {
  279. int ret, i, type, first;
  280. struct P_line *Line;
  281. struct Plus_head *plus;
  282. static struct line_cats *Cats = NULL;
  283. static struct line_pnts *Points = NULL;
  284. G_debug(3, "V2_delete_line_ogr(), line = %d", (int) line);
  285. type = first = 0;
  286. Line = NULL;
  287. plus = &(Map->plus);
  288. if (plus->built >= GV_BUILD_BASE) {
  289. Line = Map->plus.Line[line];
  290. if (Line == NULL)
  291. G_fatal_error(_("Attempt to delete dead feature"));
  292. type = Line->type;
  293. }
  294. if (!Cats) {
  295. Cats = Vect_new_cats_struct();
  296. }
  297. if (!Points) {
  298. Points = Vect_new_line_struct();
  299. }
  300. type = V2_read_line_ogr(Map, Points, Cats, line);
  301. /* Update category index */
  302. if (plus->update_cidx) {
  303. for (i = 0; i < Cats->n_cats; i++) {
  304. dig_cidx_del_cat(plus, Cats->field[i], Cats->cat[i], line, type);
  305. }
  306. }
  307. /* Update fidx */
  308. /* delete the line from coor */
  309. ret = V1_delete_line_ogr(Map, Line->offset);
  310. if (ret == -1) {
  311. return ret;
  312. }
  313. /* Update topology */
  314. if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
  315. /* TODO */
  316. /* remove centroid together with boundary (is really an OGR polygon) */
  317. }
  318. /* Delete reference from area */
  319. if (plus->built >= GV_BUILD_CENTROIDS && type == GV_CENTROID) {
  320. /* for OGR mapsets, virtual centroid will be removed when polygon is removed */
  321. }
  322. /* delete the line from topo */
  323. dig_del_line(plus, line, Points->x[0], Points->y[0], Points->z[0]);
  324. /* Rebuild areas/isles and attach centroids and isles */
  325. if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
  326. /* maybe not needed VERIFY */
  327. }
  328. return ret;
  329. }
  330. int write_attributes(dbDriver *driver, int cat, const struct field_info *Fi,
  331. OGRLayerH Ogr_layer, OGRFeatureH Ogr_feature)
  332. {
  333. int j, ogrfieldnum;
  334. char buf[2000];
  335. int ncol, sqltype, ctype, ogrtype, more;
  336. const char *fidcol, *colname;
  337. dbTable *table;
  338. dbString dbstring;
  339. dbColumn *column;
  340. dbCursor cursor;
  341. dbValue *value;
  342. OGRFieldDefnH hFieldDefn;
  343. G_debug(3, "write_attributes(): cat = %d", cat);
  344. if (cat < 0) {
  345. G_warning(_("Feature without category of layer %d"), Fi->number);
  346. return 0;
  347. }
  348. db_init_string(&dbstring);
  349. /* read & set attributes */
  350. sprintf(buf, "SELECT * FROM %s WHERE %s = %d", Fi->table, Fi->key,
  351. cat);
  352. G_debug(4, "SQL: %s", buf);
  353. db_set_string(&dbstring, buf);
  354. /* select data */
  355. if (db_open_select_cursor(driver, &dbstring, &cursor, DB_SEQUENTIAL) != DB_OK) {
  356. G_fatal_error(_("Unable to select attributes for category %d"),
  357. cat);
  358. }
  359. if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) {
  360. G_fatal_error(_("Unable to fetch data from table <%s>"),
  361. Fi->table);
  362. }
  363. if (!more) {
  364. G_warning(_("No database record for category %d, "
  365. "no attributes will be written"),
  366. cat);
  367. return -1;
  368. }
  369. fidcol = OGR_L_GetFIDColumn(Ogr_layer);
  370. table = db_get_cursor_table(&cursor);
  371. ncol = db_get_table_number_of_columns(table);
  372. for (j = 0; j < ncol; j++) {
  373. column = db_get_table_column(table, j);
  374. colname = db_get_column_name(column);
  375. if (fidcol && *fidcol && strcmp(colname, fidcol) == 0) {
  376. /* skip fid column */
  377. continue;
  378. }
  379. value = db_get_column_value(column);
  380. /* for debug only */
  381. db_convert_column_value_to_string(column, &dbstring);
  382. G_debug(2, "col %d : val = %s", j,
  383. db_get_string(&dbstring));
  384. sqltype = db_get_column_sqltype(column);
  385. ctype = db_sqltype_to_Ctype(sqltype);
  386. ogrtype = sqltype_to_ogrtype(sqltype);
  387. G_debug(2, " colctype = %d", ctype);
  388. ogrfieldnum = OGR_F_GetFieldIndex(Ogr_feature, colname);
  389. if (ogrfieldnum < 0) {
  390. /* create field if not exists */
  391. hFieldDefn = OGR_Fld_Create(colname, ogrtype);
  392. if (OGR_L_CreateField(Ogr_layer, hFieldDefn, TRUE) != OGRERR_NONE)
  393. G_warning(_("Unable to create field <%s>"), colname);
  394. ogrfieldnum = OGR_F_GetFieldIndex(Ogr_feature, colname);
  395. }
  396. /* Reset */
  397. OGR_F_UnsetField(Ogr_feature, ogrfieldnum);
  398. /* prevent writing NULL values */
  399. if (!db_test_value_isnull(value)) {
  400. switch (ctype) {
  401. case DB_C_TYPE_INT:
  402. OGR_F_SetFieldInteger(Ogr_feature, ogrfieldnum,
  403. db_get_value_int(value));
  404. break;
  405. case DB_C_TYPE_DOUBLE:
  406. OGR_F_SetFieldDouble(Ogr_feature, ogrfieldnum,
  407. db_get_value_double(value));
  408. break;
  409. case DB_C_TYPE_STRING:
  410. OGR_F_SetFieldString(Ogr_feature, ogrfieldnum,
  411. db_get_value_string(value));
  412. break;
  413. case DB_C_TYPE_DATETIME:
  414. db_convert_column_value_to_string(column,
  415. &dbstring);
  416. OGR_F_SetFieldString(Ogr_feature, ogrfieldnum,
  417. db_get_string(&dbstring));
  418. break;
  419. }
  420. }
  421. }
  422. db_close_cursor (&cursor);
  423. db_free_string(&dbstring);
  424. return 1;
  425. }
  426. int sqltype_to_ogrtype(int sqltype)
  427. {
  428. int ctype, ogrtype;
  429. ctype = db_sqltype_to_Ctype(sqltype);
  430. switch(ctype) {
  431. case DB_C_TYPE_INT:
  432. ogrtype = OFTInteger;
  433. break;
  434. case DB_C_TYPE_DOUBLE:
  435. ogrtype = OFTReal;
  436. break;
  437. case DB_C_TYPE_STRING:
  438. ogrtype = OFTString;
  439. break;
  440. case DB_C_TYPE_DATETIME:
  441. ogrtype = OFTString;
  442. break;
  443. default:
  444. ogrtype = OFTString;
  445. break;
  446. }
  447. return ogrtype;
  448. }
  449. #endif /* HAVE_OGR */