sindex.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /*!
  2. \file Vlib/sindex.c
  3. \brief Vector library - select vector features
  4. Higher 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 Radim Blazek
  9. */
  10. #include <grass/config.h>
  11. #include <stdlib.h>
  12. #include <grass/gis.h>
  13. #include <grass/vector.h>
  14. /*!
  15. \brief Select lines by box.
  16. Select lines whose boxes overlap specified box!!! It means that
  17. selected line may or may not overlap the box.
  18. \param Map vector map
  19. \param Box bounding box
  20. \param type line type
  21. \param[out] list output list, must be initialized
  22. \return number of lines
  23. */
  24. int
  25. Vect_select_lines_by_box(struct Map_info *Map, const struct bound_box * Box,
  26. int type, struct ilist *list)
  27. {
  28. int i, line, nlines;
  29. struct Plus_head *plus;
  30. struct P_line *Line;
  31. static struct ilist *LocList = NULL;
  32. G_debug(3, "Vect_select_lines_by_box()");
  33. G_debug(3, " Box(N,S,E,W,T,B): %e, %e, %e, %e, %e, %e", Box->N, Box->S,
  34. Box->E, Box->W, Box->T, Box->B);
  35. plus = &(Map->plus);
  36. if (!(plus->Spidx_built)) {
  37. G_debug(3, "Building spatial index.");
  38. Vect_build_sidx_from_topo(Map);
  39. }
  40. list->n_values = 0;
  41. if (!LocList)
  42. LocList = Vect_new_list();
  43. nlines = dig_select_lines(plus, Box, LocList);
  44. G_debug(3, " %d lines selected (all types)", nlines);
  45. /* Remove lines of not requested types */
  46. for (i = 0; i < nlines; i++) {
  47. line = LocList->value[i];
  48. if (plus->Line[line] == NULL)
  49. continue; /* Should not happen */
  50. Line = plus->Line[line];
  51. if (!(Line->type & type))
  52. continue;
  53. dig_list_add(list, line);
  54. }
  55. G_debug(3, " %d lines of requested type", list->n_values);
  56. return list->n_values;
  57. }
  58. /*!
  59. \brief Select areas by box.
  60. Select areas whose boxes overlap specified box!!!
  61. It means that selected area may or may not overlap the box.
  62. \param Map vector map
  63. \param Box bounding box
  64. \param[out] output list, must be initialized
  65. \return number of areas
  66. */
  67. int
  68. Vect_select_areas_by_box(struct Map_info *Map, const struct bound_box * Box,
  69. struct ilist *list)
  70. {
  71. int i;
  72. static int debug_level = -1;
  73. if (debug_level == -1) {
  74. const char *dstr = G__getenv("DEBUG");
  75. if (dstr != NULL)
  76. debug_level = atoi(dstr);
  77. else
  78. debug_level = 0;
  79. }
  80. G_debug(3, "Vect_select_areas_by_box()");
  81. G_debug(3, "Box(N,S,E,W,T,B): %e, %e, %e, %e, %e, %e", Box->N, Box->S,
  82. Box->E, Box->W, Box->T, Box->B);
  83. if (!(Map->plus.Spidx_built)) {
  84. G_debug(3, "Building spatial index.");
  85. Vect_build_sidx_from_topo(Map);
  86. }
  87. dig_select_areas(&(Map->plus), Box, list);
  88. G_debug(3, " %d areas selected", list->n_values);
  89. /* avoid loop when not debugging */
  90. if (debug_level > 2) {
  91. for (i = 0; i < list->n_values; i++) {
  92. G_debug(3, " area = %d pointer to area structure = %lx",
  93. list->value[i],
  94. (unsigned long)Map->plus.Area[list->value[i]]);
  95. }
  96. }
  97. return list->n_values;
  98. }
  99. /*!
  100. \brief Select isles by box.
  101. Select isles whose boxes overlap specified box!!!
  102. It means that selected isle may or may not overlap the box.
  103. \param Map vector map
  104. \param Box bounding box
  105. \param[out] list output list, must be initialized
  106. \return number of isles
  107. */
  108. int
  109. Vect_select_isles_by_box(struct Map_info *Map, const struct bound_box * Box,
  110. struct ilist *list)
  111. {
  112. G_debug(3, "Vect_select_isles_by_box()");
  113. G_debug(3, "Box(N,S,E,W,T,B): %e, %e, %e, %e, %e, %e", Box->N, Box->S,
  114. Box->E, Box->W, Box->T, Box->B);
  115. if (!(Map->plus.Spidx_built)) {
  116. G_debug(3, "Building spatial index.");
  117. Vect_build_sidx_from_topo(Map);
  118. }
  119. dig_select_isles(&(Map->plus), Box, list);
  120. G_debug(3, " %d isles selected", list->n_values);
  121. return list->n_values;
  122. }
  123. /*!
  124. \brief Select nodes by box.
  125. \param Map vector map
  126. \param Box bounding box
  127. \param[out] list output list, must be initialized
  128. \return number of nodes
  129. */
  130. int
  131. Vect_select_nodes_by_box(struct Map_info *Map, const struct bound_box * Box,
  132. struct ilist *list)
  133. {
  134. struct Plus_head *plus;
  135. G_debug(3, "Vect_select_nodes_by_box()");
  136. G_debug(3, "Box(N,S,E,W,T,B): %e, %e, %e, %e, %e, %e", Box->N, Box->S,
  137. Box->E, Box->W, Box->T, Box->B);
  138. plus = &(Map->plus);
  139. if (!(plus->Spidx_built)) {
  140. G_debug(3, "Building spatial index.");
  141. Vect_build_sidx_from_topo(Map);
  142. }
  143. list->n_values = 0;
  144. dig_select_nodes(plus, Box, list);
  145. G_debug(3, " %d nodes selected", list->n_values);
  146. return list->n_values;
  147. }
  148. /*!
  149. \brief Select lines by Polygon with optional isles.
  150. Polygons should be closed, i.e. first and last points must be identical.
  151. \param Map vector map
  152. \param Polygon outer ring
  153. \param nisles number of islands or 0
  154. \param Isles array of islands or NULL
  155. \param type line type
  156. \param[out] list output list, must be initialised
  157. \return number of lines
  158. */
  159. int
  160. Vect_select_lines_by_polygon(struct Map_info *Map, struct line_pnts *Polygon,
  161. int nisles, struct line_pnts **Isles, int type,
  162. struct ilist *List)
  163. {
  164. int i;
  165. struct bound_box box;
  166. static struct line_pnts *LPoints = NULL;
  167. static struct ilist *LocList = NULL;
  168. /* TODO: this function was not tested with isles */
  169. G_debug(3, "Vect_select_lines_by_polygon() nisles = %d", nisles);
  170. List->n_values = 0;
  171. if (!LPoints)
  172. LPoints = Vect_new_line_struct();
  173. if (!LocList)
  174. LocList = Vect_new_list();
  175. /* Select first all lines by box */
  176. dig_line_box(Polygon, &box);
  177. box.T = PORT_DOUBLE_MAX;
  178. box.B = -PORT_DOUBLE_MAX;
  179. Vect_select_lines_by_box(Map, &box, type, LocList);
  180. G_debug(3, " %d lines selected by box", LocList->n_values);
  181. /* Check all lines if intersect the polygon */
  182. for (i = 0; i < LocList->n_values; i++) {
  183. int j, line, intersect = 0;
  184. line = LocList->value[i];
  185. /* Read line points */
  186. Vect_read_line(Map, LPoints, NULL, line);
  187. /* Check if any of line vertices is within polygon */
  188. for (j = 0; j < LPoints->n_points; j++) {
  189. if (Vect_point_in_poly(LPoints->x[j], LPoints->y[j], Polygon) >= 1) { /* inside polygon */
  190. int k, inisle = 0;
  191. for (k = 0; k < nisles; k++) {
  192. if (Vect_point_in_poly(LPoints->x[j], LPoints->y[j], Isles[k]) >= 1) { /* in isle */
  193. inisle = 1;
  194. break;
  195. }
  196. }
  197. if (!inisle) { /* inside polygon, outside isles -> select */
  198. intersect = 1;
  199. break;
  200. }
  201. }
  202. }
  203. if (intersect) {
  204. dig_list_add(List, line);
  205. continue;
  206. }
  207. /* Check intersections of the line with area/isles boundary */
  208. /* Outer boundary */
  209. if (Vect_line_check_intersection(LPoints, Polygon, 0)) {
  210. dig_list_add(List, line);
  211. continue;
  212. }
  213. /* Islands */
  214. for (j = 0; j < nisles; j++) {
  215. if (Vect_line_check_intersection(LPoints, Isles[j], 0)) {
  216. intersect = 1;
  217. break;
  218. }
  219. }
  220. if (intersect) {
  221. dig_list_add(List, line);
  222. }
  223. }
  224. G_debug(4, " %d lines selected by polygon", List->n_values);
  225. return List->n_values;
  226. }
  227. /*!
  228. \brief Select areas by Polygon with optional isles.
  229. Polygons should be closed, i.e. first and last points must be identical.
  230. Warning : values in list may be duplicate!
  231. \param Map vector map
  232. \param Polygon outer ring
  233. \param nisles number of islands or 0
  234. \param Isles array of islands or NULL
  235. \param[out] list output list, must be initialised
  236. \return number of areas
  237. */
  238. int
  239. Vect_select_areas_by_polygon(struct Map_info *Map, struct line_pnts *Polygon,
  240. int nisles, struct line_pnts **Isles,
  241. struct ilist *List)
  242. {
  243. int i, area;
  244. static struct ilist *BoundList = NULL;
  245. /* TODO: this function was not tested with isles */
  246. G_debug(3, "Vect_select_areas_by_polygon() nisles = %d", nisles);
  247. List->n_values = 0;
  248. if (!BoundList)
  249. BoundList = Vect_new_list();
  250. /* Select boundaries by polygon */
  251. Vect_select_lines_by_polygon(Map, Polygon, nisles, Isles, GV_BOUNDARY,
  252. BoundList);
  253. /* Add areas on left/right side of selected boundaries */
  254. for (i = 0; i < BoundList->n_values; i++) {
  255. int line, left, right;
  256. line = BoundList->value[i];
  257. Vect_get_line_areas(Map, line, &left, &right);
  258. G_debug(4, "boundary = %d left = %d right = %d", line, left, right);
  259. if (left > 0) {
  260. dig_list_add(List, left);
  261. }
  262. else if (left < 0) { /* island */
  263. area = Vect_get_isle_area(Map, abs(left));
  264. G_debug(4, " left island -> area = %d", area);
  265. if (area > 0)
  266. dig_list_add(List, area);
  267. }
  268. if (right > 0) {
  269. dig_list_add(List, right);
  270. }
  271. else if (right < 0) { /* island */
  272. area = Vect_get_isle_area(Map, abs(right));
  273. G_debug(4, " right island -> area = %d", area);
  274. if (area > 0)
  275. dig_list_add(List, area);
  276. }
  277. }
  278. /* But the Polygon may be completely inside the area (only one), in that case
  279. * we find the area by one polygon point and add it to the list */
  280. area = Vect_find_area(Map, Polygon->x[0], Polygon->y[0]);
  281. if (area > 0)
  282. dig_list_add(List, area);
  283. G_debug(3, " %d areas selected by polygon", List->n_values);
  284. return List->n_values;
  285. }