GRASS 8 Programmer's Manual 8.6.0dev(2026)-4bb960b182
Loading...
Searching...
No Matches
extend.c
Go to the documentation of this file.
1/*!
2 \file lib/vector/vedit/extend.c
3
4 \brief Vedit library - extend lines (adopted from break.c)
5
6 SPDX-FileCopyrightText: 2017 GRASS Development Team
7 SPDX-License-Identifier: GPL-2.0-or-later
8
9 \author Huidae Cho <grass4u gmail.com>
10 */
11
12#include <math.h>
13#include <grass/vedit.h>
14
15#define TOL 1e-9
16
17static int extend_lines(struct Map_info *, int, int, int, int, double,
18 struct ilist *);
19static int find_extended_intersection(double, double, double, double, double,
20 double, double *, double *);
21static int check_extended_direction(double, double, double, int, double,
22 double);
23
24/*!
25 \brief Extend lines in given threshold
26
27 \code
28 1. Extend first line only
29 \ \
30 id1 \ -> \
31 \
32 id2 ---------- -----+----
33
34
35 2. Extend both lines
36 \ \
37 id1 \ -> \
38 \
39 id2 --- +----
40
41
42 3. Extend first line when both are on the same line
43 id1 --- --- id2 -> -----+----
44
45
46 4. Connect two parallel lines (parallel=1)
47 id1 ------ -------
48 -> /
49 id2 ------ +-----
50
51
52 5. Don't connect two parallel lines (parallel=0)
53 id1 ------ ------
54 ->
55 id2 ------ ------
56 \endcode
57
58 \param Map pointer to Map_info
59 \param List list of selected lines
60 \param nodes 1 for start node, 2 for end node, other for both
61 \param parallel connect parallel lines
62 \param thresh threshold value
63
64 \return number of modified lines
65 */
66int Vedit_extend_lines(struct Map_info *Map, struct ilist *List, int nodes,
67 int parallel, double thresh)
68{
70 int i, j, first_node, n_nodes;
71
73
75
78
79 first_node = 0;
80 n_nodes = 2;
81
82 switch (nodes) {
83 case 1:
84 n_nodes = 1;
85 break;
86 case 2:
87 first_node = 1;
88 break;
89 }
90
91 /* collect lines to be modified */
92 for (i = 0; i < List->n_values; i++) {
93 int line, extended, node[2];
94
95 line = List->value[i];
96
97 if (!Vect_line_alive(Map, line))
98 continue;
99
100 if (Vect_get_line_type(Map, line) & GV_POINTS)
101 continue;
102
103 node[0] = node[1] = -1;
104 Vect_get_line_nodes(Map, line, &(node[0]), &(node[1]));
105 if (node[0] < 0 || node[1] < 0)
106 continue;
107
108 extended = 0;
111 for (j = first_node; j < n_nodes && !extended; j++) {
112 double x, y, z;
113
114 /* for each line node find lines in threshold */
115 Vect_get_node_coor(Map, node[j], &x, &y, &z);
116
117 do {
118 int found;
119
120 /* find first nearest line */
121 found =
124
125 if (found > 0 && Vect_line_alive(Map, found)) {
126 /* try to extend lines (given node) */
127 G_debug(3, "Vedit_extend_lines(): lines=%d,%d", line,
128 found);
129 if (extend_lines(Map, !j, line, found, parallel, thresh,
130 List)) {
131 G_debug(3,
132 "Vedit_extend_lines(): lines=%d,%d -> extended",
133 line, found);
134 nlines_modified += 2;
135 extended = 1;
136 }
137 }
138
140 } while (List_found->n_values > 0 && !extended);
141 }
142 }
143
146
147 return nlines_modified;
148}
149
150int extend_lines(struct Map_info *Map, int first, int line_from, int line_to,
151 int parallel, double thresh, struct ilist *List G_UNUSED)
152{
153 /* TODO: If line_from extends to the i'th segment of line_to but the
154 * line_from node is closest to the j'th segment of line_to, this function
155 * wouldn't work because it only checks intersection of the start/end
156 * segment of line_from and the closest segment of line_to (i'th segment).
157 */
158 int line_new;
159 int type_from, type_to;
160
162 struct line_cats *Cats_from, *Cats_to;
163
169
172
173 line_new = 0;
174 if (!(type_from & GV_LINES) || !(type_to & GV_LINES))
175 line_new = -1;
176
177 /* avoid too much indentation */
178 do {
179 int n_points, seg, is, line_to_extended;
180 double x, y, px, py, x1, y1;
181 double dist, spdist, lpdist, length;
182 double angle_t, angle_f;
183
184 if (line_new == -1)
185 break;
186
187 n_points = Points_from->n_points - 1;
188
189 if (first) {
190 x = Points_from->x[0];
191 y = Points_from->y[0];
192 }
193 else {
194 x = Points_from->x[n_points];
195 y = Points_from->y[n_points];
196 }
197 seg = Vect_line_distance(Points_to, x, y, 0.0, WITHOUT_Z, &px, &py,
198 NULL, &dist, &spdist, &lpdist);
199
200 if (!(seg > 0 && dist > 0.0 && (thresh < 0. || dist <= thresh)))
201 break;
202
203 /* lines in threshold */
204 length = first ? 0 : Vect_line_length(Points_from);
205
206 /* find angles */
208 NULL) ||
210 NULL))
211 break;
212
214
215 /* extend both lines and find intersection */
216 if (!find_extended_intersection(x, y, angle_f, px, py, angle_t, &x1,
217 &y1)) {
218 /* parallel lines */
219 if (!parallel)
220 break;
221
222 x1 = px;
223 y1 = py;
224 if (first)
225 Vect_line_insert_point(Points_from, 0, x1, y1, 0.0);
226 else
227 Vect_append_point(Points_from, x1, y1, 0.0);
228 }
229 else {
230 /* skip if extended into the wrong direction */
231 if (!check_extended_direction(x, y, angle_f, first, x1, y1))
232 break;
233
234 /* skip if extended too far from line_from */
235 if (!Vect_line_distance(Points_from, x1, y1, 0.0, WITHOUT_Z, NULL,
236 NULL, NULL, &dist, NULL, NULL) ||
237 dist > thresh)
238 break;
239
241 NULL, &dist, NULL, NULL);
242 /* if intersection point is not on line_to */
243 if (dist > TOL) {
244 double x2, y2;
245
246 /* skip if not extended from a line_to node */
247 if (seg > 1 && seg < Points_to->n_points - 1)
248 break;
249
250 if (seg == 1) {
252
253 x2 = Points_to->x[0];
254 y2 = Points_to->y[0];
255 }
256 else {
258
259 x2 = Points_to->x[Points_to->n_points - 1];
260 y2 = Points_to->y[Points_to->n_points - 1];
261 }
262
263 /* skip if extended into the wrong direction */
264 if (!check_extended_direction(x2, y2, angle_t, seg == 1, x1,
265 y1))
266 break;
267 }
268 /* otherwise, split line_to later */
269
270 /* lines extended -> extend/split line_to */
271 /* update line_from */
272 if (first) {
273 Points_from->x[0] = x1;
274 Points_from->y[0] = y1;
275 }
276 else {
277 Points_from->x[n_points] = x1;
278 Points_from->y[n_points] = y1;
279 }
280 }
281
283 Cats_from);
284 /* Vect_list_append(List, line_new); */
285
287 if (line_to_extended == 1) {
288 /* extend line_to start node */
289 Vect_append_point(Points_final, x1, y1, 0.0);
290 for (is = 0; is < Points_to->n_points; is++)
292 Points_to->y[is], Points_to->z[is]);
293 line_new =
295 }
296 else if (line_to_extended == 2) {
297 /* extend line_to end node */
298 for (is = 0; is < Points_to->n_points; is++)
300 Points_to->y[is], Points_to->z[is]);
301 Vect_append_point(Points_final, x1, y1, 0.0);
302 line_new =
304 }
305 else {
306 int n_parts = 0;
307
308 /* break line_to */
309 /* update line_to -- first part */
310 for (is = 0; is < seg; is++)
312 Points_to->y[is], Points_to->z[is]);
313 Vect_append_point(Points_final, x1, y1, 0.0);
314
316 n_parts++;
319 /* Vect_list_append(List, line_new); */
320 }
321
322 /* write second part */
324 Vect_append_point(Points_final, x1, y1, 0.0);
325 for (is = seg; is < Points_to->n_points; is++)
327 Points_to->y[is], Points_to->z[is]);
328
330 if (n_parts > 0)
331 line_new =
333 else
336 /* Vect_list_append(List, line_new); */
337 }
338 }
339 } while (0);
340
346
347 return line_new > 0 ? 1 : 0;
348}
349
350static int find_extended_intersection(double x1, double y1, double angle1,
351 double x2, double y2, double angle2,
352 double *x, double *y)
353{
354 double c1, s1, c2, s2, d, a;
355
356 if (fabs(sin(angle1 - angle2)) <= TOL) {
357 /* two lines are parallel */
358 double angle;
359
360 angle = atan2(y2 - y1, x2 - x1);
361 if (fabs(sin(angle - angle1)) <= TOL) {
362 /* they are on the same line */
363 *x = x2;
364 *y = y2;
365
366 return 1;
367 }
368
369 /* two lines don't intersect */
370 return 0;
371 }
372
373 c1 = cos(angle1);
374 s1 = sin(angle1);
375 c2 = cos(angle2);
376 s2 = sin(angle2);
377 d = -c1 * s2 + c2 * s1;
378 if (d == 0.0)
379 /* shouldn't happen again */
380 return 0;
381
382 a = (-s2 * (x2 - x1) + c2 * (y2 - y1)) / d;
383 *x = x1 + a * c1;
384 *y = y1 + a * s1;
385
386 return 1;
387}
388
389static int check_extended_direction(double x, double y, double angle,
390 int start_node, double extx, double exty)
391{
392 double tmp;
393 int xdir, ydir, xext, yext;
394
395 if (start_node)
396 angle += M_PI;
397
398 /* expected directions */
399 tmp = cos(angle);
400 xdir = (fabs(tmp) <= TOL ? 0 : (tmp > 0 ? 1 : -1));
401 tmp = sin(angle);
402 ydir = (fabs(tmp) <= TOL ? 0 : (tmp > 0 ? 1 : -1));
403
404 /* extended directions */
405 tmp = extx - x;
406 xext = (fabs(tmp) <= TOL ? 0 : (tmp > 0 ? 1 : -1));
407 tmp = exty - y;
408 yext = (fabs(tmp) <= TOL ? 0 : (tmp > 0 ? 1 : -1));
409
410 if (xext != 0 && yext != 0) {
411 /* no if extended into the wrong direction */
412 if (xdir / xext <= 0 || ydir / yext <= 0)
413 return 0;
414 /* otherwise, ok */
415 }
416 else if (xext == 0 && yext == 0) {
417 /* snapped to the node, ok */
418 }
419 else if (xext == 0) {
420 /* vertical extension */
421 /* no if not expected or extended into the wrong direction */
422 if (xdir != 0 || ydir / yext <= 0)
423 return 0;
424 /* otherwise, ok */
425 }
426 else {
427 /* horizontal extension */
428 /* no if not expected or extended into the wrong direction */
429 if (ydir != 0 || xdir / xext <= 0)
430 return 0;
431 /* otherwise, ok */
432 }
433
434 return 1;
435}
#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:75
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:302
int Vect_get_node_coor(struct Map_info *, int, double *, double *, double *)
Get node coordinates.
Definition level_two.c:272
double Vect_line_length(const struct line_pnts *)
Calculate line length, 3D-length in case of 3D vector line.
Definition line.c:573
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:411
int Vect_get_line_type(struct Map_info *, int)
Get line type.
Definition level_two.c:252
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:646
int Vect_line_alive(struct Map_info *, int)
Check if feature is alive or dead (topological level required)
struct line_cats * Vect_new_cats_struct(void)
Creates and initializes line_cats structure.
struct ilist * Vect_new_list(void)
Creates and initializes a struct ilist.
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:174
off_t Vect_write_line(struct Map_info *, int, const struct line_pnts *, const struct line_cats *)
Writes a new feature.
void Vect_reset_line(struct line_pnts *)
Reset line.
Definition line.c:127
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition line.c:43
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:146
#define GV_LINES
#define WITHOUT_Z
2D/3D vector data
#define GV_POINTS
#define TOL
Definition extend.c:15
int Vedit_extend_lines(struct Map_info *Map, struct ilist *List, int nodes, int parallel, double thresh)
Extend lines in given threshold.
Definition extend.c:66
#define G_UNUSED
A macro for an attribute, if attached to a variable, indicating that the variable is not used.
Definition gis.h:43
#define M_PI
Definition gis.h:154
Vector map info.
List of integers.
Definition gis.h:712
Feature category info.
Feature geometry info - coordinates.
#define x