spindex_rw.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. /*!
  2. \file diglib/spindex.c
  3. \brief Vector library - spatial index - read/write (lower level functions)
  4. Lower level functions for reading/writing/manipulating vectors.
  5. (C) 2001-2009 by the GRASS Development Team
  6. This program is free software under the GNU General Public License
  7. (>=v2). Read the file COPYING that comes with GRASS for details.
  8. \author Original author CERL, probably Dave Gerdes
  9. \author Update to GRASS 5.7 Radim Blazek
  10. */
  11. #include <grass/config.h>
  12. #include <sys/types.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <grass/gis.h>
  16. #include <grass/vector.h>
  17. #include <grass/glocale.h>
  18. /*!
  19. \brief Write spatial index to the file
  20. \param[in,out] fp pointer to GVFILE
  21. \param ptr pointer to Plus_head structure
  22. \return 0 on success
  23. \return -1 on error
  24. */
  25. static int dig_Wr_spindx_head(GVFILE * fp, struct Plus_head *ptr)
  26. {
  27. unsigned char buf[5];
  28. long length = 42;
  29. dig_rewind(fp);
  30. dig_set_cur_port(&(ptr->spidx_port));
  31. /* bytes 1 - 5 */
  32. buf[0] = GV_SIDX_VER_MAJOR;
  33. buf[1] = GV_SIDX_VER_MINOR;
  34. buf[2] = GV_SIDX_EARLIEST_MAJOR;
  35. buf[3] = GV_SIDX_EARLIEST_MINOR;
  36. buf[4] = ptr->spidx_port.byte_order;
  37. if (0 >= dig__fwrite_port_C((const char *)buf, 5, fp))
  38. return (-1);
  39. /* get required offset size */
  40. if (ptr->off_t_size == 0) {
  41. /* should not happen, topo is written first */
  42. if (ptr->coor_size > (off_t)PORT_LONG_MAX)
  43. ptr->off_t_size = 8;
  44. else
  45. ptr->off_t_size = 4;
  46. }
  47. /* adjust header size for large files */
  48. if (ptr->off_t_size == 8) {
  49. /* 7 offset values and coor file size: add 8 * 4 */
  50. length += 32;
  51. }
  52. /* bytes 6 - 9 : header size */
  53. if (0 >= dig__fwrite_port_L(&length, 1, fp))
  54. return (0);
  55. /* byte 10 : dimension 2D or 3D */
  56. buf[0] = ptr->spidx_with_z;
  57. if (0 >= dig__fwrite_port_C((const char*) buf, 1, fp))
  58. return (-1);
  59. /* bytes 11 - 38 (large files 11 - 66) : Offsets */
  60. if (0 >= dig__fwrite_port_O(&(ptr->Node_spidx_offset), 1, fp, ptr->off_t_size))
  61. return (-1);
  62. if (0 >= dig__fwrite_port_O(&(ptr->Edge_spidx_offset), 1, fp, ptr->off_t_size))
  63. return (-1);
  64. if (0 >= dig__fwrite_port_O(&(ptr->Line_spidx_offset), 1, fp, ptr->off_t_size))
  65. return (-1);
  66. if (0 >= dig__fwrite_port_O(&(ptr->Area_spidx_offset), 1, fp, ptr->off_t_size))
  67. return (-1);
  68. if (0 >= dig__fwrite_port_O(&(ptr->Isle_spidx_offset), 1, fp, ptr->off_t_size))
  69. return (-1);
  70. if (0 >= dig__fwrite_port_O(&(ptr->Volume_spidx_offset), 1, fp, ptr->off_t_size))
  71. return (-1);
  72. if (0 >= dig__fwrite_port_O(&(ptr->Hole_spidx_offset), 1, fp, ptr->off_t_size))
  73. return (-1);
  74. G_debug(3, "spidx offset node = %lu line = %lu, area = %lu isle = %lu",
  75. (long unsigned) ptr->Node_spidx_offset, (long unsigned) ptr->Line_spidx_offset,
  76. (long unsigned) ptr->Area_spidx_offset, (long unsigned) ptr->Isle_spidx_offset);
  77. /* bytes 39 - 42 (large files 67 - 74) : Offsets */
  78. if (0 >= dig__fwrite_port_O(&(ptr->coor_size), 1, fp, ptr->off_t_size))
  79. return (-1);
  80. G_debug(2, "spidx body offset %lu", (long unsigned) dig_ftell(fp));
  81. return (0);
  82. }
  83. /*!
  84. \brief Read spatial index to the file
  85. \param fp pointer to GVFILE
  86. \param[in,out] ptr pointer to Plus_head structure
  87. \return 0 on success
  88. \return -1 on error
  89. */
  90. static int dig_Rd_spindx_head(GVFILE * fp, struct Plus_head *ptr)
  91. {
  92. unsigned char buf[5];
  93. int byte_order;
  94. off_t coor_size;
  95. dig_rewind(fp);
  96. /* bytes 1 - 5 */
  97. if (0 >= dig__fread_port_C((char*) buf, 5, fp))
  98. return (-1);
  99. ptr->spidx_Version_Major = buf[0];
  100. ptr->spidx_Version_Minor = buf[1];
  101. ptr->spidx_Back_Major = buf[2];
  102. ptr->spidx_Back_Minor = buf[3];
  103. byte_order = buf[4];
  104. G_debug(2, "Sidx header: file version %d.%d , supported from GRASS version %d.%d",
  105. ptr->spidx_Version_Major, ptr->spidx_Version_Minor,
  106. ptr->spidx_Back_Major, ptr->spidx_Back_Minor);
  107. G_debug(2, " byte order %d", byte_order);
  108. /* check version numbers */
  109. if (ptr->spidx_Version_Major > GV_SIDX_VER_MAJOR ||
  110. ptr->spidx_Version_Minor > GV_SIDX_VER_MINOR) {
  111. /* The file was created by GRASS library with higher version than this one */
  112. if (ptr->spidx_Back_Major > GV_SIDX_VER_MAJOR ||
  113. ptr->spidx_Back_Minor > GV_SIDX_VER_MINOR) {
  114. /* This version of GRASS lib is lower than the oldest which can read this format */
  115. G_fatal_error(_("Spatial index format version %d.%d is not "
  116. "supported by this release."
  117. " Try to rebuild topology or upgrade GRASS."),
  118. ptr->spidx_Version_Major, ptr->spidx_Version_Minor);
  119. return (-1);
  120. }
  121. G_warning(_("Your GRASS version does not fully support "
  122. "spatial index format %d.%d of the vector."
  123. " Consider to rebuild topology or upgrade GRASS."),
  124. ptr->spidx_Version_Major, ptr->spidx_Version_Minor);
  125. }
  126. dig_init_portable(&(ptr->spidx_port), byte_order);
  127. dig_set_cur_port(&(ptr->spidx_port));
  128. /* bytes 6 - 9 : header size */
  129. if (0 >= dig__fread_port_L(&(ptr->spidx_head_size), 1, fp))
  130. return (-1);
  131. G_debug(2, " header size %ld", ptr->spidx_head_size);
  132. /* byte 10 : dimension 2D or 3D */
  133. if (0 >= dig__fread_port_C((char *)buf, 1, fp))
  134. return (-1);
  135. ptr->spidx_with_z = buf[0];
  136. G_debug(2, " with_z %d", ptr->spidx_with_z);
  137. /* get required offset size */
  138. if (ptr->off_t_size == 0) {
  139. /* should not happen, topo is opened first */
  140. if (ptr->coor_size > (off_t)PORT_LONG_MAX)
  141. ptr->off_t_size = 8;
  142. else
  143. ptr->off_t_size = 4;
  144. }
  145. /* as long as topo is always opened first, off_t size check is not needed here */
  146. /* bytes 11 - 38 (large files 11 - 66) : Offsets */
  147. if (0 >= dig__fread_port_O(&(ptr->Node_spidx_offset), 1, fp, ptr->off_t_size))
  148. return (-1);
  149. if (0 >= dig__fread_port_O(&(ptr->Edge_spidx_offset), 1, fp, ptr->off_t_size))
  150. return (-1);
  151. if (0 >= dig__fread_port_O(&(ptr->Line_spidx_offset), 1, fp, ptr->off_t_size))
  152. return (-1);
  153. if (0 >= dig__fread_port_O(&(ptr->Area_spidx_offset), 1, fp, ptr->off_t_size))
  154. return (-1);
  155. if (0 >= dig__fread_port_O(&(ptr->Isle_spidx_offset), 1, fp, ptr->off_t_size))
  156. return (-1);
  157. if (0 >= dig__fread_port_O(&(ptr->Volume_spidx_offset), 1, fp, ptr->off_t_size))
  158. return (-1);
  159. if (0 >= dig__fread_port_O(&(ptr->Hole_spidx_offset), 1, fp, ptr->off_t_size))
  160. return (-1);
  161. /* bytes 39 - 42 (large files 67 - 74) : Offsets */
  162. if (0 >= dig__fread_port_O(&coor_size, 1, fp, ptr->off_t_size))
  163. return (-1);
  164. G_debug(2, " coor size %lu", (long unsigned) coor_size);
  165. dig_fseek(fp, ptr->spidx_head_size, SEEK_SET);
  166. return (0);
  167. }
  168. static int rtree_dump_node(FILE *, const struct Node *, int);
  169. /*!
  170. \brief Dump R-tree branch to the file
  171. \param fp pointer to FILE
  172. \param b pointer to Branch structure
  173. \param with_z non-zero value for 3D vector data
  174. \param level level value
  175. \return 0
  176. */
  177. static int rtree_dump_branch(FILE * fp, const struct Branch *b, int with_z, int level)
  178. {
  179. const struct Rect *r;
  180. r = &(b->rect);
  181. if (level == 0)
  182. fprintf(fp, " id = %d ", (int)b->child);
  183. fprintf(fp, " %f %f %f %f %f %f\n", r->boundary[0], r->boundary[1],
  184. r->boundary[2], r->boundary[3], r->boundary[4], r->boundary[5]);
  185. if (level > 0) {
  186. rtree_dump_node(fp, b->child, with_z);
  187. }
  188. return 0;
  189. }
  190. /*!
  191. \brief Dump R-tree node to the file
  192. \param fp pointer to FILE
  193. \param n pointer to Node structure
  194. \param with_z non-zero value for 3D vector data
  195. \return 0
  196. */
  197. int rtree_dump_node(FILE * fp, const struct Node *n, int with_z)
  198. {
  199. int i, nn;
  200. fprintf(fp, "Node level=%d count=%d\n", n->level, n->count);
  201. if (n->level > 0)
  202. nn = NODECARD;
  203. else
  204. nn = LEAFCARD;
  205. for (i = 0; i < nn; i++) {
  206. if (n->branch[i].child) {
  207. fprintf(fp, " Branch %d", i);
  208. rtree_dump_branch(fp, &n->branch[i], with_z, n->level);
  209. }
  210. }
  211. return 0;
  212. }
  213. static int rtree_write_node(GVFILE *, const struct Node *, int);
  214. /*!
  215. \brief Write R-tree node to the file
  216. \param fp pointer to GVFILE
  217. \param b pointer to Branch structure
  218. \param with_z non-zero value for 3D vector data
  219. \param level level value
  220. \return -1 on error
  221. \return 0 on success
  222. */
  223. static int rtree_write_branch(GVFILE * fp, const struct Branch *b, int with_z, int level)
  224. {
  225. const struct Rect *r;
  226. int i;
  227. r = &(b->rect);
  228. /* rectangle */
  229. if (with_z) {
  230. if (0 >= dig__fwrite_port_D(&(r->boundary[0]), 6, fp))
  231. return (-1);
  232. }
  233. else {
  234. if (0 >= dig__fwrite_port_D(&(r->boundary[0]), 2, fp))
  235. return (-1);
  236. if (0 >= dig__fwrite_port_D(&(r->boundary[3]), 2, fp))
  237. return (-1);
  238. }
  239. if (level == 0) { /* write data (element id) */
  240. i = (int) b->child;
  241. if (0 >= dig__fwrite_port_I(&i, 1, fp))
  242. return (-1);
  243. }
  244. else {
  245. rtree_write_node(fp, b->child, with_z);
  246. }
  247. return 0;
  248. }
  249. /*!
  250. \brief Write R-tree node to the file
  251. \param fp pointer to GVFILE
  252. \param n pointer to Node structure
  253. \param with_z non-zero value for 3D vector data
  254. \return -1 on error
  255. \return 0 on success
  256. */
  257. int rtree_write_node(GVFILE * fp, const struct Node *n, int with_z)
  258. {
  259. int i, nn;
  260. /* level ( 0 = leaf, data ) */
  261. if (0 >= dig__fwrite_port_I(&(n->level), 1, fp))
  262. return (-1);
  263. /* count */
  264. if (0 >= dig__fwrite_port_I(&(n->count), 1, fp))
  265. return (-1);
  266. if (n->level > 0)
  267. nn = NODECARD;
  268. else
  269. nn = LEAFCARD;
  270. for (i = 0; i < nn; i++) {
  271. if (n->branch[i].child) {
  272. rtree_write_branch(fp, &n->branch[i], with_z, n->level);
  273. }
  274. }
  275. return 0;
  276. }
  277. static int rtree_read_node(GVFILE * fp, struct Node *n, int with_z);
  278. /*!
  279. \brief Read R-tree branch from the file
  280. \param fp pointer to GVFILE
  281. \param b pointer to Branch structure
  282. \param with_z non-zero value for 3D vector data
  283. \param level level value
  284. \return -1 on error
  285. \return 0 on success
  286. */
  287. static int rtree_read_branch(GVFILE * fp, struct Branch *b, int with_z, int level)
  288. {
  289. struct Rect *r;
  290. int i;
  291. G_debug(3, "rtree_read_branch()");
  292. r = &(b->rect);
  293. /* rectangle */
  294. if (with_z) {
  295. if (0 >= dig__fread_port_D(&(r->boundary[0]), 6, fp))
  296. return (-1);
  297. }
  298. else {
  299. if (0 >= dig__fread_port_D(&(r->boundary[0]), 2, fp))
  300. return (-1);
  301. if (0 >= dig__fread_port_D(&(r->boundary[3]), 2, fp))
  302. return (-1);
  303. r->boundary[2] = 0;
  304. r->boundary[5] = 0;
  305. }
  306. if (level == 0) { /* read data (element id) */
  307. if (0 >= dig__fread_port_I(&i, 1, fp))
  308. return (-1);
  309. b->child = (struct Node *)i;
  310. }
  311. else {
  312. /* create new node */
  313. b->child = RTreeNewNode();
  314. rtree_read_node(fp, b->child, with_z);
  315. }
  316. return 0;
  317. }
  318. /*!
  319. \brief Read R-tree node from the file
  320. \param fp pointer to GVFILE
  321. \param n pointer to Node structure
  322. \param with_z non-zero value for 3D vector data
  323. \param level level value
  324. \return -1 on error
  325. \return 0 on success
  326. */
  327. int rtree_read_node(GVFILE * fp, struct Node *n, int with_z)
  328. {
  329. int level, count, i;
  330. G_debug(3, "rtree_read_node()");
  331. /* level ( 0 = leaf, data ) */
  332. if (0 >= dig__fread_port_I(&level, 1, fp))
  333. return (-1);
  334. n->level = level;
  335. /* count */
  336. if (0 >= dig__fread_port_I(&count, 1, fp))
  337. return (-1);
  338. n->count = count;
  339. for (i = 0; i < count; i++) {
  340. if (0 > rtree_read_branch(fp, &n->branch[i], with_z, level))
  341. return (-1);
  342. }
  343. return 0;
  344. }
  345. /*!
  346. \brief Write spatial index to the file
  347. \param[out] fp pointer to GVFILE
  348. \param Plus pointer to Plus_head structure
  349. \return 0
  350. */
  351. int dig_write_spidx(GVFILE * fp, struct Plus_head *Plus)
  352. {
  353. dig_set_cur_port(&(Plus->spidx_port));
  354. dig_rewind(fp);
  355. dig_Wr_spindx_head(fp, Plus);
  356. Plus->Node_spidx_offset = dig_ftell(fp);
  357. rtree_write_node(fp, Plus->Node_spidx, Plus->with_z);
  358. Plus->Line_spidx_offset = dig_ftell(fp);
  359. rtree_write_node(fp, Plus->Line_spidx, Plus->with_z);
  360. Plus->Area_spidx_offset = dig_ftell(fp);
  361. rtree_write_node(fp, Plus->Area_spidx, Plus->with_z);
  362. Plus->Isle_spidx_offset = dig_ftell(fp);
  363. rtree_write_node(fp, Plus->Isle_spidx, Plus->with_z);
  364. dig_rewind(fp);
  365. dig_Wr_spindx_head(fp, Plus); /* rewrite with offsets */
  366. return 0;
  367. }
  368. /*!
  369. \brief Read spatial index from the file
  370. \param fp pointer to GVFILE
  371. \param[in,out] Plus pointer to Plus_head structure
  372. \return 0
  373. */
  374. int dig_read_spidx(GVFILE * fp, struct Plus_head *Plus)
  375. {
  376. G_debug(1, "dig_read_spindx()");
  377. /* TODO: free old tree */
  378. dig_spidx_init(Plus);
  379. dig_rewind(fp);
  380. dig_Rd_spindx_head(fp, Plus);
  381. dig_set_cur_port(&(Plus->spidx_port));
  382. dig_fseek(fp, Plus->Node_spidx_offset, 0);
  383. rtree_read_node(fp, Plus->Node_spidx, Plus->with_z);
  384. dig_fseek(fp, Plus->Line_spidx_offset, 0);
  385. rtree_read_node(fp, Plus->Line_spidx, Plus->with_z);
  386. dig_fseek(fp, Plus->Area_spidx_offset, 0);
  387. rtree_read_node(fp, Plus->Area_spidx, Plus->with_z);
  388. dig_fseek(fp, Plus->Isle_spidx_offset, 0);
  389. rtree_read_node(fp, Plus->Isle_spidx, Plus->with_z);
  390. return 0;
  391. }
  392. /*!
  393. \brief Dump spatial index
  394. \param[out] fp pointe to FILE
  395. \param Plus pointer to Plus_head structure
  396. \return 0
  397. */
  398. int dig_dump_spidx(FILE * fp, const struct Plus_head *Plus)
  399. {
  400. fprintf(fp, "Nodes\n");
  401. rtree_dump_node(fp, Plus->Node_spidx, Plus->with_z);
  402. fprintf(fp, "Lines\n");
  403. rtree_dump_node(fp, Plus->Line_spidx, Plus->with_z);
  404. fprintf(fp, "Areas\n");
  405. rtree_dump_node(fp, Plus->Area_spidx, Plus->with_z);
  406. fprintf(fp, "Isles\n");
  407. rtree_dump_node(fp, Plus->Isle_spidx, Plus->with_z);
  408. return 0;
  409. }