find.c 9.1 KB

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