GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-8cbe8fef7c
merge.c
Go to the documentation of this file.
1 /*!
2  \file lib/vector/vedit/merge.c
3 
4  \brief Vedit library - merge lines
5 
6  (C) 2006-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 Jachym Cepicky <jachym.cepicky gmail.com>
12  \author Martin Landa <landa.martin gmail.com>
13  */
14 
15 #include <grass/vedit.h>
16 
17 /*!
18  \brief Merge two given lines a, b
19 
20  a : Points1/Cats1
21  b : Points2/Cats2
22  merged line : Points/Cats
23 
24  \param Points1,Cats1 first line
25  \param Points2,Cats2 second line
26  \param thresh threshold value
27  \param[out] Points result line
28 
29  \return 1 on success
30  \return 0 on error
31  */
32 static int merge_lines(struct line_pnts *Points1, struct line_cats *Cats1,
33  struct line_pnts *Points2, struct line_cats *Cats2,
34  double thresh, struct line_pnts **Points);
35 
36 /*!
37  \brief Merge lines/boundaries
38 
39  At least two lines need to be given.
40 
41  \param Map pointer to Map_info
42  \param List list of selected lines
43 
44  \return number of merged lines
45  \return -1 on error
46  */
47 int Vedit_merge_lines(struct Map_info *Map, struct ilist *List)
48 {
49  struct ilist *List_in_box;
50 
51  struct line_pnts *Points1, *Points2, *Points;
52  struct line_cats *Cats1, *Cats2;
53 
54  int line_i, i, j;
55  int line, line1, type1, line2;
56  int do_merge;
57 
58  /* number of lines (original, selected, merged) */
59  int nlines, nlines_merged;
60 
61  nlines_merged = 0;
62 
63  if (List->n_values < 2) {
64  return 0;
65  }
66 
67  G_debug(1, "Vedit_merge_lines(): merging %d lines", List->n_values);
68 
69  Points1 = Vect_new_line_struct();
70  Cats1 = Vect_new_cats_struct();
71  Points2 = Vect_new_line_struct();
73  Points = Vect_new_line_struct();
74 
75  List_in_box = Vect_new_list();
76 
77  nlines = Vect_get_num_lines(Map);
78 
79  /* merge lines */
80  for (line_i = 0; line_i < List->n_values; line_i++) {
81  line1 = List->value[line_i];
82 
83  if (!Vect_line_alive(Map, line1))
84  continue;
85 
86  type1 = Vect_read_line(Map, Points1, Cats1, line1);
87 
88  if (!(type1 & GV_LINES))
89  continue;
90 
91  /* remove duplicate points */
92  Vect_line_prune(Points1);
93 
94  if (Points1->n_points < 2) {
95  G_debug(3, "Vedit_merge_lines(): skipping zero length line");
96  continue;
97  }
98 
99  Vect_reset_line(Points);
100 
101  for (i = 0; i < Points1->n_points; i += Points1->n_points - 1) {
102  Vect_reset_list(List_in_box);
103 
104  /* define searching region */
105  Vect_reset_line(Points2);
106  /*
107  Vect_append_point (Points2, Points1 -> x[i] - thresh,
108  Points1 -> y[i] + thresh, Points1 -> z[i]);
109  Vect_append_point (Points2, Points1 -> x[i] + thresh,
110  Points1 -> y[i] + thresh, Points1 -> z[i]);
111  Vect_append_point (Points2, Points1 -> x[i] + thresh,
112  Points1 -> y[i] - thresh, Points1 -> z[i]);
113  Vect_append_point (Points2, Points1 -> x[i] - thresh,
114  Points1 -> y[i] - thresh, Points1 -> z[i]);
115  */
116  Vect_append_point(Points2, Points1->x[i], Points1->y[i],
117  Points1->z[i]);
118 
119  /*
120  * merge lines only if two lines found in the region
121  * i.e. the current line and an adjacent line
122  */
123  /* NOTE
124  * - this merges two lines also if more than two lines are
125  * found in the region, but only two of these lines are
126  * in the List
127  * - this not only merges lines connected by end points
128  * but also any adjacent line with a mid point identical
129  * to one of the end points of the current line
130  */
131  if (0 < Vect_find_line_list(Map, Points1->x[i], Points1->y[i],
132  Points1->z[i], GV_LINES, 0, 0, NULL,
133  List_in_box)) {
134  do_merge = 1;
135  line2 = -1;
136  for (j = 0; do_merge && j < List_in_box->n_values; j++) {
137  if (List_in_box->value[j] == line1 ||
138  !Vect_line_alive(Map, List_in_box->value[j]))
139  continue;
140 
141  if (Vect_val_in_list(List, List_in_box->value[j])) {
142 
143  Vect_read_line(Map, Points2, Cats2,
144  List_in_box->value[j]);
145  Vect_line_prune(Points2);
146  if (Points2->n_points == 1) {
147  line2 = List_in_box->value[j];
148  do_merge = 1;
149  break;
150  }
151  if (line2 > 0) {
152  /* three lines found
153  * selected lines will be not merged
154  */
155  do_merge = 0;
156  }
157  else {
158  line2 = List_in_box->value[j];
159  }
160  }
161  }
162 
163  if (!do_merge || line2 < 0)
164  continue;
165 
166  Vect_read_line(Map, Points2, Cats2, line2);
167 
168  merge_lines(Points1, Cats1, Points2, Cats2, -1.0,
169  &Points); /* do not use threshold value */
170 
171  G_debug(3, "Vedit_merge_lines(): lines=%d,%d", line1, line2);
172 
173  if (Points->n_points > 0) {
174  if (Vect_delete_line(Map, line2) == -1) {
175  return -1;
176  }
177 
178  if (line2 <= nlines)
179  nlines_merged++;
180  }
181  }
182  } /* for each node */
183 
184  if (Points->n_points > 0) {
185  line = Vect_rewrite_line(Map, line1, type1, Points, Cats1);
186  if (line < 0) {
187  return -1;
188  }
189 
190  if (line1 <= nlines)
191  nlines_merged++;
192 
193  /* update number of lines */
194  G_ilist_add(List, line);
195  }
196  } /* for each line */
197 
198  /* destroy structures */
199  Vect_destroy_line_struct(Points1);
200  Vect_destroy_line_struct(Points2);
201  Vect_destroy_line_struct(Points);
202 
205 
206  return nlines_merged;
207 }
208 
209 static int merge_lines(struct line_pnts *Points1, struct line_cats *Cats1,
210  struct line_pnts *Points2, struct line_cats *Cats2,
211  double thresh, struct line_pnts **Points)
212 {
213  struct line_pnts *ps = *Points;
214  struct line_cats *cs = Cats1;
215 
216  int i, mindistidx;
217  double mindist;
218 
219  /* find minimal distance and its index */
220  mindist = Vedit_get_min_distance(Points1, Points2, 0, /* TODO 3D */
221  &mindistidx);
222 
223  G_debug(3, " merge line ? index: %d, mindist: %g, thresh: %g", mindistidx,
224  mindist, thresh);
225 
226  if (thresh > 0 && mindist > thresh) {
227  return 0;
228  }
229 
230  /* set index and other things */
231  switch (mindistidx) {
232  /* for each mindistidx create new line */
233  case 0:
234  Vect_append_points(ps, Points2, GV_BACKWARD);
235  if (ps->n_points == Points2->n_points)
236  Vect_append_points(ps, Points1, GV_FORWARD);
237  break;
238  case 1:
239  Vect_append_points(ps, Points2, GV_FORWARD);
240  if (ps->n_points == Points2->n_points)
241  Vect_append_points(ps, Points1, GV_FORWARD);
242  break;
243  case 2:
244  if (ps->n_points == 0)
245  Vect_append_points(ps, Points1, GV_FORWARD);
246  Vect_append_points(ps, Points2, GV_FORWARD);
247  break;
248  case 3:
249  if (ps->n_points == 0)
250  Vect_append_points(ps, Points1, GV_FORWARD);
251  Vect_append_points(ps, Points2, GV_BACKWARD);
252  break;
253  default:
254  break;
255  }
256 
257  /* remove duplicate points */
259 
260  /* copy categories if needed */
261  for (i = 0; i < Cats2->n_cats; i++) {
262  Vect_cat_set(cs, Cats2->field[i], Cats2->cat[i]);
263  }
264 
265  return 1;
266 }
#define NULL
Definition: ccmath.h:32
void G_ilist_add(struct ilist *, int)
Add item to ilist.
Definition: ilist.c:78
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)
plus_t Vect_get_num_lines(struct Map_info *)
Fetch number of features (points, lines, boundaries, centroids) in vector map.
Definition: level_two.c:75
int Vect_cat_set(struct line_cats *, int, int)
Add new field/cat to category structure if doesn't exist yet.
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_cats_struct(struct line_cats *)
Frees all memory associated with line_cats structure, including the struct itself.
int Vect_read_line(struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
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_delete_line(struct Map_info *, off_t)
Delete existing feature (topological level required)
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition: line.c:45
int Vect_val_in_list(const struct ilist *, int)
Find a given item in the list.
void Vect_reset_line(struct line_pnts *)
Reset line.
Definition: line.c:129
int Vect_line_prune(struct line_pnts *)
Remove duplicate points, i.e. zero length segments.
Definition: line.c:279
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
int Vect_append_points(struct line_pnts *, const struct line_pnts *, int)
Appends points to the end of a line.
Definition: line.c:335
double Vedit_get_min_distance(struct line_pnts *, struct line_pnts *, int, int *)
Calculate distances between two lines.
#define GV_LINES
Definition: dig_defines.h:193
#define GV_FORWARD
Line direction indicator forward/backward.
Definition: dig_defines.h:179
#define GV_BACKWARD
Definition: dig_defines.h:180
struct line_cats * Cats2
int Vedit_merge_lines(struct Map_info *Map, struct ilist *List)
Merge lines/boundaries.
Definition: merge.c:47
struct ps_state ps
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
int * field
Array of layers (fields)
Definition: dig_structs.h:1681
int * cat
Array of categories.
Definition: dig_structs.h:1685
int n_cats
Number of categories attached to element.
Definition: dig_structs.h:1689
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