write_ogr.c 14 KB

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