find.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*!
  2. * \file find.c
  3. *
  4. * \brief Vector library - Find nearest vector feature.
  5. *
  6. * Higher level functions for reading/writing/manipulating vectors.
  7. *
  8. * (C) 2001-2009 by the GRASS Development Team
  9. *
  10. * This program is free software under the GNU General Public License
  11. * (>=v2). Read the file COPYING that comes with GRASS for details.
  12. * \author Original author CERL, probably Dave Gerdes or Mike
  13. * Higgins.
  14. * \author Update to GRASS 5.7 Radim Blazek and David D. Gray.
  15. */
  16. #include <grass/config.h>
  17. #include <math.h>
  18. #include <grass/gis.h>
  19. #include <grass/vector.h>
  20. #ifndef HUGE_VAL
  21. #define HUGE_VAL 9999999999999.0
  22. #endif
  23. /*!
  24. * \brief Find the nearest node.
  25. *
  26. * \param Map vector map
  27. * \param ux,uy,uz point coordinates
  28. * \param maxdist max distance from the line
  29. * \param with_z 3D (WITH_Z, WITHOUT_Z)
  30. *
  31. * \return number of nearest node
  32. * \return 0 if not found
  33. */
  34. int
  35. Vect_find_node(struct Map_info *Map,
  36. double ux, double uy, double uz, double maxdist, int with_z)
  37. {
  38. int i, nnodes, node;
  39. struct bound_box box;
  40. struct ilist *NList;
  41. double x, y, z;
  42. double cur_dist, dist;
  43. G_debug(3, "Vect_find_node() for %f %f %f maxdist = %f", ux, uy, uz,
  44. maxdist);
  45. NList = Vect_new_list();
  46. /* Select all nodes in box */
  47. box.N = uy + maxdist;
  48. box.S = uy - maxdist;
  49. box.E = ux + maxdist;
  50. box.W = ux - maxdist;
  51. if (with_z) {
  52. box.T = uz + maxdist;
  53. box.B = uz - maxdist;
  54. }
  55. else {
  56. box.T = HUGE_VAL;
  57. box.B = -HUGE_VAL;
  58. }
  59. nnodes = Vect_select_nodes_by_box(Map, &box, NList);
  60. G_debug(3, " %d nodes in box", nnodes);
  61. if (nnodes == 0)
  62. return 0;
  63. /* find nearest */
  64. cur_dist = PORT_DOUBLE_MAX;
  65. node = 0;
  66. for (i = 0; i < nnodes; i++) {
  67. Vect_get_node_coor(Map, NList->value[i], &x, &y, &z);
  68. dist = Vect_points_distance(ux, uy, uz, x, y, z, with_z);
  69. if (dist < cur_dist) {
  70. cur_dist = dist;
  71. node = i;
  72. }
  73. }
  74. G_debug(3, " nearest node %d in distance %f", NList->value[node],
  75. cur_dist);
  76. /* Check if in max distance */
  77. if (cur_dist <= maxdist)
  78. return (NList->value[node]);
  79. else
  80. return 0;
  81. }
  82. /*!
  83. * \brief Find the nearest line.
  84. *
  85. * \param map vector map
  86. * \param ux,uy,uz points coordinates
  87. * \param type feature type (GV_LINE, GV_POINT, GV_BOUNDARY or GV_CENTROID)
  88. * if only want to search certain types of lines or -1 if search all lines
  89. * \param maxdist max distance from the line
  90. * \param with_z 3D (WITH_Z, WITHOUT_Z)
  91. * \param exclude if > 0 number of line which should be excluded from selection.
  92. * May be useful if we need line nearest to other one.
  93. *
  94. * \return number of nearest line
  95. * \return 0 if not found
  96. *
  97. */
  98. int
  99. Vect_find_line(struct Map_info *map,
  100. double ux, double uy, double uz,
  101. int type, double maxdist, int with_z, int exclude)
  102. {
  103. int line;
  104. struct ilist *exclude_list;
  105. exclude_list = Vect_new_list();
  106. Vect_list_append(exclude_list, exclude);
  107. line = Vect_find_line_list(map, ux, uy, uz,
  108. type, maxdist, with_z, exclude_list, NULL);
  109. Vect_destroy_list(exclude_list);
  110. return line;
  111. }
  112. /*!
  113. * \brief Find the nearest line(s).
  114. *
  115. * \param map vector map
  116. * \param ux,uy,uz points coordinates
  117. * \param type feature type (GV_LINE, GV_POINT, GV_BOUNDARY or GV_CENTROID)
  118. * if only want to search certain types of lines or -1 if search all lines
  119. * \param maxdist max distance from the line
  120. * \param with_z 3D (WITH_Z, WITHOUT_Z)
  121. * \param exclude list of lines which should be excluded from selection
  122. * \param found list of found lines (or NULL)
  123. *
  124. * \return number of nearest line
  125. * \return 0 if not found
  126. */
  127. int
  128. Vect_find_line_list(struct Map_info *map,
  129. double ux, double uy, double uz,
  130. int type, double maxdist, int with_z,
  131. const struct ilist *exclude, struct ilist *found)
  132. {
  133. int choice;
  134. double new_dist;
  135. double cur_dist;
  136. int gotone;
  137. int i, line;
  138. static struct line_pnts *Points;
  139. static int first_time = 1;
  140. const struct Plus_head *Plus;
  141. struct bound_box box;
  142. struct ilist *List;
  143. G_debug(3, "Vect_find_line_list() for %f %f %f type = %d maxdist = %f",
  144. ux, uy, uz, type, maxdist);
  145. if (first_time) {
  146. Points = Vect_new_line_struct();
  147. first_time = 0;
  148. }
  149. Plus = &(map->plus);
  150. gotone = 0;
  151. choice = 0;
  152. cur_dist = HUGE_VAL;
  153. box.N = uy + maxdist;
  154. box.S = uy - maxdist;
  155. box.E = ux + maxdist;
  156. box.W = ux - maxdist;
  157. if (with_z) {
  158. box.T = uz + maxdist;
  159. box.B = uz - maxdist;
  160. }
  161. else {
  162. box.T = PORT_DOUBLE_MAX;
  163. box.B = -PORT_DOUBLE_MAX;
  164. }
  165. List = Vect_new_list();
  166. if (found)
  167. Vect_reset_list(found);
  168. Vect_select_lines_by_box(map, &box, type, List);
  169. for (i = 0; i < List->n_values; i++) {
  170. line = List->value[i];
  171. if (Vect_val_in_list(exclude, line)) {
  172. G_debug(3, " line = %d exclude", line);
  173. continue;
  174. }
  175. /* No more needed */
  176. /*
  177. Line = Plus->Line[line];
  178. if ( Line == NULL ) continue;
  179. if ( !(type & Line->type) ) continue;
  180. */
  181. Vect_read_line(map, Points, NULL, line);
  182. Vect_line_distance(Points, ux, uy, uz, with_z, NULL, NULL, NULL,
  183. &new_dist, NULL, NULL);
  184. G_debug(3, " line = %d distance = %f", line, new_dist);
  185. if (found && new_dist <= maxdist) {
  186. Vect_list_append(found, line);
  187. }
  188. if ((++gotone == 1) || (new_dist <= cur_dist)) {
  189. if (new_dist == cur_dist) {
  190. /* TODO */
  191. /* choice = dig_center_check (map->Line, choice, a, ux, uy); */
  192. continue;
  193. }
  194. choice = line;
  195. cur_dist = new_dist;
  196. }
  197. }
  198. G_debug(3, "min distance found = %f", cur_dist);
  199. if (cur_dist > maxdist)
  200. choice = 0;
  201. Vect_destroy_list(List);
  202. return (choice);
  203. }
  204. /*!
  205. * \brief Find the nearest area
  206. *
  207. * \param Map vector map
  208. * \param x,y point coordinates
  209. *
  210. * \return area number
  211. * \return 0 if not found
  212. */
  213. int Vect_find_area(struct Map_info *Map, double x, double y)
  214. {
  215. int i, ret, area;
  216. static int first = 1;
  217. struct bound_box box;
  218. static struct ilist *List;
  219. G_debug(3, "Vect_find_area() x = %f y = %f", x, y);
  220. if (first) {
  221. List = Vect_new_list();
  222. first = 0;
  223. }
  224. /* select areas by box */
  225. box.E = x;
  226. box.W = x;
  227. box.N = y;
  228. box.S = y;
  229. box.T = PORT_DOUBLE_MAX;
  230. box.B = -PORT_DOUBLE_MAX;
  231. Vect_select_areas_by_box(Map, &box, List);
  232. G_debug(3, " %d areas selected by box", List->n_values);
  233. for (i = 0; i < List->n_values; i++) {
  234. area = List->value[i];
  235. ret = Vect_point_in_area(Map, area, x, y);
  236. G_debug(3, " area = %d Vect_point_in_area() = %d", area, ret);
  237. if (ret >= 1)
  238. return (area);
  239. }
  240. return 0;
  241. }
  242. /*!
  243. * \brief Find the nearest island
  244. *
  245. * \param Map vector map
  246. * \param x,y points coordinates
  247. *
  248. * \return island number,
  249. * \return 0 if not found
  250. */
  251. int Vect_find_island(struct Map_info *Map, double x, double y)
  252. {
  253. int i, ret, island, current, current_size, size;
  254. static int first = 1;
  255. struct bound_box box;
  256. static struct ilist *List;
  257. static struct line_pnts *Points;
  258. G_debug(3, "Vect_find_island() x = %f y = %f", x, y);
  259. if (first) {
  260. List = Vect_new_list();
  261. Points = Vect_new_line_struct();
  262. first = 0;
  263. }
  264. /* select islands by box */
  265. box.E = x;
  266. box.W = x;
  267. box.N = y;
  268. box.S = y;
  269. box.T = PORT_DOUBLE_MAX;
  270. box.B = -PORT_DOUBLE_MAX;
  271. Vect_select_isles_by_box(Map, &box, List);
  272. G_debug(3, " %d islands selected by box", List->n_values);
  273. current_size = -1;
  274. current = 0;
  275. for (i = 0; i < List->n_values; i++) {
  276. island = List->value[i];
  277. ret = Vect_point_in_island(x, y, Map, island);
  278. if (ret >= 1) { /* inside */
  279. if (current > 0) { /* not first */
  280. if (current_size == -1) { /* second */
  281. G_begin_polygon_area_calculations();
  282. Vect_get_isle_points(Map, current, Points);
  283. current_size =
  284. G_area_of_polygon(Points->x, Points->y,
  285. Points->n_points);
  286. }
  287. Vect_get_isle_points(Map, island, Points);
  288. size =
  289. G_area_of_polygon(Points->x, Points->y, Points->n_points);
  290. if (size < current_size) {
  291. current = island;
  292. current_size = size;
  293. }
  294. }
  295. else { /* first */
  296. current = island;
  297. }
  298. }
  299. }
  300. return current;
  301. }