write_ogr.c 17 KB

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