build_ogr.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /*!
  2. \file lib/vector/Vlib/build_ogr.c
  3. \brief Vector library - Building topology for OGR
  4. Higher level functions for reading/writing/manipulating vectors.
  5. Line offset is
  6. - centroids : FID
  7. - other types : index of the first record (which is FID) in offset array.
  8. Category: FID, not all layer have FID, OGRNullFID is defined
  9. (5/2004) as -1, so FID should be only >= 0
  10. (C) 2001-2010 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 Radim Blazek, Piero Cavalieri
  14. \author Various updates for GRASS 7 by Martin Landa <landa.martin gmail.com>
  15. */
  16. #include <string.h>
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <grass/vector.h>
  20. #include <grass/glocale.h>
  21. #ifdef HAVE_OGR
  22. #include <ogr_api.h>
  23. /*!
  24. \brief This structure keeps info about geometry parts above
  25. current geometry, path to curent geometry in the * feature. First
  26. 'part' number however is feature Id
  27. */
  28. typedef struct
  29. {
  30. int *part;
  31. int a_parts;
  32. int n_parts;
  33. } GEOM_PARTS;
  34. /*!
  35. \brief Init parts
  36. */
  37. static void init_parts(GEOM_PARTS * parts)
  38. {
  39. parts->part = NULL;
  40. parts->a_parts = parts->n_parts = 0;
  41. }
  42. /*!
  43. \brief
  44. Reset parts
  45. */
  46. static void reset_parts(GEOM_PARTS * parts)
  47. {
  48. parts->n_parts = 0;
  49. }
  50. /*!
  51. \brief Free parts
  52. */
  53. static void free_parts(GEOM_PARTS * parts)
  54. {
  55. G_free(parts->part);
  56. parts->a_parts = parts->n_parts = 0;
  57. }
  58. /*!
  59. \brief Add new part number to parts
  60. */
  61. static void add_part(GEOM_PARTS * parts, int part)
  62. {
  63. if (parts->a_parts == parts->n_parts) {
  64. parts->a_parts += 10;
  65. parts->part =
  66. (int *)G_realloc((void *)parts->part,
  67. parts->a_parts * sizeof(int));
  68. }
  69. parts->part[parts->n_parts] = part;
  70. parts->n_parts++;
  71. }
  72. /*!
  73. \brief Remove last part
  74. */
  75. static void del_part(GEOM_PARTS * parts)
  76. {
  77. parts->n_parts--;
  78. }
  79. /*!
  80. \brief Add parts to offset
  81. */
  82. static void add_parts_to_offset(struct Map_info *Map, GEOM_PARTS * parts)
  83. {
  84. int i, j;
  85. if (Map->fInfo.ogr.offset_num + parts->n_parts >=
  86. Map->fInfo.ogr.offset_alloc) {
  87. Map->fInfo.ogr.offset_alloc += parts->n_parts + 1000;
  88. Map->fInfo.ogr.offset = (int *)G_realloc(Map->fInfo.ogr.offset,
  89. Map->fInfo.ogr.offset_alloc *
  90. sizeof(int));
  91. }
  92. j = Map->fInfo.ogr.offset_num;
  93. for (i = 0; i < parts->n_parts; i++) {
  94. G_debug(4, "add offset %d", parts->part[i]);
  95. Map->fInfo.ogr.offset[j] = parts->part[i];
  96. j++;
  97. }
  98. Map->fInfo.ogr.offset_num += parts->n_parts;
  99. }
  100. /*!
  101. \brief Add line to support structures
  102. */
  103. static int add_line(struct Map_info *Map, int type, struct line_pnts *Points,
  104. int FID, GEOM_PARTS * parts)
  105. {
  106. int line;
  107. struct Plus_head *plus;
  108. long offset;
  109. struct bound_box box;
  110. plus = &(Map->plus);
  111. if (type != GV_CENTROID) {
  112. offset = Map->fInfo.ogr.offset_num; /* beginning in the offset array */
  113. }
  114. else {
  115. /* TODO : could be used to statore category ? */
  116. offset = FID; /* because centroids are read from topology, not from layer */
  117. }
  118. G_debug(4, "Register line: FID = %d offset = %ld", FID, offset);
  119. line = dig_add_line(plus, type, Points, offset);
  120. G_debug(4, "Line registered with line = %d", line);
  121. /* Set box */
  122. dig_line_box(Points, &box);
  123. if (line == 1)
  124. Vect_box_copy(&(plus->box), &box);
  125. else
  126. Vect_box_extend(&(plus->box), &box);
  127. if (type != GV_BOUNDARY) {
  128. dig_cidx_add_cat(plus, 1, (int)FID, line, type);
  129. }
  130. else {
  131. dig_cidx_add_cat(plus, 0, 0, line, type);
  132. }
  133. if (type != GV_CENTROID) /* because centroids are read from topology, not from layer */
  134. add_parts_to_offset(Map, parts);
  135. return line;
  136. }
  137. /*!
  138. \brief Recursively add geometry to topology
  139. */
  140. static int add_geometry(struct Map_info *Map, OGRGeometryH hGeom, int FID,
  141. GEOM_PARTS * parts)
  142. {
  143. struct Plus_head *plus;
  144. int i, ret;
  145. int line;
  146. int area, isle, outer_area = 0;
  147. int lines[1];
  148. static struct line_pnts **Points = NULL;
  149. static int alloc_points = 0;
  150. struct bound_box box;
  151. struct P_line *Line;
  152. double area_size, x, y;
  153. int eType, nRings, iPart, nParts, nPoints;
  154. OGRGeometryH hGeom2, hRing;
  155. G_debug(4, "add_geometry() FID = %d", FID);
  156. plus = &(Map->plus);
  157. if (!Points) {
  158. alloc_points = 1;
  159. Points = (struct line_pnts **)G_malloc(sizeof(struct line_pnts *));
  160. Points[0] = Vect_new_line_struct();
  161. }
  162. Vect_reset_line(Points[0]);
  163. eType = wkbFlatten(OGR_G_GetGeometryType(hGeom));
  164. G_debug(4, "OGR type = %d", eType);
  165. switch (eType) {
  166. case wkbPoint:
  167. G_debug(4, "Point");
  168. Vect_append_point(Points[0], OGR_G_GetX(hGeom, 0),
  169. OGR_G_GetY(hGeom, 0), OGR_G_GetZ(hGeom, 0));
  170. add_line(Map, GV_POINT, Points[0], FID, parts);
  171. break;
  172. case wkbLineString:
  173. G_debug(4, "LineString");
  174. nPoints = OGR_G_GetPointCount(hGeom);
  175. for (i = 0; i < nPoints; i++) {
  176. Vect_append_point(Points[0],
  177. OGR_G_GetX(hGeom, i), OGR_G_GetY(hGeom, i),
  178. OGR_G_GetZ(hGeom, i));
  179. }
  180. add_line(Map, GV_LINE, Points[0], FID, parts);
  181. break;
  182. case wkbPolygon:
  183. G_debug(4, "Polygon");
  184. nRings = OGR_G_GetGeometryCount(hGeom);
  185. G_debug(4, "Number of rings: %d", nRings);
  186. /* Alloc space for islands */
  187. if (nRings >= alloc_points) {
  188. Points = (struct line_pnts **)G_realloc((void *)Points,
  189. nRings *
  190. sizeof(struct line_pnts
  191. *));
  192. for (i = alloc_points; i < nRings; i++) {
  193. Points[i] = Vect_new_line_struct();
  194. }
  195. }
  196. for (iPart = 0; iPart < nRings; iPart++) {
  197. hRing = OGR_G_GetGeometryRef(hGeom, iPart);
  198. nPoints = OGR_G_GetPointCount(hRing);
  199. G_debug(4, " ring %d : nPoints = %d", iPart, nPoints);
  200. Vect_reset_line(Points[iPart]);
  201. for (i = 0; i < nPoints; i++) {
  202. Vect_append_point(Points[iPart],
  203. OGR_G_GetX(hRing, i), OGR_G_GetY(hRing, i),
  204. OGR_G_GetZ(hRing, i));
  205. }
  206. /* register line */
  207. add_part(parts, iPart);
  208. line = add_line(Map, GV_BOUNDARY, Points[iPart], FID, parts);
  209. del_part(parts);
  210. /* add area (each inner ring is also area) */
  211. dig_line_box(Points[iPart], &box);
  212. dig_find_area_poly(Points[iPart], &area_size);
  213. if (area_size > 0) /* clockwise */
  214. lines[0] = line;
  215. else
  216. lines[0] = -line;
  217. area = dig_add_area(plus, 1, lines);
  218. dig_area_set_box(plus, area, &box);
  219. /* Each area is also isle */
  220. lines[0] = -lines[0]; /* island is counter clockwise */
  221. isle = dig_add_isle(plus, 1, lines);
  222. dig_isle_set_box(plus, isle, &box);
  223. if (iPart == 0) { /* outer ring */
  224. outer_area = area;
  225. }
  226. else { /* inner ring */
  227. struct P_isle *Isle;
  228. Isle = plus->Isle[isle];
  229. Isle->area = outer_area;
  230. dig_area_add_isle(plus, outer_area, isle);
  231. }
  232. }
  233. /* create virtual centroid */
  234. ret =
  235. Vect_get_point_in_poly_isl((const struct line_pnts *) Points[0],
  236. (const struct line_pnts **) Points + 1, nRings - 1,
  237. &x, &y);
  238. if (ret < -1) {
  239. G_warning(_("Unable to calculate centroid for area %d"),
  240. outer_area);
  241. }
  242. else {
  243. struct P_area *Area;
  244. G_debug(4, " Centroid: %f, %f", x, y);
  245. Vect_reset_line(Points[0]);
  246. Vect_append_point(Points[0], x, y, 0.0);
  247. line = add_line(Map, GV_CENTROID, Points[0], FID, parts);
  248. dig_line_box(Points[0], &box);
  249. dig_line_set_box(plus, line, &box);
  250. Line = plus->Line[line];
  251. Line->left = outer_area;
  252. /* register centroid to area */
  253. Area = plus->Area[outer_area];
  254. Area->centroid = line;
  255. }
  256. break;
  257. case wkbMultiPoint:
  258. case wkbMultiLineString:
  259. case wkbMultiPolygon:
  260. case wkbGeometryCollection:
  261. nParts = OGR_G_GetGeometryCount(hGeom);
  262. G_debug(4, "%d geoms -> next level", nParts);
  263. for (i = 0; i < nParts; i++) {
  264. add_part(parts, i);
  265. hGeom2 = OGR_G_GetGeometryRef(hGeom, i);
  266. add_geometry(Map, hGeom2, FID, parts);
  267. del_part(parts);
  268. }
  269. break;
  270. default:
  271. G_warning(_("OGR feature type %d not supported"), eType);
  272. break;
  273. }
  274. return 0;
  275. }
  276. /*!
  277. \brief Build pseudo-topology for OGR layer
  278. \param Map pointer to Map_info structure
  279. \param build build level (GV_BUILD_NONE and GV_BUILD_ALL currently supported)
  280. \return 1 on success
  281. \return 0 on error
  282. */
  283. int Vect_build_ogr(struct Map_info *Map, int build)
  284. {
  285. int iFeature, count, FID;
  286. struct Plus_head *plus;
  287. GEOM_PARTS parts;
  288. OGRFeatureH hFeature;
  289. OGRGeometryH hGeom;
  290. G_debug(1, "Vect_build_ogr(): dsn=%s layer=%s, build=%d",
  291. Map->fInfo.ogr.dsn, Map->fInfo.ogr.layer_name, build);
  292. if (build != GV_BUILD_ALL && build != GV_BUILD_NONE) {
  293. G_warning(_("Partial build for OGR is not supported"));
  294. return 0;
  295. }
  296. plus = &(Map->plus);
  297. if (build == plus->built)
  298. return 1; /* do nothing */
  299. /* TODO move this init to better place (Vect_open_ ?), because in theory build may be reused on level2 */
  300. G_free((void *) Map->fInfo.ogr.offset);
  301. Map->fInfo.ogr.offset = NULL;
  302. Map->fInfo.ogr.offset_num = 0;
  303. Map->fInfo.ogr.offset_alloc = 0;
  304. /* test layer capabilities */
  305. if (!OGR_L_TestCapability(Map->fInfo.ogr.layer, OLCRandomRead)) {
  306. G_warning(_("Random read is not supported by OGR for this layer, "
  307. "unable to build topology"));
  308. return 0;
  309. }
  310. G_message(_("Using external data format '%s' (feature type '%s')"),
  311. Vect_get_ogr_format_info(Map),
  312. Vect_get_ogr_geometry_type(Map));
  313. /* initialize data structures */
  314. init_parts(&parts);
  315. /* Check if upgrade or downgrade */
  316. if (build < plus->built) { /* lower level request, currently only GV_BUILD_NONE */
  317. dig_free_plus_areas(plus);
  318. dig_spidx_free_areas(plus);
  319. dig_free_plus_isles(plus);
  320. dig_spidx_free_isles(plus);
  321. dig_free_plus_nodes(plus);
  322. dig_spidx_free_nodes(plus);
  323. dig_free_plus_lines(plus);
  324. dig_spidx_free_lines(plus);
  325. }
  326. else {
  327. /* Note: Do not use OGR_L_GetFeatureCount (it may scan all features) */
  328. OGR_L_ResetReading(Map->fInfo.ogr.layer);
  329. count = iFeature = 0;
  330. while ((hFeature = OGR_L_GetNextFeature(Map->fInfo.ogr.layer)) != NULL) {
  331. iFeature++;
  332. count++;
  333. G_debug(3, " Feature %d", iFeature);
  334. hGeom = OGR_F_GetGeometryRef(hFeature);
  335. if (hGeom == NULL) {
  336. G_warning(_("Feature %d without geometry ignored"), iFeature);
  337. OGR_F_Destroy(hFeature);
  338. continue;
  339. }
  340. FID = (int)OGR_F_GetFID(hFeature);
  341. if (FID == OGRNullFID) {
  342. G_warning(_("OGR feature %d without ID ignored"), iFeature);
  343. OGR_F_Destroy(hFeature);
  344. continue;
  345. }
  346. G_debug(4, " FID = %d", FID);
  347. reset_parts(&parts);
  348. add_part(&parts, FID);
  349. add_geometry(Map, hGeom, FID, &parts);
  350. OGR_F_Destroy(hFeature);
  351. } /* while */
  352. }
  353. free_parts(&parts);
  354. Map->plus.built = build;
  355. return 1;
  356. }
  357. #endif