1 #include <stdlib.h>
2 #include <grass/gis.h>
3 #include <grass/vector.h>
4 #include "walk.h"
5 
6 /* find next line for given line and node
7  *  return: next line (may be input line if it is loop)
8  *          0 - num of lines <> 2
9  */
find_next_line(struct Map_info * map,int line,int node,int ltype)10 int find_next_line(struct Map_info *map, int line, int node, int ltype)
11 {
12     int n_lines, i, tmp_line, tmp_type, next_line;
13 
14     G_debug(2, "  find_next_line() line = %d node = %d", line, node);
15     next_line = 0;
16     n_lines = 0;
17     for (i = 0; i < Vect_get_node_n_lines(map, node); i++) {
18 	tmp_line = abs(Vect_get_node_line(map, node, i));
19 	tmp_type = Vect_read_line(map, NULL, NULL, tmp_line);
20 	/* The line may be a loop so we want some other line if exists or the same line if loop */
21 	if (tmp_type & ltype) {
22 	    if (next_line == 0 || tmp_line != line)
23 		next_line = tmp_line;
24 	    n_lines++;
25 	}
26     }
27     if (n_lines != 2)
28 	next_line = 0;
29 
30     G_debug(2, "  -> next line = %d", next_line);
31     return next_line;
32 }
33 
34 /* Start from some arbitrary line on a polyline and walk back to find
35    the first node (i.e. for which the number of connected lines <> 2)
36    This line must not be a dead line (note that the arbitrary line
37    cannot be a dead line because this has already been checked in
38    main.c. */
walk_back(struct Map_info * map,int start_line,int type)39 int walk_back(struct Map_info *map, int start_line, int type)
40 {
41     int start_node, n1, n2;
42     int line;
43     int next_line;
44 
45     G_debug(2, "walk_back() start = %d", start_line);
46     line = start_line;
47 
48     /* Otherwise find the start (i.e. travel in the negative direction) */
49     Vect_get_line_nodes(map, line, &start_node, NULL);
50 
51     while (1) {
52 	/* Find next line at start node */
53 	next_line = find_next_line(map, line, start_node, type);
54 	G_debug(2, "  next = %d", next_line);
55 
56 	/* Keep going so long as not returned to start_line, i.e. if not a closed set of lines */
57 	if (next_line == 0 || next_line == start_line)
58 	    break;
59 
60 	line = next_line;
61 	/* In a heavily edited binary vector map the relationship
62 	   between the direction of a line (in terms of whether it is
63 	   positive or negative in a node's line array) and the order of
64 	   the line's nodes N1 and N2 is not constant.  So here we flip
65 	   the direction of travel if the initial direction of travel
66 	   points back to the same line. */
67 	Vect_get_line_nodes(map, next_line, &n1, &n2);
68 	if (n2 == start_node)
69 	    start_node = n1;
70 	else
71 	    start_node = n2;
72     }
73 
74     return (line);
75 }
76 
77 /*
78    \brief Compare two line_cats structs.
79 
80    \return 1 - structs have same categories in all fields
81    \return 0 - structs do not have same categories in all fields
82  */
cmp_cats(struct line_cats * Cats1,struct line_cats * Cats2)83 int cmp_cats(struct line_cats *Cats1, struct line_cats *Cats2)
84 {
85     int cat_found, cat_idx, i, ret;
86     struct ilist *cats_list;
87 
88     if (Cats1->n_cats != Cats2->n_cats) {
89 	return 0;
90     }
91 
92     cats_list = Vect_new_list();
93 
94     for (cat_idx = 0; cat_idx < Cats1->n_cats; cat_idx++) {
95 
96 	ret = Vect_field_cat_get(Cats2, Cats1->field[cat_idx], cats_list);
97 
98 	if (ret == -1) {
99 	    Vect_destroy_list(cats_list);
100 	    return 0;
101 	}
102 
103 	cat_found = 0;
104 
105 	for (i = 0; i < cats_list->n_values; i++) {
106 	    if (Cats1->cat[cat_idx] == cats_list->value[i]) {
107 		cat_found = 1;
108 	    }
109 
110 	}
111 
112 	if (cat_found == 0) {
113 	    Vect_destroy_list(cats_list);
114 	    return 0;
115 	}
116     }
117 
118     Vect_destroy_list(cats_list);
119     return 1;
120 }
121 
122 /* Start from the first node on a polyline and walk to the other end,
123    collecting the coordinates of each node en route.  */
walk_forward_and_pick_up_coords(struct Map_info * map,int start_line,int ltype,struct line_pnts * points,int * lines_visited,struct line_cats * Cats,int write_cats)124 int walk_forward_and_pick_up_coords(struct Map_info *map,
125 				    int start_line, int ltype,
126 				    struct line_pnts *points,
127 				    int *lines_visited,
128 				    struct line_cats *Cats, int write_cats)
129 {
130     int cat_idx;
131     int line, next_line, n1, n2;
132     int node, next_node;
133     struct line_pnts *pnts;
134     struct line_cats *cats_tmp;
135 
136     G_debug(2, "  walk_forward() start = %d", start_line);
137     line = start_line;
138     pnts = Vect_new_line_struct();
139     if (write_cats != NO_CATS) {
140 	cats_tmp = Vect_new_cats_struct();
141     }
142     else {
143 	cats_tmp = NULL;
144 	Vect_reset_cats(Cats);
145     }
146 
147     Vect_reset_line(points);
148 
149     /* Pick up first set of coordinates */
150     lines_visited[line] = 1;
151     if (cats_tmp)
152 	Vect_read_line(map, pnts, Cats, line);
153     else
154 	Vect_read_line(map, pnts, NULL, line);
155 
156     Vect_get_line_nodes(map, line, &n1, &n2);
157     next_line = find_next_line(map, line, n1, ltype);
158     if (next_line > 0) {	/* continue at start node */
159 	Vect_append_points(points, pnts, GV_BACKWARD);
160 	next_node = n1;
161     }
162     else {
163 	Vect_append_points(points, pnts, GV_FORWARD);
164 	next_line = find_next_line(map, line, n2, ltype);	/* check end node */
165 	if (next_line > 0) {
166 	    next_node = n2;	/* continue at end node */
167 	}
168 	else {
169 	    return 1;		/* no other line */
170 	}
171     }
172 
173     /* While next line exist append coordinates */
174     line = next_line;
175     node = next_node;
176     while (line != 0 && line != start_line) {
177 	G_debug(2, "  line = %d", line);
178 	Vect_read_line(map, pnts, cats_tmp, line);
179 	if (cats_tmp && write_cats == MULTI_CATS) {
180 	    for (cat_idx = 0; cat_idx < cats_tmp->n_cats; cat_idx++) {
181 		Vect_cat_set(Cats, cats_tmp->field[cat_idx],
182 			     cats_tmp->cat[cat_idx]);
183 	    }
184 	}
185 
186 	if (cats_tmp && write_cats == SAME_CATS) {
187 
188 	    if (cmp_cats(Cats, cats_tmp) == 0) {
189 		break;
190 	    }
191 	}
192 
193 	Vect_get_line_nodes(map, line, &n1, &n2);
194 
195 	if (node == n1) {
196 	    Vect_line_delete_point(pnts, 0);	/* delete duplicate nodes */
197 	    Vect_append_points(points, pnts, GV_FORWARD);
198 	    next_node = n2;
199 	}
200 	else {
201 	    Vect_line_delete_point(pnts, pnts->n_points - 1);
202 	    Vect_append_points(points, pnts, GV_BACKWARD);
203 	    next_node = n1;
204 	}
205 
206 	lines_visited[line] = 1;
207 
208 	/* Find next one */
209 	next_line = find_next_line(map, line, next_node, ltype);
210 
211 	line = next_line;
212 	node = next_node;
213     }
214 
215     if (cats_tmp)
216 	Vect_destroy_cats_struct(cats_tmp);
217 
218     return 1;
219 }
220