box.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. /*!
  2. \file lib/vector/Vlib/box.c
  3. \brief Vector library - bounding box
  4. Higher level functions for reading/writing/manipulating vectors.
  5. (C) 2001-2015 by the GRASS Development Team
  6. This program is free software under the
  7. GNU General Public License (>=v2).
  8. Read the file COPYING that comes with GRASS
  9. for details.
  10. \author Radim Blazek
  11. */
  12. #include <stdlib.h>
  13. #include <grass/vector.h>
  14. #include <grass/glocale.h>
  15. /*!
  16. \brief Tests if point is in 3D box
  17. This function considers 3D point and 3D bounding box.
  18. \par Example
  19. \verbatim
  20. struct bound_box bbox;
  21. bbox.N = 135;
  22. bbox.S = 125;
  23. bbox.E = 220;
  24. bbox.W = 215;
  25. bbox.T = 340;
  26. bbox.B = 330;
  27. Vect_point_in_box(217, 130, 335, &bbox);
  28. \endverbatim
  29. \param x coordinate (W-E direction)
  30. \param y coordinate (S-N direction)
  31. \param z coordinate (B-T direction)
  32. \param Box boundary box
  33. \returns 1 if point is in box
  34. \returns 0 if point is not in box
  35. */
  36. int Vect_point_in_box(double x, double y, double z, const struct bound_box *Box)
  37. {
  38. return (x >= Box->W && x <= Box->E &&
  39. y >= Box->S && y <= Box->N &&
  40. z >= Box->B && z <= Box->T);
  41. }
  42. /*!
  43. \brief Tests if point is in 2D box
  44. Only x and y are tested. Top and bottom of the bounding box are ignored.
  45. \param x coordinate (W-E direction)
  46. \param y coordinate (S-N direction)
  47. \param Box boundary box (only W, E, S, N are used)
  48. \returns 1 if point is in box
  49. \returns 0 if point is not in box
  50. */
  51. int Vect_point_in_box_2d(double x, double y, const struct bound_box *Box)
  52. {
  53. return (x >= Box->W && x <= Box->E &&
  54. y >= Box->S && y <= Box->N);
  55. }
  56. /*!
  57. \brief Tests for overlap of two boxes
  58. \param A boundary box A
  59. \param B boundary box B
  60. \return 1 boxes overlap
  61. \return 0 boxes do not overlap
  62. */
  63. int Vect_box_overlap(const struct bound_box *A, const struct bound_box *B)
  64. {
  65. if (A->E < B->W || A->W > B->E ||
  66. A->N < B->S || A->S > B->N || A->T < B->B || A->B > B->T) {
  67. return 0;
  68. }
  69. return 1;
  70. }
  71. /*!
  72. \brief Copy box B to box A
  73. \param A boundary A
  74. \param B boundary B
  75. \return 1
  76. */
  77. int Vect_box_copy(struct bound_box *A, const struct bound_box *B)
  78. {
  79. A->N = B->N;
  80. A->S = B->S;
  81. A->E = B->E;
  82. A->W = B->W;
  83. A->T = B->T;
  84. A->B = B->B;
  85. return 1;
  86. }
  87. /*!
  88. \brief Extend box A by box B
  89. \param A boundary A
  90. \param B boundary B
  91. \return 1
  92. */
  93. int Vect_box_extend(struct bound_box *A, const struct bound_box *B)
  94. {
  95. if (B->N > A->N)
  96. A->N = B->N;
  97. if (B->S < A->S)
  98. A->S = B->S;
  99. if (B->E > A->E)
  100. A->E = B->E;
  101. if (B->W < A->W)
  102. A->W = B->W;
  103. if (B->T > A->T)
  104. A->T = B->T;
  105. if (B->B < A->B)
  106. A->B = B->B;
  107. return 1;
  108. }
  109. /*!
  110. * \brief Clip coordinates to box, if necessary, lines extending outside of a box.
  111. *
  112. * A line represented by the coordinates <em>x, y</em> and <em>c_x, c_y</em> is clipped to
  113. * the window defined by <em>s</em> (south), <em>n</em> (north), <em>w</em>
  114. * (west), and <em>e</em> (east). Note that the following constraints must be
  115. * true:
  116. * w <e
  117. * s <n
  118. * The <em>x</em> and <em>c_x</em> are values to be compared to <em>w</em> and
  119. * <em>e.</em> The <em>y</em> and <em>c_y</em> are values to be compared to
  120. * <em>s</em> and <em>n.</em>
  121. * The <em>x</em> and <em>c_x</em> values returned lie between <em>w</em> and
  122. * <em>e.</em> The <em>y</em> and <em>c_y</em> values returned lie between
  123. * <em>s</em> and <em>n.</em>
  124. *
  125. * \param x, y coordinates (w, e)
  126. * \param c_x,c_y coordinates (s, n)
  127. * \param Box boundary box
  128. *
  129. * \return 1 if any clipping occurred
  130. * \return 0 otherwise
  131. */
  132. int Vect_box_clip(double *x, double *y, double *c_x, double *c_y, const struct bound_box *Box)
  133. {
  134. int mod;
  135. mod = 0;
  136. if (*x < Box->W) {
  137. if (*c_x != *x)
  138. *y = *y + (Box->W - *x) / (*c_x - *x) * (*c_y - *y);
  139. *x = Box->W;
  140. mod = 1;
  141. }
  142. if (*x > Box->E) {
  143. if (*c_x != *x)
  144. *y = *y + (Box->E - *x) / (*c_x - *x) * (*c_y - *y);
  145. *x = Box->E;
  146. mod = 1;
  147. }
  148. if (*c_x < Box->W) {
  149. if (*c_x != *x)
  150. *c_y = *c_y + (Box->W - *c_x) / (*x - *c_x) * (*y - *c_y);
  151. *c_x = Box->W;
  152. mod = 1;
  153. }
  154. if (*c_x > Box->E) {
  155. if (*c_x != *x)
  156. *c_y = *c_y + (Box->E - *c_x) / (*x - *c_x) * (*y - *c_y);
  157. *c_x = Box->E;
  158. mod = 1;
  159. }
  160. if (*y < Box->S) {
  161. if (*c_y != *y)
  162. *x = *x + (Box->S - *y) / (*c_y - *y) * (*c_x - *x);
  163. *y = Box->S;
  164. mod = 1;
  165. }
  166. if (*y > Box->N) {
  167. if (*c_y != *y)
  168. *x = *x + (Box->N - *y) / (*c_y - *y) * (*c_x - *x);
  169. *y = Box->N;
  170. mod = 1;
  171. }
  172. if (*c_y < Box->S) {
  173. if (*c_y != *y)
  174. *c_x = *c_x + (Box->S - *c_y) / (*y - *c_y) * (*x - *c_x);
  175. *c_y = Box->S;
  176. mod = 1;
  177. }
  178. if (*c_y > Box->N) {
  179. if (*c_y != *y)
  180. *c_x = *c_x + (Box->N - *c_y) / (*y - *c_y) * (*x - *c_x);
  181. *c_y = Box->N;
  182. mod = 1;
  183. }
  184. return (mod);
  185. }
  186. /*!
  187. \brief Get bounding box of given feature
  188. Vector map must be open at topological level and built with level
  189. >= GV_BUILD_BASE.
  190. \param Map vector map
  191. \param line feature id
  192. \param[out] Box bounding box
  193. \return 1 on success
  194. \return 0 line is dead
  195. \return -1 on error
  196. */
  197. int Vect_get_line_box(const struct Map_info *Map, int line, struct bound_box *Box)
  198. {
  199. struct Plus_head *Plus;
  200. struct P_line *Line;
  201. int type;
  202. static struct line_pnts *Points = NULL;
  203. Plus = (struct Plus_head *) &(Map->plus);
  204. if (line < 1 || line > Plus->n_lines) {
  205. G_warning(_("Attempt to access feature with invalid id (%d)"), line);
  206. return -1;
  207. }
  208. Line = Plus->Line[line];
  209. if (Line == NULL) { /* dead */
  210. Box->N = Box->S = Box->E = Box->W = Box->T = Box->B = 0. / 0.;
  211. return 0;
  212. }
  213. type = Line->type;
  214. /* GV_LINES: retrieve box from spatial index */
  215. if (type & GV_LINES) {
  216. if (dig_find_line_box(Plus, line, Box) == 0) {
  217. G_warning(_("Unable to determine bbox for feature %d"), line);
  218. return -1;
  219. }
  220. if (!Vect_is_3d(Map)) {
  221. Box->T = PORT_DOUBLE_MAX;
  222. Box->B = -PORT_DOUBLE_MAX;
  223. }
  224. return 1;
  225. }
  226. /* all other: read line */
  227. if (Points == NULL)
  228. Points = Vect_new_line_struct();
  229. Vect_read_line(Map, Points, NULL, line);
  230. dig_line_box(Points, Box);
  231. if (!Vect_is_3d(Map)) {
  232. Box->T = PORT_DOUBLE_MAX;
  233. Box->B = -PORT_DOUBLE_MAX;
  234. }
  235. return 1;
  236. }
  237. /*!
  238. \brief Get bounding box of area
  239. Vector map must be open at topological level and built with level
  240. >= GV_BUILD_AREAS.
  241. \param Map vector map
  242. \param area area id
  243. \param[out] Box bounding box
  244. \return 1 on success
  245. \return 0 area is dead
  246. \return -1 on error
  247. */
  248. int Vect_get_area_box(const struct Map_info *Map, int area, struct bound_box *Box)
  249. {
  250. struct Plus_head *Plus;
  251. struct P_area *Area;
  252. Plus = (struct Plus_head *) &(Map->plus);
  253. if (area < 1 || area > Plus->n_areas) {
  254. G_warning(_("Attempt to access area with invalid id (%d)"), area);
  255. return -1;
  256. }
  257. Area = Plus->Area[area];
  258. if (Area == NULL) { /* dead */
  259. Box->N = Box->S = Box->E = Box->W = Box->T = Box->B = 0. / 0.;
  260. return 0;
  261. }
  262. if (dig_find_area_box(Plus, area, Box) == 0) {
  263. G_warning(_("Unable to determine bbox for area %d"), area);
  264. return -1;
  265. }
  266. if (!Vect_is_3d(Map)) {
  267. Box->T = PORT_DOUBLE_MAX;
  268. Box->B = -PORT_DOUBLE_MAX;
  269. }
  270. return 1;
  271. }
  272. /*!
  273. \brief Get bounding box of isle
  274. Vector map must be open at topological level and built with level
  275. >= GV_BUILD_AREAS.
  276. \param Map vector map
  277. \param isle isle id
  278. \param[out] Box bounding box
  279. \return 1 on success
  280. \return 0 isle is dead / bounding box not found
  281. \return -1 on error
  282. */
  283. int Vect_get_isle_box(const struct Map_info *Map, int isle, struct bound_box *Box)
  284. {
  285. struct Plus_head *Plus;
  286. struct P_isle *Isle;
  287. Plus = (struct Plus_head *) &(Map->plus);
  288. if (isle < 1 || isle > Plus->n_isles) {
  289. G_warning(_("Attempt to access area with invalid id (%d)"), isle);
  290. return -1;
  291. }
  292. Isle = Plus->Isle[isle];
  293. if (Isle == NULL) { /* dead */
  294. Box->N = Box->S = Box->E = Box->W = Box->T = Box->B = 0. / 0.;
  295. return 0;
  296. }
  297. if (dig_find_isle_box(Plus, isle, Box) == 0) {
  298. G_warning(_("Unable to determine bbox for isle %d"), isle);
  299. return -1;
  300. }
  301. if (!Vect_is_3d(Map)) {
  302. Box->T = PORT_DOUBLE_MAX;
  303. Box->B = -PORT_DOUBLE_MAX;
  304. }
  305. return 1;
  306. }
  307. /*!
  308. \brief Get bounding box of map (all features in the map)
  309. Requires level 2. On level 1 error code is returned.
  310. \param Map vector map
  311. \param[out] Box bounding box
  312. \return 1 on success
  313. \return 0 on error
  314. */
  315. int Vect_get_map_box(const struct Map_info *Map, struct bound_box *Box)
  316. {
  317. const struct Plus_head *Plus;
  318. Plus = &(Map->plus);
  319. Vect_box_copy(Box, &(Plus->box));
  320. if (Vect_level(Map) < 2)
  321. return 0;
  322. return 1;
  323. }
  324. /*!
  325. \brief Get bounding box of map on level 1 (all features in the map)
  326. This subroutine determines bounding box by reading all features
  327. sequentially.
  328. \param Map vector map
  329. \param[out] Box bounding box
  330. \return 1 on success
  331. \return 0 on error
  332. */
  333. int Vect_get_map_box1(struct Map_info *Map, struct bound_box *Box)
  334. {
  335. int type;
  336. int first = TRUE;
  337. struct line_pnts *Points;
  338. struct bound_box line_box;
  339. Points = Vect_new_line_struct();
  340. Vect_rewind(Map);
  341. G_verbose_message(_("Topology not available for vector map <%s>. "
  342. "Registering primitives..."), Vect_get_full_name(Map));
  343. while (TRUE) {
  344. /* register line */
  345. type = Vect_read_next_line(Map, Points, NULL);
  346. if (type == -1) {
  347. G_warning(_("Unable to read vector map"));
  348. return 0;
  349. }
  350. else if (type == -2) {
  351. break;
  352. }
  353. /* update box */
  354. dig_line_box(Points, &line_box);
  355. if (first == TRUE) {
  356. Vect_box_copy(Box, &line_box);
  357. first = FALSE;
  358. }
  359. else
  360. Vect_box_extend(Box, &line_box);
  361. }
  362. Vect_destroy_line_struct(Points);
  363. return 1;
  364. }
  365. /*!
  366. \brief Copy region window to bounding box
  367. \param Window region structure (raster-based)
  368. \param[out] Box boundary box (vector-based)
  369. \return 1 on success
  370. \return 0 on error
  371. */
  372. int Vect_region_box(const struct Cell_head *Window, struct bound_box *Box)
  373. {
  374. Box->N = Window->north;
  375. Box->S = Window->south;
  376. Box->E = Window->east;
  377. Box->W = Window->west;
  378. Box->T = PORT_DOUBLE_MAX;
  379. Box->B = -PORT_DOUBLE_MAX;
  380. return 1;
  381. }