spindex.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. /*!
  2. \file diglib/spindex.c
  3. \brief Vector library - spatial index (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 <stdlib.h>
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #include <fcntl.h>
  16. #include <unistd.h>
  17. #include <string.h>
  18. #include <grass/vector.h>
  19. #include <grass/glocale.h>
  20. /*!
  21. \brief Initit spatial index (nodes, lines, areas, isles)
  22. \param Plus pointer to Plus_head structure
  23. \return 1 OK
  24. \return 0 on error
  25. */
  26. int dig_spidx_init(struct Plus_head *Plus)
  27. {
  28. int ndims;
  29. ndims = (Plus->with_z != 0) ? 3 : 2;
  30. Plus->spidx_with_z = (Plus->with_z != 0);
  31. if (Plus->Spidx_file) {
  32. int fd;
  33. char *filename;
  34. filename = G_tempfile();
  35. fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
  36. Plus->Node_spidx = RTreeNewIndex(fd, 0, ndims);
  37. remove(filename);
  38. filename = G_tempfile();
  39. fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
  40. Plus->Line_spidx = RTreeNewIndex(fd, 0, ndims);
  41. remove(filename);
  42. filename = G_tempfile();
  43. fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
  44. Plus->Area_spidx = RTreeNewIndex(fd, 0, ndims);
  45. remove(filename);
  46. filename = G_tempfile();
  47. fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
  48. Plus->Isle_spidx = RTreeNewIndex(fd, 0, ndims);
  49. remove(filename);
  50. Plus->Face_spidx = NULL;
  51. Plus->Volume_spidx = NULL;
  52. Plus->Hole_spidx = NULL;
  53. }
  54. else {
  55. Plus->Node_spidx = RTreeNewIndex(-1, 0, ndims);
  56. Plus->Line_spidx = RTreeNewIndex(-1, 0, ndims);
  57. Plus->Area_spidx = RTreeNewIndex(-1, 0, ndims);
  58. Plus->Isle_spidx = RTreeNewIndex(-1, 0, ndims);
  59. Plus->Face_spidx = NULL;
  60. Plus->Volume_spidx = NULL;
  61. Plus->Hole_spidx = NULL;
  62. }
  63. Plus->Node_spidx_offset = 0L;
  64. Plus->Line_spidx_offset = 0L;
  65. Plus->Area_spidx_offset = 0L;
  66. Plus->Isle_spidx_offset = 0L;
  67. Plus->Face_spidx_offset = 0L;
  68. Plus->Volume_spidx_offset = 0L;
  69. Plus->Hole_spidx_offset = 0L;
  70. Plus->Spidx_built = 0;
  71. return 1;
  72. }
  73. /*!
  74. \brief Free spatial index for nodes
  75. \param Plus pointer to Plus_head structure
  76. */
  77. void dig_spidx_free_nodes(struct Plus_head *Plus)
  78. {
  79. int ndims;
  80. ndims = Plus->with_z ? 3 : 2;
  81. /* Node spidx */
  82. if (Plus->Node_spidx->fd > -1) {
  83. int fd;
  84. char *filename;
  85. close(Plus->Node_spidx->fd);
  86. RTreeFreeIndex(Plus->Node_spidx);
  87. filename = G_tempfile();
  88. fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
  89. Plus->Node_spidx = RTreeNewIndex(fd, 0, ndims);
  90. remove(filename);
  91. }
  92. else {
  93. RTreeFreeIndex(Plus->Node_spidx);
  94. Plus->Node_spidx = RTreeNewIndex(-1, 0, ndims);
  95. }
  96. }
  97. /*!
  98. \brief Free spatial index for lines
  99. \param Plus pointer to Plus_head structure
  100. */
  101. void dig_spidx_free_lines(struct Plus_head *Plus)
  102. {
  103. int ndims;
  104. ndims = Plus->with_z ? 3 : 2;
  105. /* Line spidx */
  106. if (Plus->Line_spidx->fd > -1) {
  107. int fd;
  108. char *filename;
  109. close(Plus->Line_spidx->fd);
  110. RTreeFreeIndex(Plus->Line_spidx);
  111. filename = G_tempfile();
  112. fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
  113. Plus->Line_spidx = RTreeNewIndex(fd, 0, ndims);
  114. remove(filename);
  115. }
  116. else {
  117. RTreeFreeIndex(Plus->Line_spidx);
  118. Plus->Line_spidx = RTreeNewIndex(-1, 0, ndims);
  119. }
  120. }
  121. /*!
  122. \brief Reset spatial index for areas
  123. \param Plus pointer to Plus_head structure
  124. */
  125. void dig_spidx_free_areas(struct Plus_head *Plus)
  126. {
  127. int ndims;
  128. ndims = Plus->with_z ? 3 : 2;
  129. /* Area spidx */
  130. if (Plus->Area_spidx->fd > -1) {
  131. int fd;
  132. char *filename;
  133. close(Plus->Area_spidx->fd);
  134. RTreeFreeIndex(Plus->Area_spidx);
  135. filename = G_tempfile();
  136. fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
  137. Plus->Area_spidx = RTreeNewIndex(fd, 0, ndims);
  138. remove(filename);
  139. }
  140. else {
  141. RTreeFreeIndex(Plus->Area_spidx);
  142. Plus->Area_spidx = RTreeNewIndex(-1, 0, ndims);
  143. }
  144. }
  145. /*!
  146. \brief Reset spatial index for isles
  147. \param Plus pointer to Plus_head structure
  148. */
  149. void dig_spidx_free_isles(struct Plus_head *Plus)
  150. {
  151. int ndims;
  152. ndims = Plus->with_z ? 3 : 2;
  153. /* Isle spidx */
  154. if (Plus->Isle_spidx->fd > -1) {
  155. int fd;
  156. char *filename;
  157. close(Plus->Isle_spidx->fd);
  158. RTreeFreeIndex(Plus->Isle_spidx);
  159. filename = G_tempfile();
  160. fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
  161. Plus->Isle_spidx = RTreeNewIndex(fd, 0, ndims);
  162. remove(filename);
  163. }
  164. else {
  165. RTreeFreeIndex(Plus->Isle_spidx);
  166. Plus->Isle_spidx = RTreeNewIndex(-1, 0, ndims);
  167. }
  168. }
  169. /*!
  170. \brief Free spatial index (nodes, lines, areas, isles)
  171. \param Plus pointer to Plus_head structure
  172. */
  173. void dig_spidx_free(struct Plus_head *Plus)
  174. {
  175. /* Node spidx */
  176. if (Plus->Node_spidx->fd > -1)
  177. close(Plus->Node_spidx->fd);
  178. RTreeFreeIndex(Plus->Node_spidx);
  179. /* Line spidx */
  180. if (Plus->Line_spidx->fd > -1)
  181. close(Plus->Line_spidx->fd);
  182. RTreeFreeIndex(Plus->Line_spidx);
  183. /* Area spidx */
  184. if (Plus->Area_spidx->fd > -1)
  185. close(Plus->Area_spidx->fd);
  186. RTreeFreeIndex(Plus->Area_spidx);
  187. /* Isle spidx */
  188. if (Plus->Isle_spidx->fd > -1)
  189. close(Plus->Isle_spidx->fd);
  190. RTreeFreeIndex(Plus->Isle_spidx);
  191. /* 3D future : */
  192. /* Face spidx */
  193. /* Volume spidx */
  194. /* Hole spidx */
  195. }
  196. /*!
  197. \brief Add new node to spatial index
  198. \param Plus pointer to Plus_head structure
  199. \param node node id
  200. \param x,y,z node coordinates
  201. \return 1 OK
  202. \return 0 on error
  203. */
  204. int
  205. dig_spidx_add_node(struct Plus_head *Plus, int node,
  206. double x, double y, double z)
  207. {
  208. struct Rect rect;
  209. G_debug(3, "dig_spidx_add_node(): node = %d, x,y,z = %f, %f, %f", node, x,
  210. y, z);
  211. rect.boundary[0] = x;
  212. rect.boundary[1] = y;
  213. rect.boundary[2] = z;
  214. rect.boundary[3] = x;
  215. rect.boundary[4] = y;
  216. rect.boundary[5] = z;
  217. RTreeInsertRect(&rect, node, Plus->Node_spidx);
  218. return 1;
  219. }
  220. /*!
  221. \brief Add new line to spatial index
  222. \param Plus pointer to Plus_head structure
  223. \param line line id
  224. \param box bounding box
  225. \return 0
  226. */
  227. int dig_spidx_add_line(struct Plus_head *Plus, int line, struct bound_box * box)
  228. {
  229. struct Rect rect;
  230. G_debug(3, "dig_spidx_add_line(): line = %d", line);
  231. rect.boundary[0] = box->W;
  232. rect.boundary[1] = box->S;
  233. rect.boundary[2] = box->B;
  234. rect.boundary[3] = box->E;
  235. rect.boundary[4] = box->N;
  236. rect.boundary[5] = box->T;
  237. RTreeInsertRect(&rect, line, Plus->Line_spidx);
  238. return 0;
  239. }
  240. /*!
  241. \brief Add new area to spatial index
  242. \param Plus pointer to Plus_head structure
  243. \param area area id
  244. \param box bounding box
  245. \return 0
  246. */
  247. int dig_spidx_add_area(struct Plus_head *Plus, int area, struct bound_box * box)
  248. {
  249. struct Rect rect;
  250. G_debug(3, "dig_spidx_add_area(): area = %d", area);
  251. rect.boundary[0] = box->W;
  252. rect.boundary[1] = box->S;
  253. rect.boundary[2] = box->B;
  254. rect.boundary[3] = box->E;
  255. rect.boundary[4] = box->N;
  256. rect.boundary[5] = box->T;
  257. RTreeInsertRect(&rect, area, Plus->Area_spidx);
  258. return 0;
  259. }
  260. /*!
  261. \brief Add new island to spatial index
  262. \param Plus pointer to Plus_head structure
  263. \param isle isle id
  264. \param box bounding box
  265. \return 0
  266. */
  267. int dig_spidx_add_isle(struct Plus_head *Plus, int isle, struct bound_box * box)
  268. {
  269. struct Rect rect;
  270. G_debug(3, "dig_spidx_add_isle(): isle = %d", isle);
  271. rect.boundary[0] = box->W;
  272. rect.boundary[1] = box->S;
  273. rect.boundary[2] = box->B;
  274. rect.boundary[3] = box->E;
  275. rect.boundary[4] = box->N;
  276. rect.boundary[5] = box->T;
  277. RTreeInsertRect(&rect, isle, Plus->Isle_spidx);
  278. return 0;
  279. }
  280. /*!
  281. \brief Delete node from spatial index
  282. G_fatal_error() called on error.
  283. \param Plus pointer to Plus_head structure
  284. \param node node id
  285. \return 0
  286. */
  287. int dig_spidx_del_node(struct Plus_head *Plus, int node)
  288. {
  289. int ret;
  290. struct P_node *Node;
  291. struct Rect rect;
  292. G_debug(3, "dig_spidx_del_node(): node = %d", node);
  293. Node = Plus->Node[node];
  294. rect.boundary[0] = Node->x;
  295. rect.boundary[1] = Node->y;
  296. rect.boundary[2] = Node->z;
  297. rect.boundary[3] = Node->x;
  298. rect.boundary[4] = Node->y;
  299. rect.boundary[5] = Node->z;
  300. ret = RTreeDeleteRect(&rect, node, Plus->Node_spidx);
  301. if (ret)
  302. G_fatal_error(_("Unable to delete node %d from spatial index"), node);
  303. return 0;
  304. }
  305. /*!
  306. \brief Delete line from spatial index
  307. G_fatal_error() called on error.
  308. \param Plus pointer to Plus_head structure
  309. \param line line id
  310. \return 0
  311. */
  312. int dig_spidx_del_line(struct Plus_head *Plus, int line)
  313. {
  314. struct P_line *Line;
  315. struct Rect rect;
  316. int ret;
  317. G_debug(3, "dig_spidx_del_line(): line = %d", line);
  318. Line = Plus->Line[line];
  319. G_debug(3, " box(x1,y1,z1,x2,y2,z2): %f %f %f %f %f %f", Line->W,
  320. Line->S, Line->B, Line->E, Line->N, Line->T);
  321. rect.boundary[0] = Line->W;
  322. rect.boundary[1] = Line->S;
  323. rect.boundary[2] = Line->B;
  324. rect.boundary[3] = Line->E;
  325. rect.boundary[4] = Line->N;
  326. rect.boundary[5] = Line->T;
  327. ret = RTreeDeleteRect(&rect, line, Plus->Line_spidx);
  328. G_debug(3, " ret = %d", ret);
  329. if (ret)
  330. G_fatal_error(_("Unable to delete line %d from spatial index"), line);
  331. return 0;
  332. }
  333. /*!
  334. \brief Delete area from spatial index
  335. G_fatal_error() called on error.
  336. \param Plus pointer to Plus_head structure
  337. \param area area id
  338. \return 0
  339. */
  340. int dig_spidx_del_area(struct Plus_head *Plus, int area)
  341. {
  342. int ret;
  343. struct P_area *Area;
  344. struct Rect rect;
  345. G_debug(3, "dig_spidx_del_area(): area = %d", area);
  346. Area = Plus->Area[area];
  347. if (Area == NULL) {
  348. G_fatal_error(_("Attempt to delete sidx for dead area"));
  349. }
  350. rect.boundary[0] = Area->W;
  351. rect.boundary[1] = Area->S;
  352. rect.boundary[2] = Area->B;
  353. rect.boundary[3] = Area->E;
  354. rect.boundary[4] = Area->N;
  355. rect.boundary[5] = Area->T;
  356. ret = RTreeDeleteRect(&rect, area, Plus->Area_spidx);
  357. if (ret)
  358. G_fatal_error(_("Unable to delete area %d from spatial index"), area);
  359. return 0;
  360. }
  361. /*!
  362. \brief Delete isle from spatial index
  363. G_fatal_error() called on error.
  364. \param Plus pointer to Plus_head structure
  365. \param isle isle id
  366. \return 0
  367. */
  368. int dig_spidx_del_isle(struct Plus_head *Plus, int isle)
  369. {
  370. int ret;
  371. struct P_isle *Isle;
  372. struct Rect rect;
  373. G_debug(3, "dig_spidx_del_isle(): isle = %d", isle);
  374. Isle = Plus->Isle[isle];
  375. rect.boundary[0] = Isle->W;
  376. rect.boundary[1] = Isle->S;
  377. rect.boundary[2] = Isle->B;
  378. rect.boundary[3] = Isle->E;
  379. rect.boundary[4] = Isle->N;
  380. rect.boundary[5] = Isle->T;
  381. ret = RTreeDeleteRect(&rect, isle, Plus->Isle_spidx);
  382. if (ret)
  383. G_fatal_error(_("Unable to delete isle %d from spatial index"), isle);
  384. return 0;
  385. }
  386. /* This function is called by RTreeSearch() to add selected node/line/area/isle to thelist */
  387. static int _add_item(int id, struct ilist *list)
  388. {
  389. dig_list_add(list, id);
  390. return 1;
  391. }
  392. /*!
  393. \brief Select nodes by bbox
  394. \param Plus pointer to Plus_head structure
  395. \param box bounding box
  396. \param list list of selected lines
  397. \return number of selected nodes
  398. \return -1 on error
  399. */
  400. int
  401. dig_select_nodes(struct Plus_head *Plus, const struct bound_box * box,
  402. struct ilist *list)
  403. {
  404. struct Rect rect;
  405. G_debug(3, "dig_select_nodes()");
  406. list->n_values = 0;
  407. rect.boundary[0] = box->W;
  408. rect.boundary[1] = box->S;
  409. rect.boundary[2] = box->B;
  410. rect.boundary[3] = box->E;
  411. rect.boundary[4] = box->N;
  412. rect.boundary[5] = box->T;
  413. if (Plus->Spidx_new)
  414. RTreeSearch(Plus->Node_spidx, &rect, (void *)_add_item, list);
  415. else
  416. rtree_search(Plus->Node_spidx, &rect, (void *)_add_item, list, Plus);
  417. return (list->n_values);
  418. }
  419. /* This function is called by RTreeSearch() for nodes to add selected node to list */
  420. static int _add_node(int id, int *node)
  421. {
  422. *node = id;
  423. return 0;
  424. }
  425. /*!
  426. \brief Find one node by coordinates
  427. \param Plus pointer to Plus_head structure
  428. \param x,y,z coordinates
  429. \return number of node
  430. \return 0 not found
  431. */
  432. int dig_find_node(struct Plus_head *Plus, double x, double y, double z)
  433. {
  434. struct Rect rect;
  435. struct ilist list;
  436. int node;
  437. G_debug(3, "dig_find_node()");
  438. dig_init_list(&list);
  439. rect.boundary[0] = x;
  440. rect.boundary[1] = y;
  441. rect.boundary[2] = z;
  442. rect.boundary[3] = x;
  443. rect.boundary[4] = y;
  444. rect.boundary[5] = z;
  445. node = 0;
  446. if (Plus->Spidx_new)
  447. RTreeSearch(Plus->Node_spidx, &rect, (void *)_add_node, &node);
  448. else
  449. rtree_search(Plus->Node_spidx, &rect, (void *)_add_node, &node, Plus);
  450. return node;
  451. }
  452. /*!
  453. \brief Select lines by box
  454. \param Plus pointer to Plus_head structure
  455. \param box bounding box
  456. \param list list of selected lines
  457. \return number of selected lines
  458. */
  459. int
  460. dig_select_lines(struct Plus_head *Plus, const struct bound_box * box,
  461. struct ilist *list)
  462. {
  463. struct Rect rect;
  464. G_debug(3, "dig_select_lines()");
  465. list->n_values = 0;
  466. rect.boundary[0] = box->W;
  467. rect.boundary[1] = box->S;
  468. rect.boundary[2] = box->B;
  469. rect.boundary[3] = box->E;
  470. rect.boundary[4] = box->N;
  471. rect.boundary[5] = box->T;
  472. if (Plus->Spidx_new)
  473. RTreeSearch(Plus->Line_spidx, &rect, (void *)_add_item, list);
  474. else
  475. rtree_search(Plus->Line_spidx, &rect, (void *)_add_item, list, Plus);
  476. return (list->n_values);
  477. }
  478. /*!
  479. \brief Select areas by box
  480. \param Plus pointer to Plus_head structure
  481. \param box bounding box
  482. \param list list of selected lines
  483. \return number of selected areas
  484. */
  485. int
  486. dig_select_areas(struct Plus_head *Plus, const struct bound_box * box,
  487. struct ilist *list)
  488. {
  489. struct Rect rect;
  490. G_debug(3, "dig_select_areas()");
  491. list->n_values = 0;
  492. rect.boundary[0] = box->W;
  493. rect.boundary[1] = box->S;
  494. rect.boundary[2] = box->B;
  495. rect.boundary[3] = box->E;
  496. rect.boundary[4] = box->N;
  497. rect.boundary[5] = box->T;
  498. if (Plus->Spidx_new)
  499. RTreeSearch(Plus->Area_spidx, &rect, (void *)_add_item, list);
  500. else
  501. rtree_search(Plus->Area_spidx, &rect, (void *)_add_item, list, Plus);
  502. return (list->n_values);
  503. }
  504. /*!
  505. \brief Select isles by box
  506. \param Plus pointer to Plus_head structure
  507. \param box bounding box
  508. \param list list of selected lines
  509. \return number of selected isles
  510. */
  511. int
  512. dig_select_isles(struct Plus_head *Plus, const struct bound_box * box,
  513. struct ilist *list)
  514. {
  515. struct Rect rect;
  516. G_debug(3, "dig_select_isles()");
  517. list->n_values = 0;
  518. rect.boundary[0] = box->W;
  519. rect.boundary[1] = box->S;
  520. rect.boundary[2] = box->B;
  521. rect.boundary[3] = box->E;
  522. rect.boundary[4] = box->N;
  523. rect.boundary[5] = box->T;
  524. if (Plus->Spidx_new)
  525. RTreeSearch(Plus->Isle_spidx, &rect, (void *)_add_item, list);
  526. else
  527. rtree_search(Plus->Isle_spidx, &rect, (void *)_add_item, list, Plus);
  528. return (list->n_values);
  529. }