find.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /*!
  2. * \file lib/vector/Vlib/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 <math.h>
  17. #include <grass/vector.h>
  18. #ifndef HUGE_VAL
  19. #define HUGE_VAL 9999999999999.0
  20. #endif
  21. /* for qsort */
  22. typedef struct {
  23. int i;
  24. double size;
  25. } BOX_SIZE;
  26. static int sort_by_size(const void *a, const void *b)
  27. {
  28. BOX_SIZE *as = (BOX_SIZE *)a;
  29. BOX_SIZE *bs = (BOX_SIZE *)b;
  30. if (as->size < bs->size)
  31. return -1;
  32. else
  33. return (as->size > bs->size);
  34. }
  35. /*!
  36. * \brief Find the nearest node.
  37. *
  38. * \param Map vector map
  39. * \param ux,uy,uz point coordinates
  40. * \param maxdist max distance from the line
  41. * \param with_z 3D (WITH_Z, WITHOUT_Z)
  42. *
  43. * \return number of nearest node
  44. * \return 0 if not found
  45. */
  46. int
  47. Vect_find_node(struct Map_info *Map,
  48. double ux, double uy, double uz, double maxdist, int with_z)
  49. {
  50. int i, nnodes, node;
  51. struct bound_box box;
  52. struct ilist *NList;
  53. double x, y, z;
  54. double cur_dist, dist;
  55. G_debug(3, "Vect_find_node() for %f %f %f maxdist = %f", ux, uy, uz,
  56. maxdist);
  57. NList = Vect_new_list();
  58. /* Select all nodes in box */
  59. box.N = uy + maxdist;
  60. box.S = uy - maxdist;
  61. box.E = ux + maxdist;
  62. box.W = ux - maxdist;
  63. if (with_z) {
  64. box.T = uz + maxdist;
  65. box.B = uz - maxdist;
  66. }
  67. else {
  68. box.T = HUGE_VAL;
  69. box.B = -HUGE_VAL;
  70. }
  71. nnodes = Vect_select_nodes_by_box(Map, &box, NList);
  72. G_debug(3, " %d nodes in box", nnodes);
  73. if (nnodes == 0)
  74. return 0;
  75. /* find nearest */
  76. cur_dist = PORT_DOUBLE_MAX;
  77. node = 0;
  78. for (i = 0; i < nnodes; i++) {
  79. Vect_get_node_coor(Map, NList->value[i], &x, &y, &z);
  80. dist = Vect_points_distance(ux, uy, uz, x, y, z, with_z);
  81. if (dist < cur_dist) {
  82. cur_dist = dist;
  83. node = i;
  84. }
  85. }
  86. G_debug(3, " nearest node %d in distance %f", NList->value[node],
  87. cur_dist);
  88. /* Check if in max distance */
  89. if (cur_dist <= maxdist)
  90. return (NList->value[node]);
  91. else
  92. return 0;
  93. }
  94. /*!
  95. * \brief Find the nearest line.
  96. *
  97. * \param map vector map
  98. * \param ux,uy,uz points coordinates
  99. * \param type feature type (GV_LINE, GV_POINT, GV_BOUNDARY or GV_CENTROID)
  100. * if only want to search certain types of lines or -1 if search all lines
  101. * \param maxdist max distance from the line
  102. * \param with_z 3D (WITH_Z, WITHOUT_Z)
  103. * \param exclude if > 0 number of line which should be excluded from selection.
  104. * May be useful if we need line nearest to other one.
  105. *
  106. * \return number of nearest line
  107. * \return 0 if not found
  108. *
  109. */
  110. int
  111. Vect_find_line(struct Map_info *map,
  112. double ux, double uy, double uz,
  113. int type, double maxdist, int with_z, int exclude)
  114. {
  115. int line;
  116. struct ilist *exclude_list;
  117. exclude_list = Vect_new_list();
  118. Vect_list_append(exclude_list, exclude);
  119. line = Vect_find_line_list(map, ux, uy, uz,
  120. type, maxdist, with_z, exclude_list, NULL);
  121. Vect_destroy_list(exclude_list);
  122. return line;
  123. }
  124. /*!
  125. * \brief Find the nearest line(s).
  126. *
  127. * \param map vector map
  128. * \param ux,uy,uz points coordinates
  129. * \param type feature type (GV_LINE, GV_POINT, GV_BOUNDARY or GV_CENTROID)
  130. * if only want to search certain types of lines or -1 if search all lines
  131. * \param maxdist max distance from the line
  132. * \param with_z 3D (WITH_Z, WITHOUT_Z)
  133. * \param exclude list of lines which should be excluded from selection
  134. * \param found list of found lines (or NULL)
  135. *
  136. * \return number of nearest line
  137. * \return 0 if not found
  138. */
  139. int
  140. Vect_find_line_list(struct Map_info *map,
  141. double ux, double uy, double uz,
  142. int type, double maxdist, int with_z,
  143. const struct ilist *exclude, struct ilist *found)
  144. {
  145. int choice;
  146. double new_dist;
  147. double cur_dist;
  148. int gotone;
  149. int i, line;
  150. static struct line_pnts *Points;
  151. static int first_time = 1;
  152. const struct Plus_head *Plus;
  153. struct bound_box box;
  154. struct ilist *List;
  155. G_debug(3, "Vect_find_line_list() for %f %f %f type = %d maxdist = %f",
  156. ux, uy, uz, type, maxdist);
  157. if (first_time) {
  158. Points = Vect_new_line_struct();
  159. first_time = 0;
  160. }
  161. Plus = &(map->plus);
  162. gotone = 0;
  163. choice = 0;
  164. cur_dist = HUGE_VAL;
  165. box.N = uy + maxdist;
  166. box.S = uy - maxdist;
  167. box.E = ux + maxdist;
  168. box.W = ux - maxdist;
  169. if (with_z) {
  170. box.T = uz + maxdist;
  171. box.B = uz - maxdist;
  172. }
  173. else {
  174. box.T = PORT_DOUBLE_MAX;
  175. box.B = -PORT_DOUBLE_MAX;
  176. }
  177. List = Vect_new_list();
  178. if (found)
  179. Vect_reset_list(found);
  180. Vect_select_lines_by_box(map, &box, type, List);
  181. for (i = 0; i < List->n_values; i++) {
  182. line = List->value[i];
  183. if (Vect_val_in_list(exclude, line)) {
  184. G_debug(3, " line = %d exclude", line);
  185. continue;
  186. }
  187. /* No more needed */
  188. /*
  189. Line = Plus->Line[line];
  190. if ( Line == NULL ) continue;
  191. if ( !(type & Line->type) ) continue;
  192. */
  193. Vect_read_line(map, Points, NULL, line);
  194. Vect_line_distance(Points, ux, uy, uz, with_z, NULL, NULL, NULL,
  195. &new_dist, NULL, NULL);
  196. G_debug(3, " line = %d distance = %f", line, new_dist);
  197. if (found && new_dist <= maxdist) {
  198. Vect_list_append(found, line);
  199. }
  200. if ((++gotone == 1) || (new_dist <= cur_dist)) {
  201. if (new_dist == cur_dist) {
  202. /* TODO */
  203. /* choice = dig_center_check (map->Line, choice, a, ux, uy); */
  204. continue;
  205. }
  206. choice = line;
  207. cur_dist = new_dist;
  208. }
  209. }
  210. G_debug(3, "min distance found = %f", cur_dist);
  211. if (cur_dist > maxdist)
  212. choice = 0;
  213. Vect_destroy_list(List);
  214. return (choice);
  215. }
  216. /*!
  217. * \brief Find the nearest area
  218. *
  219. * \param Map vector map
  220. * \param x,y point coordinates
  221. *
  222. * \return area number
  223. * \return 0 if not found
  224. */
  225. int Vect_find_area(struct Map_info *Map, double x, double y)
  226. {
  227. int i, ret, area;
  228. static int first = 1;
  229. struct bound_box box;
  230. static struct ilist *List;
  231. static BOX_SIZE *size_list;
  232. static int alloc_size_list = 0;
  233. G_debug(3, "Vect_find_area() x = %f y = %f", x, y);
  234. if (first) {
  235. List = Vect_new_list();
  236. first = 0;
  237. alloc_size_list = 10;
  238. size_list = G_malloc(alloc_size_list * sizeof(BOX_SIZE));
  239. }
  240. /* select areas by box */
  241. box.E = x;
  242. box.W = x;
  243. box.N = y;
  244. box.S = y;
  245. box.T = PORT_DOUBLE_MAX;
  246. box.B = -PORT_DOUBLE_MAX;
  247. Vect_select_areas_by_box(Map, &box, List);
  248. G_debug(3, " %d areas selected by box", List->n_values);
  249. /* sort areas by size, the smallest is likely to be the nearest */
  250. if (alloc_size_list < List->n_values) {
  251. alloc_size_list = List->n_values;
  252. size_list = G_realloc(size_list, alloc_size_list * sizeof(BOX_SIZE));
  253. }
  254. for (i = 0; i < List->n_values; i++) {
  255. size_list[i].i = area = List->value[i];
  256. Vect_get_area_box(Map, area, &box);
  257. size_list[i].size = (box.N - box.S) * (box.E - box.W);
  258. }
  259. if (List->n_values == 2) {
  260. /* simple swap */
  261. if (size_list[1].size < size_list[0].size) {
  262. size_list[0].i = List->value[1];
  263. size_list[1].i = List->value[0];
  264. }
  265. }
  266. else if (List->n_values > 2)
  267. qsort(size_list, List->n_values, sizeof(BOX_SIZE), sort_by_size);
  268. for (i = 0; i < List->n_values; i++) {
  269. area = size_list[i].i;
  270. ret = Vect_point_in_area(Map, area, x, y);
  271. G_debug(3, " area = %d Vect_point_in_area() = %d", area, ret);
  272. if (ret >= 1)
  273. return (area);
  274. }
  275. return 0;
  276. }
  277. /*!
  278. * \brief Find the nearest island
  279. *
  280. * \param Map vector map
  281. * \param x,y points coordinates
  282. *
  283. * \return island number,
  284. * \return 0 if not found
  285. */
  286. int Vect_find_island(struct Map_info *Map, double x, double y)
  287. {
  288. int i, ret, island, current, current_size, size;
  289. static int first = 1;
  290. struct bound_box box;
  291. static struct ilist *List;
  292. static struct line_pnts *Points;
  293. G_debug(3, "Vect_find_island() x = %f y = %f", x, y);
  294. if (first) {
  295. List = Vect_new_list();
  296. Points = Vect_new_line_struct();
  297. first = 0;
  298. }
  299. /* select islands by box */
  300. box.E = x;
  301. box.W = x;
  302. box.N = y;
  303. box.S = y;
  304. box.T = PORT_DOUBLE_MAX;
  305. box.B = -PORT_DOUBLE_MAX;
  306. Vect_select_isles_by_box(Map, &box, List);
  307. G_debug(3, " %d islands selected by box", List->n_values);
  308. current_size = -1;
  309. current = 0;
  310. for (i = 0; i < List->n_values; i++) {
  311. island = List->value[i];
  312. ret = Vect_point_in_island(x, y, Map, island);
  313. if (ret >= 1) { /* inside */
  314. if (current > 0) { /* not first */
  315. if (current_size == -1) { /* second */
  316. G_begin_polygon_area_calculations();
  317. Vect_get_isle_points(Map, current, Points);
  318. current_size =
  319. G_area_of_polygon(Points->x, Points->y,
  320. Points->n_points);
  321. }
  322. Vect_get_isle_points(Map, island, Points);
  323. size =
  324. G_area_of_polygon(Points->x, Points->y, Points->n_points);
  325. if (size < current_size) {
  326. current = island;
  327. current_size = size;
  328. }
  329. }
  330. else { /* first */
  331. current = island;
  332. }
  333. }
  334. }
  335. return current;
  336. }