write_ogr.c 15 KB

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