sindex.c 9.4 KB

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