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