select.c 6.3 KB

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