spindex_rw.c 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504
  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. \author Update to GRASS 7 Markus Metz
  11. */
  12. #include <sys/types.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <unistd.h>
  16. #include <assert.h>
  17. #include <grass/vector.h>
  18. #include <grass/glocale.h>
  19. #include <grass/version.h>
  20. /* TODO: only write out actually used sides */
  21. #ifndef NUMSIDES
  22. #define NUMSIDES 6
  23. #endif
  24. /* TODO: merge these two */
  25. struct spidxstack
  26. {
  27. off_t pos[MAXCARD]; /* file position of child node, object ID on level 0 */
  28. struct RTree_Node sn; /* stack node */
  29. int branch_id; /* branch no to follow down */
  30. };
  31. struct spidxpstack
  32. {
  33. off_t pos[MAXCARD]; /* file position of child node, object ID on level 0 */
  34. struct RTree_Node *sn; /* stack node pointer */
  35. int branch_id; /* branch no to follow down */
  36. };
  37. /*!
  38. \brief Write spatial index header to file
  39. \param[in,out] fp pointer to struct gvfile
  40. \param ptr pointer to Plus_head structure
  41. \return 0 on success
  42. \return -1 on error
  43. */
  44. int dig_Wr_spidx_head(struct gvfile * fp, struct Plus_head *ptr)
  45. {
  46. unsigned char buf[6];
  47. long length = 81; /* header length in bytes */
  48. struct RTree *t;
  49. size_t size;
  50. dig_rewind(fp);
  51. dig_set_cur_port(&(ptr->spidx_port));
  52. /* use ptr->off_t_size = 4 if possible */
  53. if (sizeof(off_t) > 4) {
  54. size = 145; /* max header size, see below */
  55. size += ptr->Node_spidx->n_nodes * ptr->Node_spidx->nodesize;
  56. size += ptr->Line_spidx->n_nodes * ptr->Line_spidx->nodesize;
  57. size += ptr->Area_spidx->n_nodes * ptr->Area_spidx->nodesize;
  58. size += ptr->Isle_spidx->n_nodes * ptr->Isle_spidx->nodesize;
  59. if (size < PORT_INT_MAX)
  60. ptr->spidx_port.off_t_size = 4;
  61. else
  62. ptr->spidx_port.off_t_size = 8;
  63. }
  64. else
  65. ptr->spidx_port.off_t_size = 4;
  66. /* bytes 1 - 6 */
  67. buf[0] = GV_SIDX_VER_MAJOR;
  68. buf[1] = GV_SIDX_VER_MINOR;
  69. buf[2] = GV_SIDX_EARLIEST_MAJOR;
  70. buf[3] = GV_SIDX_EARLIEST_MINOR;
  71. buf[4] = ptr->spidx_port.byte_order;
  72. buf[5] = (unsigned char)ptr->spidx_port.off_t_size;
  73. if (0 >= dig__fwrite_port_C((const char *)buf, 6, fp))
  74. return (-1);
  75. /* adjust header size for large files */
  76. if (ptr->spidx_port.off_t_size == 4) {
  77. if (ptr->off_t_size == 4)
  78. length = 113;
  79. else if (ptr->off_t_size == 8)
  80. length = 117;
  81. else
  82. G_fatal_error(_("Topology file must be written before spatial index file"));
  83. }
  84. else if (ptr->spidx_port.off_t_size == 8) {
  85. if (ptr->off_t_size == 4)
  86. length = 141;
  87. else if (ptr->off_t_size == 8)
  88. length = 145;
  89. else
  90. G_fatal_error(_("Topology file must be written before spatial index file"));
  91. }
  92. /* bytes 7 - 10 : header size */
  93. if (0 >= dig__fwrite_port_L(&length, 1, fp))
  94. return (0);
  95. ptr->spidx_head_size = length;
  96. /* byte 11 : dimension 2D or 3D */
  97. buf[0] = ptr->spidx_with_z;
  98. if (0 >= dig__fwrite_port_C((const char *)buf, 1, fp))
  99. return (-1);
  100. /* identical for all spatial indices: */
  101. t = ptr->Node_spidx;
  102. /* byte 12 : n dimensions */
  103. if (0 >= dig__fwrite_port_C((const char *)&(t->ndims), 1, fp))
  104. return (-1);
  105. /* byte 13 : n sides */
  106. if (0 >= dig__fwrite_port_C((const char *)&(t->nsides), 1, fp))
  107. return (-1);
  108. /* bytes 14 - 17 : nodesize */
  109. if (0 >= dig__fwrite_port_I(&(t->nodesize), 1, fp))
  110. return (-1);
  111. /* bytes 18 - 21 : nodecard */
  112. if (0 >= dig__fwrite_port_I(&(t->nodecard), 1, fp))
  113. return (-1);
  114. /* bytes 22 - 25 : leafcard */
  115. if (0 >= dig__fwrite_port_I(&(t->leafcard), 1, fp))
  116. return (-1);
  117. /* bytes 26 - 29 : min node fill */
  118. if (0 >= dig__fwrite_port_I(&(t->min_node_fill), 1, fp))
  119. return (-1);
  120. /* bytes 30 - 33 : min leaf fill */
  121. if (0 >= dig__fwrite_port_I(&(t->min_leaf_fill), 1, fp))
  122. return (-1);
  123. /* for each spatial index : */
  124. /* Node spatial index */
  125. /* bytes 34 - 37 : n nodes */
  126. if (0 >= dig__fwrite_port_I((const int *)&(t->n_nodes), 1, fp))
  127. return (-1);
  128. /* bytes 38 - 41 : n leafs */
  129. if (0 >= dig__fwrite_port_I((const int *)&(t->n_leafs), 1, fp))
  130. return (-1);
  131. /* bytes 42 - 45 : n levels */
  132. if (0 >= dig__fwrite_port_I(&(t->rootlevel), 1, fp))
  133. return (-1);
  134. /* bytes 46 - 49 (LFS 53) : root node offset */
  135. if (0 >=
  136. dig__fwrite_port_O(&(ptr->Node_spidx_offset), 1, fp,
  137. ptr->spidx_port.off_t_size))
  138. return (-1);
  139. /* Line spatial index */
  140. t = ptr->Line_spidx;
  141. /* bytes 50 - 53 (LFS 54 - 57) : n nodes */
  142. if (0 >= dig__fwrite_port_I((const int *)&(t->n_nodes), 1, fp))
  143. return (-1);
  144. /* bytes 54 - 57 (LFS 58 - 61) : n leafs */
  145. if (0 >= dig__fwrite_port_I((const int *)&(t->n_leafs), 1, fp))
  146. return (-1);
  147. /* bytes 58 - 61 (LFS 62 - 65) : n levels */
  148. if (0 >= dig__fwrite_port_I(&(t->rootlevel), 1, fp))
  149. return (-1);
  150. /* bytes 62 - 65 (LFS 66 - 73) : root node offset */
  151. if (0 >=
  152. dig__fwrite_port_O(&(ptr->Line_spidx_offset), 1, fp,
  153. ptr->spidx_port.off_t_size))
  154. return (-1);
  155. /* Area spatial index */
  156. t = ptr->Area_spidx;
  157. /* bytes 66 - 69 (LFS 74 - 77) : n nodes */
  158. if (0 >= dig__fwrite_port_I((const int *)&(t->n_nodes), 1, fp))
  159. return (-1);
  160. /* bytes 70 - 73 (LFS 78 - 81) : n leafs */
  161. if (0 >= dig__fwrite_port_I((const int *)&(t->n_leafs), 1, fp))
  162. return (-1);
  163. /* bytes 74 - 77 (LFS 82 - 85) : n levels */
  164. if (0 >= dig__fwrite_port_I(&(t->rootlevel), 1, fp))
  165. return (-1);
  166. /* bytes 78 - 81 (LFS 86 - 93) : root node offset */
  167. if (0 >=
  168. dig__fwrite_port_O(&(ptr->Area_spidx_offset), 1, fp,
  169. ptr->spidx_port.off_t_size))
  170. return (-1);
  171. /* Isle spatial index */
  172. t = ptr->Isle_spidx;
  173. /* bytes 82 - 85 (LFS 94 - 97) : n nodes */
  174. if (0 >= dig__fwrite_port_I((const int *)&(t->n_nodes), 1, fp))
  175. return (-1);
  176. /* bytes 86 - 89 (LFS 98 - 101) : n leafs */
  177. if (0 >= dig__fwrite_port_I((const int *)&(t->n_leafs), 1, fp))
  178. return (-1);
  179. /* bytes 90 - 93 (LFS 102 - 105) : n levels */
  180. if (0 >= dig__fwrite_port_I(&(t->rootlevel), 1, fp))
  181. return (-1);
  182. /* bytes 94 - 97 (LFS 106 - 113) : root node offset */
  183. if (0 >=
  184. dig__fwrite_port_O(&(ptr->Isle_spidx_offset), 1, fp,
  185. ptr->spidx_port.off_t_size))
  186. return (-1);
  187. /* 3D future : */
  188. /* Face spatial index */
  189. /* bytes 98 - 101 (LFS 114 - 121) : root node offset */
  190. if (0 >=
  191. dig__fwrite_port_O(&(ptr->Face_spidx_offset), 1, fp,
  192. ptr->spidx_port.off_t_size))
  193. return (-1);
  194. /* ptr->Face_spidx->rootpos = ptr->Face_spidx_offset; */
  195. /* Volume spatial index */
  196. /* bytes 102 - 105 (LFS 122 - 129) : root node offset */
  197. if (0 >=
  198. dig__fwrite_port_O(&(ptr->Volume_spidx_offset), 1, fp,
  199. ptr->spidx_port.off_t_size))
  200. return (-1);
  201. /* ptr->Volume_spidx->rootpos = ptr->Volume_spidx_offset; */
  202. /* Hole spatial index */
  203. /* bytes 106 - 109 (LFS 130 - 137) : root node offset */
  204. if (0 >=
  205. dig__fwrite_port_O(&(ptr->Hole_spidx_offset), 1, fp,
  206. ptr->spidx_port.off_t_size))
  207. return (-1);
  208. /* ptr->Hole_spidx->rootpos = ptr->Hole_spidx_offset; */
  209. G_debug(3, "spidx offset node = %lu line = %lu, area = %lu isle = %lu",
  210. (long unsigned)ptr->Node_spidx_offset,
  211. (long unsigned)ptr->Line_spidx_offset,
  212. (long unsigned)ptr->Area_spidx_offset,
  213. (long unsigned)ptr->Isle_spidx_offset);
  214. /* coor file size : bytes 110 - 113 (117) (LFS: 138 - 141 (145)) */
  215. if (0 >= dig__fwrite_port_O(&(ptr->coor_size), 1, fp, ptr->off_t_size))
  216. return (-1);
  217. length = (long unsigned)dig_ftell(fp);
  218. G_debug(1, "spidx body offset %lu", length);
  219. if (ptr->spidx_head_size != length)
  220. G_fatal_error("wrong sidx head length %ld", ptr->spidx_head_size);
  221. return (0);
  222. }
  223. /*!
  224. \brief Read spatial index header from sidx file
  225. \param fp pointer to struct gvfile
  226. \param[in,out] ptr pointer to Plus_head structure
  227. \return 0 on success
  228. \return -1 on error
  229. */
  230. int dig_Rd_spidx_head(struct gvfile * fp, struct Plus_head *ptr)
  231. {
  232. unsigned char buf[6];
  233. int byte_order;
  234. struct RTree *t;
  235. dig_rewind(fp);
  236. /* bytes 1 - 6 */
  237. if (0 >= dig__fread_port_C((char *)buf, 6, fp))
  238. return (-1);
  239. ptr->version.spidx.major = buf[0];
  240. ptr->version.spidx.minor = buf[1];
  241. ptr->version.spidx.back_major = buf[2];
  242. ptr->version.spidx.back_minor = buf[3];
  243. byte_order = buf[4];
  244. ptr->spidx_port.off_t_size = buf[5];
  245. G_debug(2,
  246. "Spidx header: file version %d.%d , supported from GRASS version %d.%d",
  247. ptr->version.spidx.major, ptr->version.spidx.minor,
  248. ptr->version.spidx.back_major, ptr->version.spidx.back_minor);
  249. G_debug(2, " byte order %d", byte_order);
  250. /* check version numbers */
  251. if (ptr->version.spidx.major > GV_SIDX_VER_MAJOR ||
  252. ptr->version.spidx.minor > GV_SIDX_VER_MINOR) {
  253. /* The file was created by GRASS library with higher version than this one */
  254. if (ptr->version.spidx.back_major > GV_SIDX_VER_MAJOR ||
  255. ptr->version.spidx.back_minor > GV_SIDX_VER_MINOR) {
  256. /* This version of GRASS lib is lower than the oldest which can read this format */
  257. G_debug(1, "Spatial index format version %d.%d",
  258. ptr->version.spidx.major, ptr->version.spidx.minor);
  259. G_fatal_error
  260. (_("This version of GRASS (%d.%d) is too old to read this spatial index format."
  261. " Try to rebuild topology or upgrade GRASS to at least version %d."),
  262. GRASS_VERSION_MAJOR, GRASS_VERSION_MINOR, GRASS_VERSION_MAJOR + 1);
  263. return (-1);
  264. }
  265. G_warning(_("Your GRASS version does not fully support "
  266. "spatial index format %d.%d of the vector."
  267. " Consider to rebuild topology or upgrade GRASS."),
  268. ptr->version.spidx.major, ptr->version.spidx.minor);
  269. }
  270. if (ptr->version.spidx.major < GV_SIDX_VER_MAJOR ||
  271. (ptr->version.spidx.major == GV_SIDX_VER_MAJOR &&
  272. ptr->version.spidx.minor < GV_SIDX_VER_MINOR)) {
  273. /* The file was created by GRASS library with lower version than this one */
  274. G_fatal_error(_("Spatial index format version %d.%d is not "
  275. "supported by this release."
  276. " Please rebuild topology."),
  277. ptr->version.spidx.major, ptr->version.spidx.minor);
  278. return (-1);
  279. }
  280. /* can this library read the sidx file ? */
  281. if (ptr->spidx_port.off_t_size > (int)sizeof(off_t)) {
  282. G_fatal_error("Spatial index was written with LFS but this "
  283. "GRASS version does not support LFS. "
  284. "Please get a GRASS version with LFS support.");
  285. }
  286. dig_init_portable(&(ptr->spidx_port), byte_order);
  287. dig_set_cur_port(&(ptr->spidx_port));
  288. /* bytes 7 - 10 : header size */
  289. if (0 >= dig__fread_port_L(&(ptr->spidx_head_size), 1, fp))
  290. return (-1);
  291. G_debug(2, " header size %ld", ptr->spidx_head_size);
  292. /* byte 11 : dimension 2D or 3D */
  293. if (0 >= dig__fread_port_C((char *)buf, 1, fp))
  294. return (-1);
  295. ptr->spidx_with_z = buf[0];
  296. G_debug(2, " with_z %d", ptr->spidx_with_z);
  297. /* identical for all spatial indices: */
  298. t = ptr->Node_spidx;
  299. /* byte 12 : n dimensions */
  300. if (0 >= dig__fread_port_C((char *)&(t->ndims), 1, fp))
  301. return (-1);
  302. ptr->Node_spidx->ndims = t->ndims;
  303. ptr->Line_spidx->ndims = t->ndims;
  304. ptr->Area_spidx->ndims = t->ndims;
  305. ptr->Isle_spidx->ndims = t->ndims;
  306. /* byte 13 : n sides */
  307. if (0 >= dig__fread_port_C((char *)&(t->nsides), 1, fp))
  308. return (-1);
  309. ptr->Node_spidx->nsides = t->nsides;
  310. ptr->Line_spidx->nsides = t->nsides;
  311. ptr->Area_spidx->nsides = t->nsides;
  312. ptr->Isle_spidx->nsides = t->nsides;
  313. /* bytes 14 - 17 : nodesize */
  314. if (0 >= dig__fread_port_I(&(t->nodesize), 1, fp))
  315. return (-1);
  316. ptr->Node_spidx->nodesize = t->nodesize;
  317. ptr->Line_spidx->nodesize = t->nodesize;
  318. ptr->Area_spidx->nodesize = t->nodesize;
  319. ptr->Isle_spidx->nodesize = t->nodesize;
  320. /* bytes 18 - 21 : nodecard */
  321. if (0 >= dig__fread_port_I(&(t->nodecard), 1, fp))
  322. return (-1);
  323. ptr->Node_spidx->nodecard = t->nodecard;
  324. ptr->Line_spidx->nodecard = t->nodecard;
  325. ptr->Area_spidx->nodecard = t->nodecard;
  326. ptr->Isle_spidx->nodecard = t->nodecard;
  327. /* bytes 22 - 25 : leafcard */
  328. if (0 >= dig__fread_port_I(&(t->leafcard), 1, fp))
  329. return (-1);
  330. ptr->Node_spidx->leafcard = t->leafcard;
  331. ptr->Line_spidx->leafcard = t->leafcard;
  332. ptr->Area_spidx->leafcard = t->leafcard;
  333. ptr->Isle_spidx->leafcard = t->leafcard;
  334. /* bytes 26 - 29 : min node fill */
  335. if (0 >= dig__fread_port_I(&(t->min_node_fill), 1, fp))
  336. return (-1);
  337. ptr->Node_spidx->min_node_fill = t->min_node_fill;
  338. ptr->Line_spidx->min_node_fill = t->min_node_fill;
  339. ptr->Area_spidx->min_node_fill = t->min_node_fill;
  340. ptr->Isle_spidx->min_node_fill = t->min_node_fill;
  341. /* bytes 30 - 33 : min leaf fill */
  342. if (0 >= dig__fread_port_I(&(t->min_leaf_fill), 1, fp))
  343. return (-1);
  344. ptr->Node_spidx->min_leaf_fill = t->min_leaf_fill;
  345. ptr->Line_spidx->min_leaf_fill = t->min_leaf_fill;
  346. ptr->Area_spidx->min_leaf_fill = t->min_leaf_fill;
  347. ptr->Isle_spidx->min_leaf_fill = t->min_leaf_fill;
  348. /* for each spatial index : */
  349. /* Node spatial index */
  350. /* bytes 34 - 37 : n nodes */
  351. if (0 >= dig__fread_port_I((int *)&(t->n_nodes), 1, fp))
  352. return (-1);
  353. /* bytes 38 - 41 : n leafs */
  354. if (0 >= dig__fread_port_I((int *)&(t->n_leafs), 1, fp))
  355. return (-1);
  356. /* bytes 42 - 45 : n levels */
  357. if (0 >= dig__fread_port_I(&(t->rootlevel), 1, fp))
  358. return (-1);
  359. /* bytes 46 - 49 (LFS 53) : root node offset */
  360. if (0 >=
  361. dig__fread_port_O(&(ptr->Node_spidx_offset), 1, fp,
  362. ptr->spidx_port.off_t_size))
  363. return (-1);
  364. t->rootpos = ptr->Node_spidx_offset;
  365. /* Line spatial index */
  366. t = ptr->Line_spidx;
  367. /* bytes 50 - 53 (LFS 54 - 57) : n nodes */
  368. if (0 >= dig__fread_port_I((int *)&(t->n_nodes), 1, fp))
  369. return (-1);
  370. /* bytes 54 - 57 (LFS 58 - 61) : n leafs */
  371. if (0 >= dig__fread_port_I((int *)&(t->n_leafs), 1, fp))
  372. return (-1);
  373. /* bytes 58 - 61 (LFS 62 - 65) : n levels */
  374. if (0 >= dig__fread_port_I(&(t->rootlevel), 1, fp))
  375. return (-1);
  376. /* bytes 62 - 65 (LFS 66 - 73) : root node offset */
  377. if (0 >=
  378. dig__fread_port_O(&(ptr->Line_spidx_offset), 1, fp,
  379. ptr->spidx_port.off_t_size))
  380. return (-1);
  381. ptr->Line_spidx->rootpos = ptr->Line_spidx_offset;
  382. /* Area spatial index */
  383. t = ptr->Area_spidx;
  384. /* bytes 66 - 69 (LFS 74 - 77) : n nodes */
  385. if (0 >= dig__fread_port_I((int *)&(t->n_nodes), 1, fp))
  386. return (-1);
  387. /* bytes 70 - 73 (LFS 78 - 81) : n leafs */
  388. if (0 >= dig__fread_port_I((int *)&(t->n_leafs), 1, fp))
  389. return (-1);
  390. /* bytes 74 - 77 (LFS 82 - 85) : n levels */
  391. if (0 >= dig__fread_port_I(&(t->rootlevel), 1, fp))
  392. return (-1);
  393. /* bytes 78 - 81 (LFS 86 - 93) : root node offset */
  394. if (0 >=
  395. dig__fread_port_O(&(ptr->Area_spidx_offset), 1, fp,
  396. ptr->spidx_port.off_t_size))
  397. return (-1);
  398. ptr->Area_spidx->rootpos = ptr->Area_spidx_offset;
  399. /* Isle spatial index */
  400. t = ptr->Isle_spidx;
  401. /* bytes 82 - 85 (LFS 94 - 97) : n nodes */
  402. if (0 >= dig__fread_port_I((int *)&(t->n_nodes), 1, fp))
  403. return (-1);
  404. /* bytes 86 - 89 (LFS 98 - 101) : n leafs */
  405. if (0 >= dig__fread_port_I((int *)&(t->n_leafs), 1, fp))
  406. return (-1);
  407. /* bytes 90 - 93 (LFS 102 - 105) : n levels */
  408. if (0 >= dig__fread_port_I(&(t->rootlevel), 1, fp))
  409. return (-1);
  410. /* bytes 94 - 97 (LFS 106 - 113) : root node offset */
  411. if (0 >=
  412. dig__fread_port_O(&(ptr->Isle_spidx_offset), 1, fp,
  413. ptr->spidx_port.off_t_size))
  414. return (-1);
  415. ptr->Isle_spidx->rootpos = ptr->Isle_spidx_offset;
  416. /* 3D future : */
  417. /* Face spatial index */
  418. /* bytes 98 - 101 (LFS 114 - 121) : root node offset */
  419. if (0 >=
  420. dig__fread_port_O(&(ptr->Face_spidx_offset), 1, fp,
  421. ptr->spidx_port.off_t_size))
  422. return (-1);
  423. /* ptr->Face_spidx->rootpos = ptr->Face_spidx_offset; */
  424. /* Volume spatial index */
  425. /* bytes 102 - 105 (LFS 122 - 129) : root node offset */
  426. if (0 >=
  427. dig__fread_port_O(&(ptr->Volume_spidx_offset), 1, fp,
  428. ptr->spidx_port.off_t_size))
  429. return (-1);
  430. /* ptr->Volume_spidx->rootpos = ptr->Volume_spidx_offset; */
  431. /* Hole spatial index */
  432. /* bytes 106 - 109 (LFS 130 - 137) : root node offset */
  433. if (0 >=
  434. dig__fread_port_O(&(ptr->Hole_spidx_offset), 1, fp,
  435. ptr->spidx_port.off_t_size))
  436. return (-1);
  437. /* ptr->Hole_spidx->rootpos = ptr->Hole_spidx_offset; */
  438. /* coor file size : bytes 110 - 113 (117) (LFS: 138 - 145) */
  439. if (ptr->off_t_size == -1)
  440. ptr->off_t_size = ptr->spidx_port.off_t_size;
  441. if (0 >= dig__fread_port_O(&(ptr->coor_size), 1, fp, ptr->off_t_size))
  442. return (-1);
  443. G_debug(2, " coor size %lu", (long unsigned)ptr->coor_size);
  444. dig_fseek(fp, ptr->spidx_head_size, SEEK_SET);
  445. return (0);
  446. }
  447. static int rtree_dump_node(FILE *, struct RTree_Node *n, int);
  448. /*!
  449. \brief Dump R-tree branch to the file
  450. \param fp pointer to FILE
  451. \param b pointer to Branch structure
  452. \param with_z non-zero value for 3D vector data
  453. \param level level value
  454. \return 0
  455. */
  456. static int rtree_dump_branch(FILE * fp, struct RTree_Branch *b, int with_z,
  457. int level)
  458. {
  459. const struct RTree_Rect *r;
  460. r = &(b->rect);
  461. if (level == 0)
  462. fprintf(fp, " id = %d ", b->child.id);
  463. fprintf(fp, " %f %f %f %f %f %f\n", r->boundary[0], r->boundary[1],
  464. r->boundary[2], r->boundary[3], r->boundary[4], r->boundary[5]);
  465. if (level > 0) {
  466. rtree_dump_node(fp, b->child.ptr, with_z);
  467. }
  468. return 0;
  469. }
  470. /*!
  471. \brief Dump R-tree node to the file
  472. \param fp pointer to FILE
  473. \param n pointer to Node structure
  474. \param with_z non-zero value for 3D vector data
  475. \return 0
  476. */
  477. int rtree_dump_node(FILE * fp, struct RTree_Node *n, int with_z)
  478. {
  479. int i;
  480. /* recursive nearly-but-a-bit-messy depth-first pre-order traversal
  481. * potentially filling up memory */
  482. /* TODO: change to non-recursive depth-first post-order traversal */
  483. /* left for comparison with GRASS6.x */
  484. fprintf(fp, "Node level=%d count=%d\n", n->level, n->count);
  485. if (n->level > 0)
  486. for (i = 0; i < NODECARD; i++) {
  487. if (n->branch[i].child.ptr) {
  488. fprintf(fp, " Branch %d", i);
  489. rtree_dump_branch(fp, &n->branch[i], with_z, n->level);
  490. }
  491. }
  492. else
  493. for (i = 0; i < LEAFCARD; i++) {
  494. if (n->branch[i].child.id) {
  495. fprintf(fp, " Branch %d", i);
  496. rtree_dump_branch(fp, &n->branch[i], with_z, n->level);
  497. }
  498. }
  499. return 0;
  500. }
  501. static int rtree_dump_node_file(FILE *, off_t, int, struct RTree *);
  502. /*!
  503. \brief Dump R-tree branch from temp file to the file
  504. \param fp pointer to FILE
  505. \param b pointer to Branch structure
  506. \param with_z non-zero value for 3D vector data
  507. \param level level value
  508. \return 0
  509. */
  510. static int rtree_dump_branch_file(FILE * fp, struct RTree_Branch *b, int with_z,
  511. int level, struct RTree *t)
  512. {
  513. const struct RTree_Rect *r;
  514. r = &(b->rect);
  515. if (level == 0)
  516. fprintf(fp, " id = %d ", b->child.id);
  517. fprintf(fp, " %f %f %f %f %f %f\n", r->boundary[0], r->boundary[1],
  518. r->boundary[2], r->boundary[3], r->boundary[4], r->boundary[5]);
  519. if (level > 0) {
  520. rtree_dump_node_file(fp, b->child.pos, with_z, t);
  521. }
  522. return 0;
  523. }
  524. /*!
  525. \brief Dump R-tree node from temp file to the file
  526. \param fp pointer to FILE
  527. \param pos position of Node in temp file
  528. \param with_z non-zero value for 3D vector data
  529. \param t RTree to dump
  530. \return 0
  531. */
  532. int rtree_dump_node_file(FILE * fp, off_t pos, int with_z, struct RTree *t)
  533. {
  534. int i;
  535. static struct RTree_Node *n = NULL;
  536. if (!n) {
  537. n = RTreeAllocNode(t, 1);
  538. }
  539. /* recursive nearly-but-a-bit-messy depth-first pre-order traversal
  540. * potentially filling up memory */
  541. /* TODO: change to non-recursive depth-first post-order traversal */
  542. /* left for comparison with GRASS6.x */
  543. RTreeReadNode(n, pos, t);
  544. fprintf(fp, "Node level=%d count=%d\n", n->level, n->count);
  545. if (n->level > 0)
  546. for (i = 0; i < NODECARD; i++) {
  547. if (n->branch[i].child.pos >= 0) {
  548. fprintf(fp, " Branch %d", i);
  549. rtree_dump_branch_file(fp, &(n->branch[i]), with_z, n->level, t);
  550. }
  551. }
  552. else
  553. for (i = 0; i < LEAFCARD; i++) {
  554. if (n->branch[i].child.id) {
  555. fprintf(fp, " Branch %d", i);
  556. rtree_dump_branch_file(fp, &(n->branch[i]), with_z, n->level, t);
  557. }
  558. }
  559. return 0;
  560. }
  561. /*
  562. * all following methods to transfer spatial indices (rtrees) are based
  563. * on the same idea
  564. * do a postorder depth-first non-recursive traversal of the rtree
  565. * a leaf node is transferred first
  566. * the root node is transferred last
  567. *
  568. * this applies to all four scenarios
  569. * - from intermediate file to sidx file
  570. * - from sidx file to intermediate file
  571. * - from memory to sidx file
  572. * - from sidx file to memory
  573. *
  574. * I could not think of one function that's good for all four scenarios,
  575. * but that doesn't mean there is none...
  576. *
  577. * maybe something like V2_read_line_array and Write_line_array
  578. * in Vlib/read.c and Vlib/write.c, at least for transferring from sidx
  579. * and transferrring to sidx?
  580. */
  581. /*!
  582. \brief Write RTree body from memory to sidx file
  583. Must be called when new or updated vector is closed
  584. \param[out] fp pointer to struct gvfile
  585. \param startpos offset to struct gvfile where to start writing out
  586. \param t pointer to RTree
  587. \param off_t_size size of off_t used to write struct gvfile
  588. \return -1 on error
  589. \return offset to root node on success
  590. */
  591. static off_t rtree_write_from_memory(struct gvfile *fp, off_t startpos,
  592. struct RTree *t, int off_t_size)
  593. {
  594. off_t nextfreepos = startpos;
  595. int sidx_nodesize, sidx_leafsize;
  596. struct RTree_Node *n;
  597. int i, j, writeout, maxcard;
  598. struct spidxpstack *s = G_malloc(MAXLEVEL * sizeof(struct spidxstack));
  599. int top = 0;
  600. /* should be foolproof */
  601. sidx_nodesize =
  602. (int)(2 * PORT_INT + t->nodecard * (off_t_size + NUMSIDES * PORT_DOUBLE));
  603. sidx_leafsize =
  604. (int)(2 * PORT_INT + t->leafcard * (off_t_size + NUMSIDES * PORT_DOUBLE));
  605. /* stack size of t->rootlevel + 1 would be enough because of
  606. * depth-first post-order traversal:
  607. * only one node per level on stack at any given time */
  608. /* add root node position to stack */
  609. s[top].branch_id = i = 0;
  610. s[top].sn = t->root;
  611. /* depth-first postorder traversal
  612. * all children of a node are visitied and written out first
  613. * when a child is written out, its position in file is stored in pos[] for
  614. * the parent node and written out with the parent node */
  615. /* root node is written out last and its position returned */
  616. while (top >= 0) {
  617. if (s[top].sn == NULL)
  618. G_fatal_error("NULL node ptr at top = %d", top);
  619. n = s[top].sn;
  620. writeout = 1;
  621. /* this is an internal node in the RTree
  622. * all its children are processed first,
  623. * before it is written out to the sidx file */
  624. if (s[top].sn->level > 0) {
  625. for (i = s[top].branch_id; i < t->nodecard; i++) {
  626. s[top].pos[i] = 0;
  627. if (n->branch[i].child.ptr != NULL) {
  628. s[top++].branch_id = i + 1;
  629. s[top].sn = n->branch[i].child.ptr;
  630. s[top].branch_id = 0;
  631. writeout = 0;
  632. break;
  633. }
  634. }
  635. if (writeout) {
  636. /* nothing else found, ready to write out */
  637. s[top].branch_id = t->nodecard;
  638. }
  639. }
  640. if (writeout) {
  641. /* write node to sidx file */
  642. if (G_ftell(fp->file) != nextfreepos)
  643. G_fatal_error("Unable to write spatial index. "
  644. "Wrong node position (%"PRI_OFF_T") in file (should be %"PRI_OFF_T").",
  645. G_ftell(fp->file), nextfreepos);
  646. /* write with dig__fwrite_port_* fns */
  647. dig__fwrite_port_I(&(s[top].sn->count), 1, fp);
  648. dig__fwrite_port_I(&(s[top].sn->level), 1, fp);
  649. maxcard = s[top].sn->level ? t->nodecard : t->leafcard;
  650. for (j = 0; j < maxcard; j++) {
  651. dig__fwrite_port_D(s[top].sn->branch[j].rect.boundary,
  652. NUMSIDES, fp);
  653. /* leaf node: vector object IDs are stored in child.id */
  654. if (s[top].sn->level == 0)
  655. s[top].pos[j] = (off_t) s[top].sn->branch[j].child.id;
  656. dig__fwrite_port_O(&(s[top].pos[j]), 1, fp, off_t_size);
  657. }
  658. top--;
  659. /* update corresponding child position of parent node
  660. * this node is only updated if its level is > 0, i.e.
  661. * this is an internal node
  662. * children of internal nodes do not have an ID, instead
  663. * they hold the position in file of the next nodes down the tree */
  664. if (top >= 0) {
  665. s[top].pos[s[top].branch_id - 1] = nextfreepos;
  666. nextfreepos += (s[top + 1].sn->level ? sidx_nodesize : sidx_leafsize);
  667. }
  668. }
  669. }
  670. G_free(s);
  671. return nextfreepos;
  672. }
  673. /*!
  674. \brief Write RTree body from temporary file to sidx file
  675. Must be called when new or updated vector is closed
  676. \param[out] fp pointer to struct gvfile
  677. \param startpos offset to struct gvfile where to start writing out
  678. \param t pointer to RTree
  679. \param off_t_size size of off_t used to write struct gvfile
  680. \return -1 on error
  681. \return offset to root node on success
  682. */
  683. static off_t rtree_write_from_file(struct gvfile *fp, off_t startpos,
  684. struct RTree *t, int off_t_size)
  685. {
  686. off_t nextfreepos = startpos;
  687. int sidx_nodesize, sidx_leafsize;
  688. struct RTree_Node *n;
  689. int i, j, writeout, maxcard;
  690. static struct spidxstack *s = NULL;
  691. int top = 0;
  692. if (!s) {
  693. s = G_malloc(MAXLEVEL * sizeof(struct spidxstack));
  694. for (i = 0; i < MAXLEVEL; i++) {
  695. s[i].sn.branch = G_malloc(MAXCARD * sizeof(struct RTree_Branch));
  696. for (j = 0; j < MAXCARD; j++) {
  697. s[i].sn.branch[j].rect.boundary = G_malloc(6 * sizeof(RectReal));
  698. }
  699. }
  700. }
  701. /* write pending changes to file */
  702. RTreeFlushBuffer(t);
  703. /* should be foolproof */
  704. sidx_nodesize =
  705. (int)(2 * PORT_INT + t->nodecard * (off_t_size + NUMSIDES * PORT_DOUBLE));
  706. sidx_leafsize =
  707. (int)(2 * PORT_INT + t->leafcard * (off_t_size + NUMSIDES * PORT_DOUBLE));
  708. /* stack size of t->rootlevel + 1 would be enough because of
  709. * depth-first post-order traversal:
  710. * only one node per level on stack at any given time */
  711. /* add root node position to stack */
  712. s[top].branch_id = i = 0;
  713. RTreeReadNode(&s[top].sn, t->rootpos, t);
  714. /* depth-first postorder traversal
  715. * all children of a node are visitied and written out first
  716. * when a child is written out, its position in file is stored in pos[] for
  717. * the parent node and written out with the parent node */
  718. /* root node is written out last and its position returned */
  719. while (top >= 0) {
  720. n = &(s[top].sn);
  721. writeout = 1;
  722. /* this is an internal node in the RTree
  723. * all its children are processed first,
  724. * before it is written out to the sidx file */
  725. if (s[top].sn.level > 0) {
  726. for (i = s[top].branch_id; i < t->nodecard; i++) {
  727. s[top].pos[i] = 0;
  728. if (n->branch[i].child.pos >= 0) {
  729. s[top++].branch_id = i + 1;
  730. RTreeReadNode(&s[top].sn, n->branch[i].child.pos, t);
  731. s[top].branch_id = 0;
  732. writeout = 0;
  733. break;
  734. }
  735. }
  736. if (writeout) {
  737. /* nothing else found, ready to write out */
  738. s[top].branch_id = t->nodecard;
  739. }
  740. }
  741. if (writeout) {
  742. /* write node to sidx file */
  743. if (G_ftell(fp->file) != nextfreepos)
  744. G_fatal_error("Unable to write spatial index. "
  745. "Wrong node position (%"PRI_OFF_T") in file (should be %"PRI_OFF_T").",
  746. G_ftell(fp->file), nextfreepos);
  747. /* write with dig__fwrite_port_* fns */
  748. dig__fwrite_port_I(&(s[top].sn.count), 1, fp);
  749. dig__fwrite_port_I(&(s[top].sn.level), 1, fp);
  750. maxcard = s[top].sn.level ? t->nodecard : t->leafcard;
  751. for (j = 0; j < maxcard; j++) {
  752. dig__fwrite_port_D(s[top].sn.branch[j].rect.boundary,
  753. NUMSIDES, fp);
  754. /* leaf node: vector object IDs are stored in child.id */
  755. if (s[top].sn.level == 0)
  756. s[top].pos[j] = (off_t) s[top].sn.branch[j].child.id;
  757. dig__fwrite_port_O(&(s[top].pos[j]), 1, fp, off_t_size);
  758. }
  759. top--;
  760. /* update corresponding child position of parent node
  761. * this node is only updated if its level is > 0, i.e.
  762. * this is an internal node
  763. * children of internal nodes do not have an ID, instead
  764. * they hold the position in file of the next nodes down the tree */
  765. if (top >= 0) {
  766. s[top].pos[s[top].branch_id - 1] = nextfreepos;
  767. nextfreepos += (s[top + 1].sn.level ? sidx_nodesize : sidx_leafsize);
  768. }
  769. }
  770. }
  771. close(t->fd);
  772. return nextfreepos;
  773. }
  774. /* write RTree body to sidx file */
  775. static off_t rtree_write_to_sidx(struct gvfile *fp, off_t startpos,
  776. struct RTree *t, int off_t_size)
  777. {
  778. if (t->fd > -1)
  779. return rtree_write_from_file(fp, startpos, t, off_t_size);
  780. else
  781. return rtree_write_from_memory(fp, startpos, t, off_t_size);
  782. }
  783. /*!
  784. \brief Load RTree body from sidx file to memory
  785. Must be called when old vector is opened in update mode
  786. \param fp pointer to struct gvfile
  787. \param rootpos position of root node in file
  788. \param t pointer to RTree
  789. \param off_t_size size of off_t used to read struct gvfile
  790. \return pointer to root node on success
  791. */
  792. static void rtree_load_to_memory(struct gvfile *fp, off_t rootpos,
  793. struct RTree *t, int off_t_size)
  794. {
  795. struct RTree_Node *newnode = NULL;
  796. int i, j, loadnode, maxcard;
  797. struct spidxstack *last;
  798. static struct spidxstack *s = NULL;
  799. int top = 0;
  800. if (!s) {
  801. s = G_malloc(MAXLEVEL * sizeof(struct spidxstack));
  802. for (i = 0; i < MAXLEVEL; i++) {
  803. s[i].sn.branch = G_malloc(MAXCARD * sizeof(struct RTree_Branch));
  804. for (j = 0; j < MAXCARD; j++) {
  805. s[i].sn.branch[j].rect.boundary = G_malloc(6 * sizeof(RectReal));
  806. }
  807. }
  808. }
  809. /* stack size of t->rootlevel + 1 would be enough because of
  810. * depth-first postorder traversal:
  811. * only one node per level on stack at any given time */
  812. /* add root node position to stack */
  813. last = &(s[top]);
  814. G_fseek(fp->file, rootpos, SEEK_SET);
  815. /* read with dig__fread_port_* fns */
  816. dig__fread_port_I(&(s[top].sn.count), 1, fp);
  817. dig__fread_port_I(&(s[top].sn.level), 1, fp);
  818. maxcard = s[top].sn.level ? t->nodecard : t->leafcard;
  819. for (j = 0; j < maxcard; j++) {
  820. dig__fread_port_D(s[top].sn.branch[j].rect.boundary, NUMSIDES, fp);
  821. dig__fread_port_O(&(s[top].pos[j]), 1, fp, off_t_size);
  822. /* leaf node: vector object IDs are stored in child.id */
  823. if (s[top].sn.level == 0) {
  824. s[top].sn.branch[j].child.id = (int)s[top].pos[j];
  825. }
  826. else {
  827. s[top].sn.branch[j].child.ptr = NULL;
  828. }
  829. }
  830. s[top].branch_id = i = 0;
  831. /* some sort of postorder traversal */
  832. /* root node is loaded last and returned */
  833. while (top >= 0) {
  834. last = &(s[top]);
  835. loadnode = 1;
  836. /* this is an internal node in the RTree
  837. * all its children are read first,
  838. * before it is transferred to the RTree in memory */
  839. if (s[top].sn.level > 0) {
  840. for (i = s[top].branch_id; i < t->nodecard; i++) {
  841. if (s[top].pos[i] > 0) {
  842. s[top++].branch_id = i + 1;
  843. G_fseek(fp->file, last->pos[i], SEEK_SET);
  844. /* read with dig__fread_port_* fns */
  845. dig__fread_port_I(&(s[top].sn.count), 1, fp);
  846. dig__fread_port_I(&(s[top].sn.level), 1, fp);
  847. maxcard = s[top].sn.level ? t->nodecard : t->leafcard;
  848. for (j = 0; j < maxcard; j++) {
  849. dig__fread_port_D(s[top].sn.branch[j].rect.boundary,
  850. NUMSIDES, fp);
  851. dig__fread_port_O(&(s[top].pos[j]), 1, fp,
  852. off_t_size);
  853. /* leaf node
  854. * vector object IDs are stored in file as
  855. * off_t but always fit into an int, see dig_structs.h
  856. * vector object IDs are transferred to child.id */
  857. if (s[top].sn.level == 0) {
  858. s[top].sn.branch[j].child.id =
  859. (int)s[top].pos[j];
  860. }
  861. else {
  862. s[top].sn.branch[j].child.ptr = NULL;
  863. }
  864. }
  865. s[top].branch_id = 0;
  866. loadnode = 0;
  867. break;
  868. }
  869. else if (last->pos[i] < 0)
  870. G_fatal_error("corrupt spatial index");
  871. }
  872. if (loadnode) {
  873. /* nothing else found, ready to load */
  874. s[top].branch_id = t->nodecard;
  875. }
  876. }
  877. if (loadnode) {
  878. /* ready to load node to memory */
  879. newnode = RTreeAllocNode(t, s[top].sn.level);
  880. /* copy from stack node */
  881. RTreeCopyNode(newnode, &(s[top].sn), t);
  882. top--;
  883. /* update child of parent node
  884. * this node is only updated if its level is > 0, i.e.
  885. * this is an internal node
  886. * children of internal nodes do not have an ID, instead
  887. * they point to the next nodes down the tree */
  888. if (top >= 0) {
  889. s[top].sn.branch[s[top].branch_id - 1].child.ptr = newnode;
  890. }
  891. }
  892. }
  893. t->root = newnode;
  894. }
  895. /*!
  896. \brief Load RTree body from sidx file to temporary file
  897. Must be called when old vector is opened in update mode
  898. \param fp pointer to struct gvfile
  899. \param rootpos position of root node in file
  900. \param t pointer to RTree
  901. \param off_t_size size of off_t used to read struct gvfile
  902. \return offset to root node
  903. */
  904. static void rtree_load_to_file(struct gvfile *fp, off_t rootpos,
  905. struct RTree *t, int off_t_size)
  906. {
  907. off_t newnode_pos = -1;
  908. int i, j, loadnode, maxcard;
  909. struct spidxstack *last;
  910. static struct spidxstack *s = NULL;
  911. int top = 0;
  912. if (!s) {
  913. s = G_malloc(MAXLEVEL * sizeof(struct spidxstack));
  914. for (i = 0; i < MAXLEVEL; i++) {
  915. s[i].sn.branch = G_malloc(MAXCARD * sizeof(struct RTree_Branch));
  916. for (j = 0; j < MAXCARD; j++) {
  917. s[i].sn.branch[j].rect.boundary = G_malloc(6 * sizeof(RectReal));
  918. }
  919. }
  920. }
  921. /* stack size of t->rootlevel + 1 would be enough because of
  922. * depth-first postorder traversal:
  923. * only one node per level on stack at any given time */
  924. /* add root node position to stack */
  925. last = &(s[top]);
  926. G_fseek(fp->file, rootpos, SEEK_SET);
  927. /* read with dig__fread_port_* fns */
  928. dig__fread_port_I(&(s[top].sn.count), 1, fp);
  929. dig__fread_port_I(&(s[top].sn.level), 1, fp);
  930. maxcard = t->rootlevel ? t->nodecard : t->leafcard;
  931. for (j = 0; j < maxcard; j++) {
  932. dig__fread_port_D(s[top].sn.branch[j].rect.boundary, NUMSIDES, fp);
  933. dig__fread_port_O(&(s[top].pos[j]), 1, fp, off_t_size);
  934. /* leaf node: vector object IDs are stored in child.id */
  935. if (s[top].sn.level == 0) {
  936. s[top].sn.branch[j].child.id = (int)s[top].pos[j];
  937. }
  938. else {
  939. s[top].sn.branch[j].child.pos = -1;
  940. }
  941. }
  942. s[top].branch_id = i = 0;
  943. /* depth-first postorder traversal */
  944. /* root node is loaded last and returned */
  945. while (top >= 0) {
  946. last = &(s[top]);
  947. loadnode = 1;
  948. /* this is an internal node in the RTree
  949. * all its children are read first,
  950. * before it is transferred to the RTree in memory */
  951. if (s[top].sn.level > 0) {
  952. for (i = s[top].branch_id; i < t->nodecard; i++) {
  953. if (s[top].pos[i] > 0) {
  954. s[top++].branch_id = i + 1;
  955. G_fseek(fp->file, last->pos[i], SEEK_SET);
  956. /* read with dig__fread_port_* fns */
  957. dig__fread_port_I(&(s[top].sn.count), 1, fp);
  958. dig__fread_port_I(&(s[top].sn.level), 1, fp);
  959. maxcard = s[top].sn.level ? t->nodecard : t->leafcard;
  960. for (j = 0; j < maxcard; j++) {
  961. dig__fread_port_D(s[top].sn.branch[j].rect.boundary,
  962. NUMSIDES, fp);
  963. dig__fread_port_O(&(s[top].pos[j]), 1, fp,
  964. off_t_size);
  965. /* leaf node
  966. * vector object IDs are stored in file as
  967. * off_t but always fit into an int, see dig_structs.h
  968. * vector object IDs are transferred to child.id */
  969. if (s[top].sn.level == 0) {
  970. s[top].sn.branch[j].child.id =
  971. (int)s[top].pos[j];
  972. }
  973. else {
  974. s[top].sn.branch[j].child.pos = -1;
  975. }
  976. }
  977. s[top].branch_id = 0;
  978. loadnode = 0;
  979. break;
  980. }
  981. else if (last->pos[i] < 0)
  982. G_fatal_error("corrupt spatial index");
  983. }
  984. if (loadnode) {
  985. /* nothing else found, ready to load */
  986. s[top].branch_id = t->nodecard;
  987. }
  988. }
  989. if (loadnode) {
  990. /* ready to load node and write to temp file */
  991. newnode_pos = RTreeGetNodePos(t);
  992. RTreeWriteNode(&(s[top].sn), t);
  993. top--;
  994. /* update child of parent node
  995. * this node is only updated if its level is > 0, i.e.
  996. * this is an internal node
  997. * children of internal nodes do not have an ID, instead
  998. * they point to the next nodes down the tree */
  999. if (top >= 0) {
  1000. s[top].sn.branch[s[top].branch_id - 1].child.pos = newnode_pos;
  1001. }
  1002. }
  1003. }
  1004. t->rootpos = newnode_pos;
  1005. }
  1006. static void rtree_load_from_sidx(struct gvfile *fp, off_t rootpos,
  1007. struct RTree *t, int off_t_size)
  1008. {
  1009. if (t->fd > -1)
  1010. return rtree_load_to_file(fp, rootpos, t, off_t_size);
  1011. else
  1012. return rtree_load_to_memory(fp, rootpos, t, off_t_size);
  1013. }
  1014. /*!
  1015. \brief Write spatial index to file
  1016. \param[out] fp pointer to struct gvfile
  1017. \param Plus pointer to Plus_head structure
  1018. \return 0
  1019. */
  1020. int dig_Wr_spidx(struct gvfile *fp, struct Plus_head *Plus)
  1021. {
  1022. G_debug(1, "dig_Wr_spidx()");
  1023. dig_set_cur_port(&(Plus->spidx_port));
  1024. dig_rewind(fp);
  1025. dig_Wr_spidx_head(fp, Plus);
  1026. /* Nodes */
  1027. Plus->Node_spidx_offset =
  1028. rtree_write_to_sidx(fp, dig_ftell(fp), Plus->Node_spidx,
  1029. Plus->spidx_port.off_t_size);
  1030. /* Lines */
  1031. Plus->Line_spidx_offset =
  1032. rtree_write_to_sidx(fp, dig_ftell(fp), Plus->Line_spidx,
  1033. Plus->spidx_port.off_t_size);
  1034. /* Areas */
  1035. Plus->Area_spidx_offset =
  1036. rtree_write_to_sidx(fp, dig_ftell(fp), Plus->Area_spidx,
  1037. Plus->spidx_port.off_t_size);
  1038. /* Isles */
  1039. Plus->Isle_spidx_offset =
  1040. rtree_write_to_sidx(fp, dig_ftell(fp), Plus->Isle_spidx,
  1041. Plus->spidx_port.off_t_size);
  1042. /* 3D future : */
  1043. /* Faces */
  1044. /* Volumes */
  1045. /* Holes */
  1046. dig_rewind(fp);
  1047. dig_Wr_spidx_head(fp, Plus); /* rewrite with offsets */
  1048. dig_fflush(fp);
  1049. return 0;
  1050. }
  1051. /*!
  1052. \brief Read spatial index from sidx file
  1053. Only needed when old vector is opened in update mode
  1054. \param fp pointer to struct gvfile
  1055. \param[in,out] Plus pointer to Plus_head structure
  1056. \return 0
  1057. */
  1058. int dig_Rd_spidx(struct gvfile * fp, struct Plus_head *Plus)
  1059. {
  1060. G_debug(1, "dig_read_spindx()");
  1061. /* free old trees, init new trees */
  1062. dig_spidx_free(Plus);
  1063. dig_spidx_init(Plus);
  1064. dig_rewind(fp);
  1065. dig_Rd_spidx_head(fp, Plus);
  1066. dig_set_cur_port(&(Plus->spidx_port));
  1067. /* Nodes */
  1068. rtree_load_from_sidx(fp, Plus->Node_spidx_offset,
  1069. Plus->Node_spidx, Plus->spidx_port.off_t_size);
  1070. /* Lines */
  1071. rtree_load_from_sidx(fp, Plus->Line_spidx_offset,
  1072. Plus->Line_spidx, Plus->spidx_port.off_t_size);
  1073. /* Areas */
  1074. rtree_load_from_sidx(fp, Plus->Area_spidx_offset,
  1075. Plus->Area_spidx, Plus->spidx_port.off_t_size);
  1076. /* Isles */
  1077. rtree_load_from_sidx(fp, Plus->Isle_spidx_offset,
  1078. Plus->Isle_spidx, Plus->spidx_port.off_t_size);
  1079. /* 3D future : */
  1080. /* Faces */
  1081. /* Volumes */
  1082. /* Holes */
  1083. return 0;
  1084. }
  1085. /*!
  1086. \brief Dump spatial index
  1087. \param[out] fp pointer to FILE
  1088. \param Plus pointer to Plus_head structure
  1089. \return 0
  1090. */
  1091. int dig_dump_spidx(FILE * fp, const struct Plus_head *Plus)
  1092. {
  1093. fprintf(fp, "Nodes\n");
  1094. if (Plus->Node_spidx->fd < 0)
  1095. rtree_dump_node(fp, Plus->Node_spidx->root, Plus->with_z);
  1096. else {
  1097. RTreeFlushBuffer(Plus->Node_spidx);
  1098. rtree_dump_node_file(fp, Plus->Node_spidx->rootpos, Plus->with_z,
  1099. Plus->Node_spidx);
  1100. }
  1101. fprintf(fp, "Lines\n");
  1102. if (Plus->Line_spidx->fd < 0)
  1103. rtree_dump_node(fp, Plus->Line_spidx->root, Plus->with_z);
  1104. else {
  1105. RTreeFlushBuffer(Plus->Line_spidx);
  1106. rtree_dump_node_file(fp, Plus->Line_spidx->rootpos, Plus->with_z,
  1107. Plus->Line_spidx);
  1108. }
  1109. fprintf(fp, "Areas\n");
  1110. if (Plus->Area_spidx->fd < 0)
  1111. rtree_dump_node(fp, Plus->Area_spidx->root, Plus->with_z);
  1112. else {
  1113. RTreeFlushBuffer(Plus->Area_spidx);
  1114. rtree_dump_node_file(fp, Plus->Area_spidx->rootpos, Plus->with_z,
  1115. Plus->Area_spidx);
  1116. }
  1117. fprintf(fp, "Isles\n");
  1118. if (Plus->Isle_spidx->fd < 0)
  1119. rtree_dump_node(fp, Plus->Isle_spidx->root, Plus->with_z);
  1120. else {
  1121. RTreeFlushBuffer(Plus->Isle_spidx);
  1122. rtree_dump_node_file(fp, Plus->Isle_spidx->rootpos, Plus->with_z,
  1123. Plus->Isle_spidx);
  1124. }
  1125. return 0;
  1126. }
  1127. /* read node from file */
  1128. static void rtree_read_node(struct NodeBuffer *nb,
  1129. off_t nodepos, struct RTree *t, struct Plus_head *Plus)
  1130. {
  1131. int i, maxcard;
  1132. off_t pos;
  1133. struct gvfile *file = &(Plus->spidx_fp);
  1134. dig_fseek(file, nodepos, SEEK_SET);
  1135. /* read with dig__fread_port_* fns */
  1136. dig__fread_port_I(&(nb->n.count), 1, file);
  1137. dig__fread_port_I(&(nb->n.level), 1, file);
  1138. maxcard = nb->n.level ? t->nodecard : t->leafcard;
  1139. for (i = 0; i < maxcard; i++) {
  1140. dig__fread_port_D(nb->n.branch[i].rect.boundary, NUMSIDES,
  1141. file);
  1142. dig__fread_port_O(&pos, 1, file,
  1143. Plus->spidx_port.off_t_size);
  1144. /* leaf node: vector object IDs are stored in child.id */
  1145. if (nb->n.level == 0) {
  1146. nb->n.branch[i].child.id = (int)pos;
  1147. }
  1148. else {
  1149. nb->n.branch[i].child.pos = pos;
  1150. }
  1151. }
  1152. }
  1153. /* get node from buffer or file */
  1154. static struct RTree_Node *rtree_get_node(off_t nodepos, int level,
  1155. struct RTree *t,
  1156. struct Plus_head *Plus)
  1157. {
  1158. int which, i = 0;
  1159. /* check mru first */
  1160. /* t->used[level][i] */
  1161. while (t->nb[level][t->used[level][i]].pos != nodepos &&
  1162. t->nb[level][t->used[level][i]].pos >= 0 &&
  1163. i < NODE_BUFFER_SIZE - 1) {
  1164. i++;
  1165. }
  1166. which = t->used[level][i];
  1167. if (t->nb[level][which].pos != nodepos) {
  1168. rtree_read_node(&(t->nb[level][which]), nodepos, t, Plus);
  1169. t->nb[level][which].pos = nodepos;
  1170. }
  1171. assert(t->nb[level][which].n.level == level);
  1172. /* make it mru */
  1173. if (i) { /* t->used[level][0] != which */
  1174. #if 0
  1175. t->used[level][i] = t->used[level][0];
  1176. t->used[level][0] = which;
  1177. #else
  1178. while (i) {
  1179. t->used[level][i] = t->used[level][i - 1];
  1180. i--;
  1181. }
  1182. t->used[level][0] = which;
  1183. #endif
  1184. }
  1185. return &(t->nb[level][which].n);
  1186. }
  1187. /*!
  1188. \brief Search spatial index file
  1189. Can't use regular RTreeSearch() here because sidx must be read
  1190. with dig__fread_port_*() functions
  1191. \param t pointer to RTree
  1192. \param r search rectangle
  1193. \param shcb user-provided callback
  1194. \param cbarg argument for shcb
  1195. \param Plus pointer to Plus_head structure
  1196. \return number of qualifying rectangles
  1197. */
  1198. int rtree_search(struct RTree *t, struct RTree_Rect *r,
  1199. SearchHitCallback shcb, void *cbarg, struct Plus_head *Plus)
  1200. {
  1201. int hitCount = 0, found;
  1202. /* int j, maxcard; */
  1203. int i;
  1204. struct spidxpstack s[MAXLEVEL];
  1205. int top = 0, level;
  1206. off_t lastpos;
  1207. assert(r);
  1208. assert(t);
  1209. /* stack size of t->rootlevel + 1 is enough because of depth first search */
  1210. /* only one node per level on stack at any given time */
  1211. dig_set_cur_port(&(Plus->spidx_port));
  1212. /* add root node position to stack */
  1213. s[top].sn = rtree_get_node(t->rootpos, t->rootlevel, t, Plus);
  1214. #if 0
  1215. dig_fseek(&(Plus->spidx_fp), t->rootpos, SEEK_SET);
  1216. /* read with dig__fread_port_* fns */
  1217. dig__fread_port_I(&(s[top].sn.count), 1, &(Plus->spidx_fp));
  1218. dig__fread_port_I(&(s[top].sn.level), 1, &(Plus->spidx_fp));
  1219. maxcard = t->rootlevel ? t->nodecard : t->leafcard;
  1220. for (j = 0; j < maxcard; j++) {
  1221. dig__fread_port_D(s[top].sn.branch[j].rect.boundary, NUMSIDES,
  1222. &(Plus->spidx_fp));
  1223. dig__fread_port_O(&(s[top].pos[j]), 1, &(Plus->spidx_fp),
  1224. Plus->spidx_port.off_t_size);
  1225. /* leaf node: vector object IDs are stored in child.id */
  1226. if (s[top].sn.level == 0) {
  1227. s[top].sn.branch[j].child.id = (int)s[top].pos[j];
  1228. }
  1229. else {
  1230. s[top].sn.branch[j].child.pos = s[top].pos[j];
  1231. }
  1232. }
  1233. #endif
  1234. s[top].branch_id = i = 0;
  1235. while (top >= 0) {
  1236. level = s[top].sn->level;
  1237. if (level > 0) { /* this is an internal node in the tree */
  1238. found = 1;
  1239. for (i = s[top].branch_id; i < t->nodecard; i++) {
  1240. lastpos = s[top].sn->branch[i].child.pos;
  1241. if (lastpos > 0 &&
  1242. RTreeOverlap(r, &(s[top].sn->branch[i].rect), t)) {
  1243. s[top++].branch_id = i + 1;
  1244. s[top].sn = rtree_get_node(lastpos, level - 1, t, Plus);
  1245. #if 0
  1246. dig_fseek(&(Plus->spidx_fp), lastpos, SEEK_SET);
  1247. /* read with dig__fread_port_* fns */
  1248. dig__fread_port_I(&(s[top].sn.count), 1,
  1249. &(Plus->spidx_fp));
  1250. dig__fread_port_I(&(s[top].sn.level), 1,
  1251. &(Plus->spidx_fp));
  1252. maxcard = s[top].sn.level ? t->nodecard : t->leafcard;
  1253. for (j = 0; j < maxcard; j++) {
  1254. dig__fread_port_D(s[top].sn.branch[j].rect.boundary,
  1255. NUMSIDES, &(Plus->spidx_fp));
  1256. dig__fread_port_O(&(s[top].pos[j]), 1,
  1257. &(Plus->spidx_fp),
  1258. Plus->spidx_port.off_t_size);
  1259. if (s[top].sn.level == 0) {
  1260. s[top].sn.branch[j].child.id = (int)s[top].pos[j];
  1261. }
  1262. else {
  1263. s[top].sn.branch[j].child.pos = s[top].pos[j];
  1264. }
  1265. }
  1266. #endif
  1267. s[top].branch_id = 0;
  1268. found = 0;
  1269. break;
  1270. }
  1271. }
  1272. if (found) {
  1273. /* nothing else found, go back up */
  1274. s[top].branch_id = t->nodecard;
  1275. top--;
  1276. }
  1277. }
  1278. else { /* this is a leaf node */
  1279. for (i = 0; i < t->leafcard; i++) {
  1280. if (s[top].sn->branch[i].child.id &&
  1281. RTreeOverlap(r, &(s[top].sn->branch[i].rect), t)) {
  1282. hitCount++;
  1283. if (shcb) { /* call the user-provided callback */
  1284. if (!shcb((int)s[top].sn->branch[i].child.id,
  1285. &s[top].sn->branch[i].rect, cbarg)) {
  1286. /* callback wants to terminate search early */
  1287. return hitCount;
  1288. }
  1289. }
  1290. }
  1291. }
  1292. top--;
  1293. }
  1294. }
  1295. return hitCount;
  1296. }