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