GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-112dd97adf
break.c
Go to the documentation of this file.
1 /*!
2  \file lib/vector/vedit/break.c
3 
4  \brief Vedit library - split, break, connect lines
5 
6  (C) 2007-2008 by the GRASS Development Team
7 
8  This program is free software under the GNU General Public License
9  (>=v2). Read the file COPYING that comes with GRASS for details.
10 
11  \author Martin Landa <landa.martin gmail.com>
12  */
13 
14 #include <math.h>
15 #include <grass/vedit.h>
16 
17 static int connect_lines(struct Map_info *, int, int, int, double,
18  struct ilist *);
19 
20 /*!
21  \brief Split selected lines on given position
22 
23  \param Map pointer to Map_info
24  \param List list of selected lines
25  \param coord points location
26  \param thresh threshold
27  \param[out] List_updated list of rewritten features (or NULL)
28 
29  \return number of modified lines
30  \return -1 on error
31  */
32 int Vedit_split_lines(struct Map_info *Map, struct ilist *List,
33  struct line_pnts *coord, double thresh,
34  struct ilist *List_updated)
35 {
36  int i, j, l;
37  int type, line, seg, newline;
38  int nlines_modified;
39  double px, py, spdist, lpdist, dist;
40  double *x, *y, *z;
41 
42  struct line_pnts *Points, *Points2;
43  struct line_cats *Cats;
44  struct ilist *List_in_box;
45 
46  nlines_modified = 0;
47 
48  Points = Vect_new_line_struct();
49  Points2 = Vect_new_line_struct();
50  Cats = Vect_new_cats_struct();
51  List_in_box = Vect_new_list();
52 
53  for (i = 0; i < List->n_values; i++) {
54  line = List->value[i];
55 
56  if (!Vect_line_alive(Map, line))
57  continue;
58 
59  type = Vect_read_line(Map, Points, Cats, line);
60 
61  if (!(type & GV_LINES))
62  continue;
63 
64  x = Points->x;
65  y = Points->y;
66  z = Points->z;
67 
68  for (j = 0; j < coord->n_points; j++) {
69  seg = Vect_line_distance(Points, coord->x[j], coord->y[j],
70  coord->z[j], WITHOUT_Z, &px, &py, NULL,
71  &dist, &spdist, &lpdist);
72 
73  if (dist > thresh) {
74  continue;
75  }
76 
77  G_debug(3,
78  "Vedit_split_lines(): line=%d, x=%f, y=%f, px=%f, py=%f, "
79  "seg=%d, "
80  "dist=%f, spdist=%f, lpdist=%f",
81  line, coord->x[j], coord->y[j], px, py, seg, dist, spdist,
82  lpdist);
83 
84  if (spdist <= 0.0 || spdist >= Vect_line_length(Points))
85  continue;
86 
87  G_debug(3, "Vedit_split_lines(): line=%d", line);
88 
89  /* copy first line part */
90  Vect_reset_line(Points2);
91  for (l = 0; l < seg; l++) {
92  Vect_append_point(Points2, x[l], y[l], z[l]);
93  }
94 
95  /* add last vertex */
96  Vect_append_point(Points2, px, py, 0.0);
97 
98  /* rewrite the line */
99  if (j == 0)
100  newline = Vect_rewrite_line(Map, line, type, Points2, Cats);
101  else
102  newline = Vect_write_line(Map, type, Points2, Cats);
103  if (newline < 0) {
104  return -1;
105  }
106  if (List_updated)
107  Vect_list_append(List_updated, newline);
108  Vect_reset_line(Points2);
109 
110  /* add given vertex */
111  Vect_append_point(Points2, px, py, 0.0);
112 
113  /* copy second line part */
114  for (l = seg; l < Points->n_points; l++) {
115  Vect_append_point(Points2, x[l], y[l], z[l]);
116  }
117 
118  /* rewrite the line */
119  newline = Vect_write_line(Map, type, Points2, Cats);
120  if (newline < 0) {
121  return -1;
122  }
123  if (List_updated)
124  Vect_list_append(List_updated, newline);
125 
126  nlines_modified++;
127  } /* for each bounding box */
128  } /* for each selected line */
129 
130  Vect_destroy_line_struct(Points);
131  Vect_destroy_line_struct(Points2);
133  Vect_destroy_list(List_in_box);
134 
135  return nlines_modified;
136 }
137 
138 /*!
139  \brief Connect lines in given threshold
140 
141  \code
142  \ \
143  id1 \ -> \
144  \
145  id2 --------- -----+---
146  \endcode
147 
148  If two lines are selected and <i>thresh</i> is -1, no limit is
149  applied.
150 
151  \param Map pointer to Map_info
152  \param List list of selected lines
153  \param thresh threshold value
154 
155  \return number of modified lines
156  \return -1 on error
157  */
158 int Vedit_connect_lines(struct Map_info *Map, struct ilist *List, double thresh)
159 {
160  int nlines_modified, connected;
161  int i, j, node[2], n_nodes;
162  int line, found;
163  double x, y, z;
164 
165  struct ilist *List_exclude, *List_found;
166 
167  nlines_modified = 0;
168 
169  List_exclude = Vect_new_list();
170  List_found = Vect_new_list();
171 
172  n_nodes = 2;
173 
174  /* collect lines to be modified */
175  for (i = 0; i < List->n_values; i++) {
176  line = List->value[i];
177 
178  if (!Vect_line_alive(Map, line))
179  continue;
180 
181  if (Vect_get_line_type(Map, line) & GV_POINTS)
182  continue;
183 
184  node[0] = node[1] = -1;
185  Vect_get_line_nodes(Map, line, &(node[0]), &(node[1]));
186  if (node[0] < 0 || node[1] < 0)
187  continue;
188 
189  connected = 0;
190  Vect_reset_list(List_exclude);
191  Vect_list_append(List_exclude, line);
192  for (j = 0; j < n_nodes && !connected; j++) {
193  /* for each line node find lines in threshold */
194  Vect_get_node_coor(Map, node[j], &x, &y, &z);
195 
196  do {
197  /* find first nearest line */
198  found =
199  Vect_find_line_list(Map, x, y, z, GV_LINES, thresh,
200  WITHOUT_Z, List_exclude, List_found);
201 
202  if (found > 0 && Vect_line_alive(Map, found)) {
203  /* try to connect lines (given node) */
204  G_debug(3, "Vedit_connect_lines(): lines=%d,%d", line,
205  found);
206  if (connect_lines(Map, !j, line, found, thresh, List)) {
207  G_debug(
208  3,
209  "Vedit_connect_lines(): lines=%d,%d -> connected",
210  line, found);
211  nlines_modified += 2;
212  connected = 1;
213  }
214  }
215 
216  Vect_list_append(List_exclude, found);
217  } while (List_found->n_values > 0 && !connected);
218  }
219  }
220 
221  Vect_destroy_list(List_exclude);
222  Vect_destroy_list(List_found);
223 
224  return nlines_modified;
225 }
226 
227 int connect_lines(struct Map_info *Map, int first, int line_from, int line_to,
228  double thresh, struct ilist *List UNUSED)
229 {
230  int line_new;
231  int type_from, type_to;
232  int n_points, seg, is;
233  double x, y, px, py, x1, y1;
234  double dist, spdist, lpdist, length, dist_p;
235  double angle_t, angle_f, angle;
236 
237  struct line_pnts *Points_from, *Points_to, *Points_final;
238  struct line_cats *Cats_from, *Cats_to;
239 
240  Points_from = Vect_new_line_struct();
241  Points_to = Vect_new_line_struct();
242  Points_final = Vect_new_line_struct();
243  Cats_from = Vect_new_cats_struct();
244  Cats_to = Vect_new_cats_struct();
245 
246  type_from = Vect_read_line(Map, Points_from, Cats_from, line_from);
247  type_to = Vect_read_line(Map, Points_to, Cats_to, line_to);
248 
249  line_new = 0;
250  if (!(type_from & GV_LINES) || !(type_to & GV_LINES))
251  line_new = -1;
252 
253  if (line_new > -1) {
254  n_points = Points_from->n_points - 1;
255 
256  if (first) {
257  x = Points_from->x[0];
258  y = Points_from->y[0];
259  }
260  else {
261  x = Points_from->x[n_points];
262  y = Points_from->y[n_points];
263  }
264  seg = Vect_line_distance(Points_to, x, y, 0.0, WITHOUT_Z, &px, &py,
265  NULL, &dist, &spdist, &lpdist);
266 
267  if (seg > 0 && dist > 0.0 && (thresh < 0. || dist <= thresh)) {
268  /* lines in threshold */
269  if (first)
270  length = 0;
271  else
272  length = Vect_line_length(Points_from);
273 
274  if (Vect_point_on_line(Points_from, length, NULL, NULL, NULL,
275  &angle_f, NULL) > 0) {
276  if (Vect_point_on_line(Points_to, lpdist, NULL, NULL, NULL,
277  &angle_t, NULL) > 0) {
278  angle = angle_t - angle_f;
279  dist_p = fabs(dist / sin(angle));
280 
281  if (first) {
282  if (angle_f < 0)
283  angle_f -= M_PI;
284  else
285  angle_f += M_PI;
286  }
287 
288  x1 = x + dist_p * cos(angle_f);
289  y1 = y + dist_p * sin(angle_f);
290 
291  length = Vect_line_length(Points_to);
292  Vect_line_insert_point(Points_to, seg, x1, y1, 0.);
293  if (fabs(Vect_line_length(Points_to) - length) <
294  length * 1e-3) {
295  /* lines connected -> split line_to */
296  /* update line_from */
297  if (first) {
298  Points_from->x[0] = x1;
299  Points_from->y[0] = y1;
300  }
301  else {
302  Points_from->x[n_points] = x1;
303  Points_from->y[n_points] = y1;
304  }
305 
306  line_new = Vect_rewrite_line(Map, line_from, type_from,
307  Points_from, Cats_from);
308  /* Vect_list_append(List, line_new); */
309 
310  /* update line_to -- first part */
311  Vect_reset_line(Points_final);
312  for (is = 0; is < seg; is++) {
313  Vect_append_point(Points_final, Points_to->x[is],
314  Points_to->y[is],
315  Points_to->z[is]);
316  }
317  Vect_append_point(Points_final, x1, y1, 0.0);
318  line_new = Vect_rewrite_line(Map, line_to, type_to,
319  Points_final, Cats_to);
320  /* Vect_list_append(List, line_new); */
321 
322  /* write second part */
323  Vect_reset_line(Points_final);
324  Vect_append_point(Points_final, x1, y1, 0.0);
325  for (is = seg; is < Points_to->n_points; is++) {
326  Vect_append_point(Points_final, Points_to->x[is],
327  Points_to->y[is],
328  Points_to->z[is]);
329  }
330 
331  /* rewrite first part */
332  line_new = Vect_write_line(Map, type_to, Points_final,
333  Cats_to);
334  /* Vect_list_append(List, line_new); */
335  }
336  }
337  }
338  }
339  }
340 
341  Vect_destroy_line_struct(Points_from);
342  Vect_destroy_line_struct(Points_to);
343  Vect_destroy_line_struct(Points_final);
344  Vect_destroy_cats_struct(Cats_from);
345  Vect_destroy_cats_struct(Cats_to);
346 
347  return line_new > 0 ? 1 : 0;
348 }
int Vedit_connect_lines(struct Map_info *Map, struct ilist *List, double thresh)
Connect lines in given threshold.
Definition: break.c:158
int connect_lines(struct Map_info *Map, int first, int line_from, int line_to, double thresh, struct ilist *List UNUSED)
Definition: break.c:227
int Vedit_split_lines(struct Map_info *Map, struct ilist *List, struct line_pnts *coord, double thresh, struct ilist *List_updated)
Split selected lines on given position.
Definition: break.c:32
#define NULL
Definition: ccmath.h:32
int G_debug(int, const char *,...) __attribute__((format(printf
void Vect_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
Definition: line.c:77
off_t Vect_rewrite_line(struct Map_info *, off_t, int, const struct line_pnts *, const struct line_cats *)
Rewrites existing feature (topological level required)
int Vect_get_line_nodes(struct Map_info *, int, int *, int *)
Get line nodes.
Definition: level_two.c:303
int Vect_get_node_coor(struct Map_info *, int, double *, double *, double *)
Get node coordinates.
Definition: level_two.c:274
double Vect_line_length(const struct line_pnts *)
Calculate line length, 3D-length in case of 3D vector line.
Definition: line.c:575
int Vect_point_on_line(const struct line_pnts *, double, double *, double *, double *, double *, double *)
Find point on line in the specified distance.
Definition: line.c:413
int Vect_get_line_type(struct Map_info *, int)
Get line type.
Definition: level_two.c:254
int Vect_find_line_list(struct Map_info *, double, double, double, int, double, int, const struct ilist *, struct ilist *)
Find the nearest line(s).
void Vect_destroy_list(struct ilist *)
Frees all memory associated with a struct ilist, including the struct itself.
void Vect_destroy_cats_struct(struct line_cats *)
Frees all memory associated with line_cats structure, including the struct itself.
int Vect_list_append(struct ilist *, int)
Append new item to the end of list if not yet present.
int Vect_read_line(struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
int Vect_line_distance(const struct line_pnts *, double, double, double, int, double *, double *, double *, double *, double *, double *)
Calculate distance of point to line.
Definition: line.c:648
struct ilist * Vect_new_list(void)
Creates and initializes a struct ilist.
int Vect_line_alive(struct Map_info *, int)
Check if feature is alive or dead (topological level required)
int Vect_line_insert_point(struct line_pnts *, int, double, double, double)
Insert new point at index position and move all old points at that position and above up.
Definition: line.c:176
off_t Vect_write_line(struct Map_info *, int, const struct line_pnts *, const struct line_cats *)
Writes a new feature.
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition: line.c:45
void Vect_reset_line(struct line_pnts *)
Reset line.
Definition: line.c:129
struct line_cats * Vect_new_cats_struct(void)
Creates and initializes line_cats structure.
int Vect_reset_list(struct ilist *)
Reset ilist structure.
int Vect_append_point(struct line_pnts *, double, double, double)
Appends one point to the end of a line.
Definition: line.c:148
#define GV_LINES
Definition: dig_defines.h:193
#define WITHOUT_Z
2D/3D vector data
Definition: dig_defines.h:171
#define GV_POINTS
Definition: dig_defines.h:192
#define UNUSED
A macro for an attribute, if attached to a variable, indicating that the variable is not used.
Definition: gis.h:47
#define M_PI
Definition: gis.h:158
double l
Definition: r_raster.c:39
Vector map info.
Definition: dig_structs.h:1243
List of integers.
Definition: gis.h:706
int n_values
Number of values in the list.
Definition: gis.h:714
int * value
Array of values.
Definition: gis.h:710
Feature category info.
Definition: dig_structs.h:1677
Feature geometry info - coordinates.
Definition: dig_structs.h:1651
double * y
Array of Y coordinates.
Definition: dig_structs.h:1659
double * x
Array of X coordinates.
Definition: dig_structs.h:1655
int n_points
Number of points.
Definition: dig_structs.h:1667
double * z
Array of Z coordinates.
Definition: dig_structs.h:1663
#define x