select.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /*!
  2. \file lib/vector/vedit/select.c
  3. \brief Vedit library - select primitives by query
  4. (C) 2007-2008 by the GRASS Development Team
  5. This program is free software under the GNU General Public License
  6. (>=v2). Read the file COPYING that comes with GRASS for details.
  7. \author Martin Landa <landa.martin gmail.com>
  8. */
  9. #include <math.h>
  10. #include <grass/glocale.h>
  11. #include <grass/vedit.h>
  12. static int select_by_query(struct Map_info *, int, int, double,
  13. int, struct line_pnts *, struct line_cats *);
  14. static int merge_lists(struct ilist *alist, struct ilist *blist);
  15. /*!
  16. \brief Select primitives by query (based on geometry properties)
  17. Currently supported:
  18. - QUERY_LENGTH, select all lines longer than threshold (or shorter if threshold is < 0)
  19. - QUERY_DANGLE, select all dangles longer than threshold (or shorter if threshold is < 0)
  20. Perform global query if <i>List</i> is empty otherwise query only
  21. selected vector objects.
  22. \param Map pointer to Map_info
  23. \param type feature type
  24. \param layer layer number
  25. \param thresh threshold value (< 0 for 'shorter', > 0 for 'longer')
  26. \param query query (length, dangle, ...)
  27. \param[in,out] List list of selected features
  28. \return number of selected primitives
  29. */
  30. int Vedit_select_by_query(struct Map_info *Map,
  31. int type, int layer, double thresh, int query,
  32. struct ilist *List)
  33. {
  34. int num, line, i;
  35. double thresh_tmp;
  36. struct line_pnts *Points;
  37. struct line_cats *Cats;
  38. struct ilist *List_query;
  39. Points = Vect_new_line_struct();
  40. Cats = Vect_new_cats_struct();
  41. if (List->n_values == 0) {
  42. List_query = List;
  43. }
  44. else {
  45. List_query = Vect_new_list();
  46. }
  47. switch (query) {
  48. case QUERY_LENGTH:{
  49. if (List->n_values == 0) {
  50. /* query all vector objects in vector map */
  51. num = Vect_get_num_lines(Map);
  52. for (line = 1; line <= num; line++) {
  53. if (select_by_query(Map, line, type, thresh,
  54. query, Points, Cats))
  55. Vect_list_append(List_query, line);
  56. }
  57. }
  58. else {
  59. for (i = 0; i < List->n_values; i++) {
  60. line = List->value[i];
  61. if (select_by_query(Map, line, type, thresh,
  62. query, Points, Cats)) {
  63. Vect_list_append(List_query, line);
  64. }
  65. }
  66. }
  67. break;
  68. }
  69. case QUERY_DANGLE:{
  70. struct ilist *List_dangle;
  71. List_dangle = Vect_new_list();
  72. thresh_tmp = fabs(thresh);
  73. /* select dangles shorter than 'thresh_tmp' */
  74. Vect_select_dangles(Map, type, thresh_tmp, List_dangle);
  75. if (thresh <= 0.0) { /* shorter than */
  76. for (i = 0; i < List_dangle->n_values; i++) {
  77. Vect_list_append(List_query, List_dangle->value[i]);
  78. }
  79. }
  80. else { /* longer than */
  81. for (i = 1; i <= Vect_get_num_lines(Map); i++) {
  82. if (!Vect_val_in_list(List_dangle, i))
  83. Vect_list_append(List_query, i);
  84. }
  85. }
  86. Vect_destroy_list(List_dangle);
  87. break;
  88. }
  89. default:
  90. break;
  91. }
  92. if (List != List_query) {
  93. merge_lists(List, List_query);
  94. Vect_destroy_list(List_query);
  95. }
  96. G_debug(3, "Vedit_select_by_query(): %d lines selected (by query %d)",
  97. List->n_values, query);
  98. Vect_destroy_line_struct(Points);
  99. Vect_destroy_cats_struct(Cats);
  100. return List->n_values;
  101. }
  102. /*!
  103. \brief Query selected primitive
  104. \return 1 line test positive
  105. \return 0 line test negative
  106. \return -1 on error (line is dead)
  107. */
  108. int select_by_query(struct Map_info *Map, int line, int type, double thresh,
  109. int query, struct line_pnts *Points,
  110. struct line_cats *Cats)
  111. {
  112. int ltype;
  113. double length;
  114. int i, cat_curr;
  115. int node1, node2, node; /* nodes */
  116. int nnode1, nnode2; /* number of line in node */
  117. double nx, ny, nz; /* node coordinates */
  118. struct ilist *exclude, *found; /* line id of nearest lines */
  119. struct line_cats *Cats_curr;
  120. if (!Vect_line_alive(Map, line))
  121. return -1;
  122. ltype = Vect_read_line(Map, Points, Cats, line);
  123. if (!(ltype & type))
  124. return -1;
  125. if (query == QUERY_LENGTH) {
  126. length = Vect_line_length(Points);
  127. if (thresh <= 0.0) { /* shorter then */
  128. if (length <= fabs(thresh))
  129. return 1;
  130. }
  131. else { /* longer then */
  132. if (length > thresh)
  133. return 1;
  134. }
  135. }
  136. else if (query == QUERY_DANGLE) {
  137. /*
  138. this code is currently replaced by Vect_select_dangle()
  139. not used by v.edit
  140. */
  141. int layer, cat;
  142. layer = 1;
  143. Vect_cat_get(Cats, layer, &cat); /* get first category from layer */
  144. if (!(type & GV_LINES))
  145. return -1;
  146. /* check if line is dangle */
  147. Vect_get_line_nodes(Map, line, &node1, &node2);
  148. node = -1;
  149. nnode1 = Vect_get_node_n_lines(Map, node1);
  150. nnode2 = Vect_get_node_n_lines(Map, node2);
  151. if ((nnode1 == 4 && nnode2 == 1) || (nnode1 == 1 && nnode2 == 4)) {
  152. if (nnode1 == 4)
  153. node = node1;
  154. else
  155. node = node2;
  156. }
  157. /* no dangle ? */
  158. if (node == -1)
  159. return -1;
  160. length = Vect_line_length(Points);
  161. if (thresh <= 0.0) { /* shorter then */
  162. if (length > fabs(thresh))
  163. return -1;
  164. }
  165. else { /* longer then */
  166. if (length <= thresh)
  167. return -1;
  168. }
  169. /* at least one of the lines need to have same category number */
  170. exclude = Vect_new_list();
  171. found = Vect_new_list();
  172. Vect_get_node_coor(Map, node, &nx, &ny, &nz);
  173. Vect_list_append(exclude, line);
  174. Vect_find_line_list(Map, nx, ny, nz,
  175. GV_LINES, 0.0, WITHOUT_Z, exclude, found);
  176. Cats_curr = Vect_new_cats_struct();
  177. for (i = 0; i < found->n_values; i++) {
  178. Vect_read_line(Map, NULL, Cats_curr, found->value[i]);
  179. if (Vect_cat_get(Cats_curr, layer, &cat_curr) > -1) {
  180. if (cat == cat_curr)
  181. return 1;
  182. }
  183. }
  184. Vect_destroy_cats_struct(Cats_curr);
  185. Vect_destroy_list(exclude);
  186. Vect_destroy_list(found);
  187. }
  188. else {
  189. /* this shouldn't happen */
  190. G_fatal_error("Vedit_select_by_query(): %s", _("Unknown query tool"));
  191. }
  192. return 0;
  193. }
  194. /*!
  195. \brief Merge two lists, i.e. store only duplicate items
  196. \param[in,out] alist list to be merged
  197. \param blist list used for merging
  198. \return result number of items
  199. */
  200. int merge_lists(struct ilist *alist, struct ilist *blist)
  201. {
  202. int i;
  203. struct ilist *list_del;
  204. list_del = Vect_new_list();
  205. for (i = 0; i < alist->n_values; i++) {
  206. if (!Vect_val_in_list(blist, alist->value[i]))
  207. Vect_list_append(list_del, alist->value[i]);
  208. }
  209. Vect_list_delete_list(alist, list_del);
  210. Vect_destroy_list(list_del);
  211. return alist->n_values;
  212. }