GRASS 8 Programmer's Manual 8.6.0dev(2026)-55de52a352
Loading...
Searching...
No Matches
vector/Vlib/intersect.c
Go to the documentation of this file.
1/*!
2 \file lib/vector/Vlib/intersect.c
3
4 \brief Vector library - intersection
5
6 Higher level functions for reading/writing/manipulating vectors.
7
8 Some parts of code taken from grass50 v.spag/linecros.c
9
10 Based on the following:
11
12 <code>
13 (ax2-ax1)r1 - (bx2-bx1)r2 = ax2 - ax1
14 (ay2-ay1)r1 - (by2-by1)r2 = ay2 - ay1
15 </code>
16
17 Solving for r1 and r2, if r1 and r2 are between 0 and 1, then line
18 segments (ax1,ay1)(ax2,ay2) and (bx1,by1)(bx2,by2) intersect.
19
20 Intersect 2 line segments.
21
22 Returns: 0 - do not intersect
23 1 - intersect at one point
24 <pre>
25 \ / \ / \ /
26 \/ \/ \/
27 /\ \
28 / \ \
29 2 - partial overlap ( \/ )
30 ------ a ( distance < threshold )
31 ------ b ( )
32 3 - a contains b ( /\ )
33 ---------- a ----------- a
34 ---- b ----- b
35 4 - b contains a
36 ---- a ----- a
37 ---------- b ----------- b
38 5 - identical
39 ---------- a
40 ---------- b
41 </pre>
42 Intersection points:
43 <pre>
44 return point1 breaks: point2 breaks: distance1 on: distance2 on:
45 0 - - - -
46 1 a,b - a b
47 2 a b a b
48 3 a a a a
49 4 b b b b
50 5 - - - -
51 </pre>
52 Sometimes (often) is important to get the same coordinates for a x
53 b and b x a. To reach this, the segments a,b are 'sorted' at the
54 beginning, so that for the same switched segments, results are
55 identical. (reason is that double values are always rounded because
56 of limited number of decimal places and for different order of
57 coordinates, the results would be different)
58
59 SPDX-FileCopyrightText: 2001-2009, 2022 GRASS Development Team
60 SPDX-License-Identifier: GPL-2.0-or-later
61
62 \author Original author CERL, probably Dave Gerdes or Mike Higgins.
63 \author Update to GRASS 5.7 Radim Blazek.
64 */
65
66#include <stdlib.h>
67#include <stdio.h>
68#include <unistd.h>
69#include <math.h>
70#include <grass/vector.h>
71#include <grass/glocale.h>
72
73/* function prototypes */
74static int cmp_cross(const void *pa, const void *pb);
75static void add_cross(int asegment, double adistance, int bsegment,
76 double bdistance, double x, double y);
77static double dist2(double x1, double y1, double x2, double y2);
78
79static int debug_level = -1;
80
81#if 0
82static int ident(double x1, double y1, double x2, double y2, double thresh);
83#endif
84static int cross_seg(int id, const struct RTree_Rect *rect, void *arg);
85static int find_cross(int id, const struct RTree_Rect *rect, void *arg);
87 struct line_pnts *BPoints, int with_z);
88
89#define D ((ax2 - ax1) * (by1 - by2) - (ay2 - ay1) * (bx1 - bx2))
90#define D1 ((bx1 - ax1) * (by1 - by2) - (by1 - ay1) * (bx1 - bx2))
91#define D2 ((ax2 - ax1) * (by1 - ay1) - (ay2 - ay1) * (bx1 - ax1))
92
93/*!
94 * \brief Check for intersect of 2 line segments.
95 *
96 * \param ax1,ay1,az1,ax2,ay2,az2 input line a
97 * \param bx1,by1,bz1,bx2,by2,bz2 input line b
98 * \param[out] x1,y1,z1 intersection point1 (case 2-4)
99 * \param[out] x2,y2,z2 intersection point2 (case 2-4)
100 * \param with_z use z coordinate (3D) (TODO)
101 *
102 * \return 0 - do not intersect,
103 * \return 1 - intersect at one point,
104 * \return 2 - partial overlap,
105 * \return 3 - a contains b,
106 * \return 4 - b contains a,
107 * \return 5 - identical
108 */
109int Vect_segment_intersection(double ax1, double ay1, double az1, double ax2,
110 double ay2, double az2, double bx1, double by1,
111 double bz1, double bx2, double by2, double bz2,
112 double *x1, double *y1, double *z1, double *x2,
113 double *y2, double *z2, int with_z)
114{
115 static int first_3d = 1;
116 double d, d1, d2, r1, dtol, t;
117 int switched;
118 int end_points;
119
120 /* TODO: Works for points ? */
121
122 G_debug(4, "Vect_segment_intersection()");
123 G_debug(4, " %.15g , %.15g - %.15g , %.15g", ax1, ay1, ax2, ay2);
124 G_debug(4, " %.15g , %.15g - %.15g , %.15g", bx1, by1, bx2, by2);
125
126 /* TODO 3D */
127 if (with_z && first_3d) {
128 G_warning(_("3D not supported by Vect_segment_intersection()"));
129 first_3d = 0;
130 }
131
132 *x1 = 0;
133 *y1 = 0;
134 *z1 = 0;
135 *x2 = 0;
136 *y2 = 0;
137 *z2 = 0;
138
139 /* 'Sort' each segment by x, y
140 * MUST happen before D, D1, D2 are calculated */
141 switched = 0;
142 if (bx2 < bx1)
143 switched = 1;
144 else if (bx2 == bx1) {
145 if (by2 < by1)
146 switched = 1;
147 }
148
149 if (switched) {
150 t = bx1;
151 bx1 = bx2;
152 bx2 = t;
153 t = by1;
154 by1 = by2;
155 by2 = t;
156 t = bz1;
157 bz1 = bz2;
158 bz2 = t;
159 }
160
161 switched = 0;
162 if (ax2 < ax1)
163 switched = 1;
164 else if (ax2 == ax1) {
165 if (ay2 < ay1)
166 switched = 1;
167 }
168
169 if (switched) {
170 t = ax1;
171 ax1 = ax2;
172 ax2 = t;
173 t = ay1;
174 ay1 = ay2;
175 ay2 = t;
176 t = az1;
177 az1 = az2;
178 az2 = t;
179 }
180
181 /* Check for identical segments */
182 if (ax1 == bx1 && ay1 == by1 && ax2 == bx2 && ay2 == by2) {
183 G_debug(2, " -> identical segments");
184 *x1 = ax1;
185 *y1 = ay1;
186 *z1 = az1;
187 *x2 = ax2;
188 *y2 = ay2;
189 *z2 = az2;
190 return 5;
191 }
192
193 /* 'Sort' segments by x, y: make sure a <= b
194 * MUST happen before D, D1, D2 are calculated */
195 switched = 0;
196 if (bx1 < ax1)
197 switched = 1;
198 else if (bx1 == ax1) {
199 if (bx2 < ax2)
200 switched = 1;
201 else if (bx2 == ax2) {
202 if (by1 < ay1)
203 switched = 1;
204 else if (by1 == ay1) {
205 if (by2 < ay2)
206 switched = 1;
207 }
208 }
209 }
210
211 if (switched) {
212 t = ax1;
213 ax1 = bx1;
214 bx1 = t;
215 t = ax2;
216 ax2 = bx2;
217 bx2 = t;
218
219 t = ay1;
220 ay1 = by1;
221 by1 = t;
222 t = ay2;
223 ay2 = by2;
224 by2 = t;
225
226 t = az1;
227 az1 = bz1;
228 bz1 = t;
229 t = az2;
230 az2 = bz2;
231 bz2 = t;
232 }
233
234 d = D;
235 d1 = D1;
236 d2 = D2;
237
238 G_debug(2, "Vect_segment_intersection(): d = %f, d1 = %f, d2 = %f", d, d1,
239 d2);
240
241 end_points = 0;
242 if (ax1 == bx1 && ay1 == by1) {
243 end_points = 1;
244 *x1 = ax1;
245 *y1 = ay1;
246 }
247 if (ax1 == bx2 && ay1 == by2) {
248 end_points = 1;
249 *x1 = ax1;
250 *y1 = ay1;
251 }
252 if (ax2 == bx1 && ay2 == by1) {
253 end_points = 2;
254 *x1 = ax2;
255 *y1 = ay2;
256 }
257 if (ax2 == bx2 && ay2 == by2) {
258 end_points = 2;
259 *x1 = ax2;
260 *y1 = ay2;
261 }
262
263 /* TODO: dtol was originally set to 1.0e-10, which was usually working but
264 * not always. Can it be a problem to set the tolerance to 0.0 ? */
265 dtol = 0.0;
266 if (fabs(d) > dtol) {
267
268 G_debug(2, " -> not parallel/collinear: d1 = %f, d2 = %f", d1, d2);
269 if (d > 0) {
270 if (d1 < 0 || d1 > d || d2 < 0 || d2 > d) {
271 if (end_points) {
272 G_debug(
273 2,
274 " -> fp error, but intersection at end points %f, %f",
275 *x1, *y1);
276
277 return 1;
278 }
279 else {
280 G_debug(2, " -> no intersection");
281
282 return 0;
283 }
284 }
285 }
286 else {
287 if (d1 < d || d1 > 0 || d2 < d || d2 > 0) {
288 if (end_points) {
289 G_debug(
290 2,
291 " -> fp error, but intersection at end points %f, %f",
292 *x1, *y1);
293
294 return 1;
295 }
296 else {
297 G_debug(2, " -> no intersection");
298
299 return 0;
300 }
301 }
302 }
303
304 r1 = d1 / d;
305
306 *x1 = ax1 + r1 * (ax2 - ax1);
307 *y1 = ay1 + r1 * (ay2 - ay1);
308 *z1 = 0;
309
310 G_debug(2, " -> intersection %f, %f", *x1, *y1);
311 return 1;
312 }
313
314 /* segments are parallel or collinear */
315 G_debug(3, " -> parallel/collinear");
316
317 if (d1 || d2) { /* lines are parallel */
318 G_debug(2, " -> parallel");
319 if (end_points)
320 G_debug(2, "Segments are apparently parallel, but connected at end "
321 "points -> collinear");
322 else
323 return 0;
324 }
325
326 /* segments are colinear. check for overlap */
327
328 /* Collinear vertical */
329 /* original code assumed lines were not both vertical
330 * so there is a special case if they are */
331 if (ax1 == ax2) {
332 G_debug(2, " -> collinear vertical");
333 if (ay1 > by2 || ay2 < by1) {
334 G_debug(2, " -> no intersection");
335 return 0;
336 }
337
338 /* end points */
339 if (ay1 == by2) {
340 G_debug(2, " -> connected by end points");
341 *x1 = ax1;
342 *y1 = ay1;
343 *z1 = 0;
344
345 return 1; /* endpoints only */
346 }
347 if (ay2 == by1) {
348 G_debug(2, " -> connected by end points");
349 *x1 = ax2;
350 *y1 = ay2;
351 *z1 = 0;
352
353 return 1; /* endpoints only */
354 }
355
356 /* general overlap */
357 G_debug(3, " -> vertical overlap");
358 /* a contains b */
360 G_debug(2, " -> a contains b");
361 *x1 = bx1;
362 *y1 = by1;
363 *z1 = 0;
364 *x2 = bx2;
365 *y2 = by2;
366 *z2 = 0;
367
368 return 3;
369 }
370 /* b contains a */
371 if (ay1 >= by1 && ay2 <= by2) {
372 G_debug(2, " -> b contains a");
373 *x1 = ax1;
374 *y1 = ay1;
375 *z1 = 0;
376 *x2 = ax2;
377 *y2 = ay2;
378 *z2 = 0;
379
380 return 4;
381 }
382
383 /* general overlap, 2 intersection points */
384 G_debug(2, " -> partial overlap");
385 if (by1 > ay1 && by1 < ay2) { /* b1 in a */
386 G_debug(2, " -> b1 in a");
387 *x1 = bx1;
388 *y1 = by1;
389 *z1 = 0;
390 *x2 = ax2;
391 *y2 = ay2;
392 *z2 = 0;
393
394 return 2;
395 }
396 if (by2 > ay1 && by2 < ay2) { /* b2 in a */
397 G_debug(2, " -> b2 in a");
398 *x1 = ax1;
399 *y1 = ay1;
400 *z1 = 0;
401 *x2 = bx2;
402 *y2 = by2;
403 *z2 = 0;
404
405 return 2;
406 }
407
408 /* should not be reached */
409 G_warning(_(
410 "Vect_segment_intersection() ERROR (collinear vertical segments)"));
411 G_warning("a");
412 G_warning("%.15g %.15g", ax1, ay1);
413 G_warning("%.15g %.15g", ax2, ay2);
414 G_warning("b");
415 G_warning("%.15g %.15g", bx1, by1);
416 G_warning("%.15g %.15g", bx2, by2);
417
418 return 0;
419 }
420
421 /* Collinear non vertical */
422
423 G_debug(2, " -> collinear non vertical");
424
425 /* b is to the left or right of a */
426 if ((bx1 > ax2) || (bx2 < ax1)) {
427 /* should not happen if segments are selected from rtree */
428 G_debug(2, " -> no intersection");
429 return 0;
430 }
431
432 /* there is overlap or connected end points */
433 G_debug(2, " -> overlap/connected end points");
434
435 /* end points */
436 if (ax1 == bx2 && ay1 == by2) {
437 G_debug(2, " -> connected by end points");
438 *x1 = ax1;
439 *y1 = ay1;
440 *z1 = 0;
441
442 return 1;
443 }
444 if (ax2 == bx1 && ay2 == by1) {
445 G_debug(2, " -> connected by end points");
446 *x1 = ax2;
447 *y1 = ay2;
448 *z1 = 0;
449
450 return 1;
451 }
452
453 /* a contains b */
455 G_debug(2, " -> a contains b");
456 *x1 = bx1;
457 *y1 = by1;
458 *z1 = 0;
459 *x2 = bx2;
460 *y2 = by2;
461 *z2 = 0;
462
463 return 3;
464 }
465 /* b contains a */
466 if (ax1 >= bx1 && ax2 <= bx2) {
467 G_debug(2, " -> b contains a");
468 *x1 = ax1;
469 *y1 = ay1;
470 *z1 = 0;
471 *x2 = ax2;
472 *y2 = ay2;
473 *z2 = 0;
474
475 return 4;
476 }
477
478 /* general overlap, 2 intersection points (lines are not vertical) */
479 G_debug(2, " -> partial overlap");
480 if (bx1 > ax1 && bx1 < ax2) { /* b1 is in a */
481 G_debug(2, " -> b1 in a");
482 *x1 = bx1;
483 *y1 = by1;
484 *z1 = 0;
485 *x2 = ax2;
486 *y2 = ay2;
487 *z2 = 0;
488
489 return 2;
490 }
491 if (bx2 > ax1 && bx2 < ax2) { /* b2 is in a */
492 G_debug(2, " -> b2 in a");
493 *x1 = ax1;
494 *y1 = ay1;
495 *z1 = 0;
496 *x2 = bx2;
497 *y2 = by2;
498 *z2 = 0;
499
500 return 2;
501 }
502
503 /* should not be reached */
504 G_warning(_(
505 "Vect_segment_intersection() ERROR (collinear non vertical segments)"));
506 G_warning("a");
507 G_warning("%.15g %.15g", ax1, ay1);
508 G_warning("%.15g %.15g", ax2, ay2);
509 G_warning("b");
510 G_warning("%.15g %.15g", bx1, by1);
511 G_warning("%.15g %.15g", bx2, by2);
512
513 return 0;
514}
515
516typedef struct { /* in arrays 0 - A line , 1 - B line */
517 int segment[2]; /* segment number, start from 0 for first */
518 double distance[2];
519 double x, y, z;
520} CROSS;
521
522/* Current line in arrays is for some functions like cmp() set by: */
523static int current;
524static int second; /* line which is not current */
525
526static int a_cross = 0;
527static int n_cross;
528static CROSS *cross = NULL;
529static int *use_cross = NULL;
530
531static void add_cross(int asegment, double adistance, int bsegment,
532 double bdistance, double x, double y)
533{
534 if (n_cross == a_cross) {
535 /* Must be space + 1, used later for last line point, do it better */
536 cross =
537 (CROSS *)G_realloc((void *)cross, (a_cross + 101) * sizeof(CROSS));
538 use_cross =
539 (int *)G_realloc((void *)use_cross, (a_cross + 101) * sizeof(int));
540 a_cross += 100;
541 }
542
543 G_debug(
544 5,
545 " add new cross: aseg/dist = %d/%f bseg/dist = %d/%f, x = %f y = %f",
547 cross[n_cross].segment[0] = asegment;
548 cross[n_cross].distance[0] = adistance;
549 cross[n_cross].segment[1] = bsegment;
550 cross[n_cross].distance[1] = bdistance;
551 cross[n_cross].x = x;
552 cross[n_cross].y = y;
553 n_cross++;
554}
555
556static int cmp_cross(const void *pa, const void *pb)
557{
558 CROSS *p1 = (CROSS *)pa;
559 CROSS *p2 = (CROSS *)pb;
560
561 if (p1->segment[current] < p2->segment[current])
562 return -1;
563 if (p1->segment[current] > p2->segment[current])
564 return 1;
565 /* the same segment */
566 if (p1->distance[current] < p2->distance[current])
567 return -1;
568 if (p1->distance[current] > p2->distance[current])
569 return 1;
570 return 0;
571}
572
573static double dist2(double x1, double y1, double x2, double y2)
574{
575 double dx, dy;
576
577 dx = x2 - x1;
578 dy = y2 - y1;
579 return (dx * dx + dy * dy);
580}
581
582#if 0
583/* returns 1 if points are identical */
584static int ident(double x1, double y1, double x2, double y2, double thresh)
585{
586 double dx, dy;
587
588 dx = x2 - x1;
589 dy = y2 - y1;
590 if ((dx * dx + dy * dy) <= thresh * thresh)
591 return 1;
592
593 return 0;
594}
595#endif
596
597/* shared by Vect_line_intersection, Vect_line_check_intersection, cross_seg,
598 * find_cross */
599static struct line_pnts *APnts, *BPnts;
600
601/* break segments (called by rtree search) */
602static int cross_seg(int id, const struct RTree_Rect *rect G_UNUSED, void *arg)
603{
604 double x1, y1, z1, x2, y2, z2;
605 int i, j, ret;
606
607 /* !!! segment number for B lines is returned as +1 */
608 i = *(int *)arg;
609 j = id - 1;
610 /* Note: -1 to make up for the +1 when data was inserted */
611
613 APnts->x[i], APnts->y[i], APnts->z[i], APnts->x[i + 1], APnts->y[i + 1],
614 APnts->z[i + 1], BPnts->x[j], BPnts->y[j], BPnts->z[j], BPnts->x[j + 1],
615 BPnts->y[j + 1], BPnts->z[j + 1], &x1, &y1, &z1, &x2, &y2, &z2, 0);
616
617 /* add ALL (including end points and duplicates), clean later */
618 if (ret > 0) {
619 G_debug(2, " -> %d x %d: intersection type = %d", i, j, ret);
620 if (ret == 1) { /* one intersection on segment A */
621 G_debug(3, " in %f, %f ", x1, y1);
622 add_cross(i, 0.0, j, 0.0, x1, y1);
623 }
624 else if (ret == 2 || ret == 3 || ret == 4 || ret == 5) {
625 /* partial overlap; a broken in one, b broken in one
626 * or a contains b; a is broken in 2 points (but 1 may be end)
627 * or b contains a; b is broken in 2 points (but 1 may be end)
628 * or identical */
629 G_debug(3, " in %f, %f; %f, %f", x1, y1, x2, y2);
630 add_cross(i, 0.0, j, 0.0, x1, y1);
631 add_cross(i, 0.0, j, 0.0, x2, y2);
632 }
633 }
634 return 1; /* keep going */
635}
636
637/*!
638 * \brief Intersect 2 lines.
639 *
640 * Creates array of new lines created from original A line, by
641 * intersection with B line. Points (Points->n_points == 1) are not
642 * supported.
643 *
644 * Superseded by the faster Vect_line_intersection2()
645 * Kept as reference implementation
646 *
647 * \param APoints first input line
648 * \param BPoints second input line
649 * \param ABox
650 * \param BBox
651 * \param[out] ALines array of new lines created from original A line
652 * \param[out] BLines array of new lines created from original B line
653 * \param[out] nalines number of new lines (ALines)
654 * \param[out] nblines number of new lines (BLines)
655 * \param with_z 3D, not supported!
656 *
657 * \return 0 no intersection
658 * \return 1 intersection found
659 */
661 struct bound_box *ABox, struct bound_box *BBox,
662 struct line_pnts ***ALines,
663 struct line_pnts ***BLines, int *nalines,
664 int *nblines, int with_z G_UNUSED)
665{
666 int i, j, k, l, last_seg, seg, last;
667 int n_alive_cross;
668 double dist, curdist, last_x, last_y, last_z;
669 double x, y, rethresh;
670 struct line_pnts **XLines, *Points;
671 struct RTree *MyRTree;
672 struct line_pnts *Points1, *Points2; /* first, second points */
673 int seg1, seg2, vert1, vert2;
674 static struct RTree_Rect rect;
675 static int rect_init = 0;
676 struct bound_box box, abbox;
677
678 if (debug_level == -1) {
679 const char *dstr = G_getenv_nofatal("DEBUG");
680
681 if (dstr != NULL)
682 debug_level = atoi(dstr);
683 else
684 debug_level = 0;
685 }
686
687 if (!rect_init) {
688 rect.boundary = G_malloc(6 * sizeof(RectReal));
689 rect_init = 6;
690 }
691
692 n_cross = 0;
693 rethresh = 0.000001; /* TODO */
694 APnts = APoints;
695 BPnts = BPoints;
696
697 /* RE (representation error).
698 * RE thresh above is nonsense of course, the RE threshold should be based
699 * on number of significant digits for double (IEEE-754) which is 15 or 16
700 * and exponent. The number above is in fact not required threshold, and
701 * will not work for example: equator length is 40.075,695 km (8 digits),
702 * units are m (+3) and we want precision in mm (+ 3) = 14 -> minimum
703 * rethresh may be around 0.001 ?Maybe all nonsense? Use rounding error of
704 * the unit in the least place ? max of fabs(x), fabs(y) rethresh = pow(2,
705 * log2(max) - 53) */
706
707 /* Warning: This function is also used to intersect the line by itself i.e.
708 * APoints and BPoints are identical. I am not sure if it is clever, but it
709 * seems to work, but we have to keep this in mind and handle some special
710 * cases (maybe) */
711
712 /* TODO: 3D, RE threshold, GV_POINTS (line x point) */
713
714 /* Take each segment from A and intersect by each segment from B.
715 *
716 * All intersections are found first and saved to array, then sorted by a
717 * distance along the line, and then the line is split to pieces.
718 *
719 * Note: If segments are collinear, check if previous/next segments are
720 * also collinear, in that case do not break:
721 * +----------+
722 * +----+-----+ etc.
723 * doesn't need to be broken
724 *
725 * Note: If 2 adjacent segments of line B have common vertex exactly (or
726 * within thresh) on line A, intersection points for these B segments may
727 * differ due to RE:
728 * ------------ a ----+--+---- ----+--+----
729 * /\ => / \ or maybe \/
730 * b0 / \ b1 / \ even: /\
731 *
732 * -> solution: snap all breaks to nearest vertices first within RE
733 * threshold
734 *
735 * Question: Snap all breaks to each other within RE threshold?
736 *
737 * Note: If a break is snapped to end point or two breaks are snapped to
738 * the same vertex resulting new line is degenerated => before line is added
739 * to array, it must be checked if line is not degenerated
740 *
741 * Note: to snap to vertices is important for cases where line A is broken
742 * by B and C line at the same point: \ / b no snap \ /
743 * \/ could ----+--+----
744 * ------ a result
745 * /\ in ?: /\
746 * / \ c / \
747 *
748 * Note: once we snap breaks to vertices, we have to do that for both lines
749 * A and B in the same way and because we cannot be sure that A children
750 * will not change a bit by break(s) we have to break both A and B at once
751 * i.e. in one Vect_line_intersection () call.
752 */
753
754 /* Spatial index: lines may be very long (thousands of segments) and check
755 * each segment with each from second line takes a long time (n*m). Because
756 * of that, spatial index is build first for the second line and segments
757 * from the first line are broken by segments in bound box */
758
759 if (!Vect_box_overlap(ABox, BBox)) {
760 *nalines = 0;
761 *nblines = 0;
762 return 0;
763 }
764
765 abbox = *BBox;
766 if (abbox.N > ABox->N)
767 abbox.N = ABox->N;
768 if (abbox.S < ABox->S)
769 abbox.S = ABox->S;
770 if (abbox.E > ABox->E)
771 abbox.E = ABox->E;
772 if (abbox.W < ABox->W)
773 abbox.W = ABox->W;
774 if (abbox.T > ABox->T)
775 abbox.T = ABox->T;
776 if (abbox.B < ABox->B)
777 abbox.B = ABox->B;
778
779 abbox.N += rethresh;
780 abbox.S -= rethresh;
781 abbox.E += rethresh;
782 abbox.W -= rethresh;
783 abbox.T += rethresh;
784 abbox.B -= rethresh;
785
786 /* Create rtree for B line */
787 MyRTree = RTreeCreateTree(-1, 0, 2);
789 for (i = 0; i < BPoints->n_points - 1; i++) {
790 if (BPoints->x[i] <= BPoints->x[i + 1]) {
791 rect.boundary[0] = BPoints->x[i];
792 rect.boundary[3] = BPoints->x[i + 1];
793 }
794 else {
795 rect.boundary[0] = BPoints->x[i + 1];
796 rect.boundary[3] = BPoints->x[i];
797 }
798
799 if (BPoints->y[i] <= BPoints->y[i + 1]) {
800 rect.boundary[1] = BPoints->y[i];
801 rect.boundary[4] = BPoints->y[i + 1];
802 }
803 else {
804 rect.boundary[1] = BPoints->y[i + 1];
805 rect.boundary[4] = BPoints->y[i];
806 }
807
808 if (BPoints->z[i] <= BPoints->z[i + 1]) {
809 rect.boundary[2] = BPoints->z[i];
810 rect.boundary[5] = BPoints->z[i + 1];
811 }
812 else {
813 rect.boundary[2] = BPoints->z[i + 1];
814 rect.boundary[5] = BPoints->z[i];
815 }
816
817 box.W = rect.boundary[0] - rethresh;
818 box.S = rect.boundary[1] - rethresh;
819 box.B = rect.boundary[2] - rethresh;
820 box.E = rect.boundary[3] + rethresh;
821 box.N = rect.boundary[4] + rethresh;
822 box.T = rect.boundary[5] + rethresh;
823
824 if (Vect_box_overlap(&abbox, &box)) {
826 &rect, i + 1,
827 MyRTree); /* B line segment numbers in rtree start from 1 */
828 }
829 }
830
831 /* Break segments in A by segments in B */
832 for (i = 0; i < APoints->n_points - 1; i++) {
833 if (APoints->x[i] <= APoints->x[i + 1]) {
834 rect.boundary[0] = APoints->x[i];
835 rect.boundary[3] = APoints->x[i + 1];
836 }
837 else {
838 rect.boundary[0] = APoints->x[i + 1];
839 rect.boundary[3] = APoints->x[i];
840 }
841
842 if (APoints->y[i] <= APoints->y[i + 1]) {
843 rect.boundary[1] = APoints->y[i];
844 rect.boundary[4] = APoints->y[i + 1];
845 }
846 else {
847 rect.boundary[1] = APoints->y[i + 1];
848 rect.boundary[4] = APoints->y[i];
849 }
850 if (APoints->z[i] <= APoints->z[i + 1]) {
851 rect.boundary[2] = APoints->z[i];
852 rect.boundary[5] = APoints->z[i + 1];
853 }
854 else {
855 rect.boundary[2] = APoints->z[i + 1];
856 rect.boundary[5] = APoints->z[i];
857 }
858 box.W = rect.boundary[0] - rethresh;
859 box.S = rect.boundary[1] - rethresh;
860 box.B = rect.boundary[2] - rethresh;
861 box.E = rect.boundary[3] + rethresh;
862 box.N = rect.boundary[4] + rethresh;
863 box.T = rect.boundary[5] + rethresh;
864
865 if (Vect_box_overlap(&abbox, &box)) {
866 j = RTreeSearch(MyRTree, &rect, cross_seg,
867 &i); /* A segment number from 0 */
868 }
869 }
870
871 /* Free RTree */
873
874 G_debug(2, "n_cross = %d", n_cross);
875 /* Lines do not cross each other */
876 if (n_cross == 0) {
877 *nalines = 0;
878 *nblines = 0;
879 return 0;
880 }
881
882 /* Snap breaks to nearest vertices within RE threshold */
883 /* Calculate distances along segments */
884 for (i = 0; i < n_cross; i++) {
885
886 /* 1. of A seg */
887 seg = cross[i].segment[0];
888 curdist =
889 dist2(cross[i].x, cross[i].y, APoints->x[seg], APoints->y[seg]);
890 x = APoints->x[seg];
891 y = APoints->y[seg];
892
893 cross[i].distance[0] = curdist;
894
895 /* 2. of A seg */
896 dist = dist2(cross[i].x, cross[i].y, APoints->x[seg + 1],
897 APoints->y[seg + 1]);
898 if (dist < curdist) {
899 curdist = dist;
900 x = APoints->x[seg + 1];
901 y = APoints->y[seg + 1];
902 }
903
904 /* 1. of B seg */
905 seg = cross[i].segment[1];
906 dist = dist2(cross[i].x, cross[i].y, BPoints->x[seg], BPoints->y[seg]);
907 cross[i].distance[1] = dist;
908
909 if (dist < curdist) {
910 curdist = dist;
911 x = BPoints->x[seg];
912 y = BPoints->y[seg];
913 }
914 /* 2. of B seg */
915 dist = dist2(cross[i].x, cross[i].y, BPoints->x[seg + 1],
916 BPoints->y[seg + 1]);
917 if (dist < curdist) {
918 curdist = dist;
919 x = BPoints->x[seg + 1];
920 y = BPoints->y[seg + 1];
921 }
922 if (curdist < rethresh * rethresh) {
923 cross[i].x = x;
924 cross[i].y = y;
925
926 /* Update distances along segments */
927 seg = cross[i].segment[0];
928 cross[i].distance[0] =
929 dist2(APoints->x[seg], APoints->y[seg], cross[i].x, cross[i].y);
930 seg = cross[i].segment[1];
931 cross[i].distance[1] =
932 dist2(BPoints->x[seg], BPoints->y[seg], cross[i].x, cross[i].y);
933 }
934 }
935
936 /* l = 1 ~ line A, l = 2 ~ line B */
937 for (l = 1; l < 3; l++) {
938 for (i = 0; i < n_cross; i++)
939 use_cross[i] = 1;
940
941 /* Create array of lines */
942 XLines = G_malloc((n_cross + 1) * sizeof(struct line_pnts *));
943
944 if (l == 1) {
945 G_debug(2, "Clean and create array for line A");
946 Points = APoints;
949 current = 0;
950 second = 1;
951 }
952 else {
953 G_debug(2, "Clean and create array for line B");
954 Points = BPoints;
957 current = 1;
958 second = 0;
959 }
960
961 /* Sort points along lines */
962 qsort((void *)cross, sizeof(char) * n_cross, sizeof(CROSS), cmp_cross);
963
964 /* Print all (raw) breaks */
965 /* avoid loop when not debugging */
966 if (debug_level > 2) {
967 for (i = 0; i < n_cross; i++) {
968 G_debug(
969 3,
970 " cross = %d seg1/dist1 = %d/%f seg2/dist2 = %d/%f x = %f "
971 "y = %f",
972 i, cross[i].segment[current],
973 sqrt(cross[i].distance[current]), cross[i].segment[second],
974 sqrt(cross[i].distance[second]), cross[i].x, cross[i].y);
975 }
976 }
977
978 /* Remove breaks on first/last line vertices */
979 for (i = 0; i < n_cross; i++) {
980 if (use_cross[i] == 1) {
981 j = Points1->n_points - 1;
982
983 /* Note: */
984 if ((cross[i].segment[current] == 0 &&
985 cross[i].x == Points1->x[0] &&
986 cross[i].y == Points1->y[0]) ||
987 (cross[i].segment[current] == j - 1 &&
988 cross[i].x == Points1->x[j] &&
989 cross[i].y == Points1->y[j])) {
990 use_cross[i] = 0; /* first/last */
991 G_debug(3, "cross %d deleted (first/last point)", i);
992 }
993 }
994 }
995
996 /* Remove breaks with collinear previous and next segments on 1 and 2 */
997 /* Note: breaks with collinear previous and nex must be remove
998 * duplicates, otherwise some cross may be lost. Example (+ is vertex):
999 * B first cross intersections: A/B segment:
1000 * | 0/0, 0/1, 1/0, 1/1 - collinear previous
1001 * and next AB -----+----+--- A 0/4, 0/5, 1/4, 1/5 - OK
1002 * \___|
1003 * B
1004 * This should not influence that break is always on first segment, see
1005 * below (I hope)
1006 */
1007 /* TODO: this doesn't find identical with breaks on revious/next */
1008 for (i = 0; i < n_cross; i++) {
1009 if (use_cross[i] == 0)
1010 continue;
1011 G_debug(3, " is %d between colinear?", i);
1012
1013 seg1 = cross[i].segment[current];
1014 seg2 = cross[i].segment[second];
1015
1016 /* Is it vertex on 1, which? */
1017 if (cross[i].x == Points1->x[seg1] &&
1018 cross[i].y == Points1->y[seg1]) {
1019 vert1 = seg1;
1020 }
1021 else if (cross[i].x == Points1->x[seg1 + 1] &&
1022 cross[i].y == Points1->y[seg1 + 1]) {
1023 vert1 = seg1 + 1;
1024 }
1025 else {
1026 G_debug(3, " -> is not vertex on 1. line");
1027 continue;
1028 }
1029
1030 /* Is it vertex on 2, which? */
1031 /* For 1. line it is easy, because breaks on vertex are always at
1032 * end vertex for 2. line we need to find which vertex is on break
1033 * if any (vert2 starts from 0) */
1034 if (cross[i].x == Points2->x[seg2] &&
1035 cross[i].y == Points2->y[seg2]) {
1036 vert2 = seg2;
1037 }
1038 else if (cross[i].x == Points2->x[seg2 + 1] &&
1039 cross[i].y == Points2->y[seg2 + 1]) {
1040 vert2 = seg2 + 1;
1041 }
1042 else {
1043 G_debug(3, " -> is not vertex on 2. line");
1044 continue;
1045 }
1046 G_debug(3, " seg1/vert1 = %d/%d seg2/ver2 = %d/%d", seg1, vert1,
1047 seg2, vert2);
1048
1049 /* Check if the second vertex is not first/last */
1050 if (vert2 == 0 || vert2 == Points2->n_points - 1) {
1051 G_debug(3, " -> vertex 2 (%d) is first/last", vert2);
1052 continue;
1053 }
1054
1055 /* Are there first vertices of this segment identical */
1056 if (!((Points1->x[vert1 - 1] == Points2->x[vert2 - 1] &&
1057 Points1->y[vert1 - 1] == Points2->y[vert2 - 1] &&
1058 Points1->x[vert1 + 1] == Points2->x[vert2 + 1] &&
1059 Points1->y[vert1 + 1] == Points2->y[vert2 + 1]) ||
1060 (Points1->x[vert1 - 1] == Points2->x[vert2 + 1] &&
1061 Points1->y[vert1 - 1] == Points2->y[vert2 + 1] &&
1062 Points1->x[vert1 + 1] == Points2->x[vert2 - 1] &&
1063 Points1->y[vert1 + 1] == Points2->y[vert2 - 1]))) {
1064 G_debug(3, " -> previous/next are not identical");
1065 continue;
1066 }
1067
1068 use_cross[i] = 0;
1069
1070 G_debug(3, " -> collinear -> remove");
1071 }
1072
1073 /* Remove duplicates, i.e. merge all identical breaks to one.
1074 * We must be careful because two points with identical coordinates may
1075 * be distant if measured along the line: | Segments b0 and b1
1076 * overlap, b0 runs up, b1 down. | Two inersections may be
1077 * merged for a, because they are identical,
1078 * -----+---- a but cannot be merged for b, because both b0 and b1
1079 * must be broken. | I.e. Breaks on b have identical
1080 * coordinates, but there are not identical b0 | b1 if measured
1081 * along line b.
1082 *
1083 * -> Breaks may be merged as identical if lay on the same segment,
1084 * or on vertex connecting 2 adjacent segments the points lay on
1085 *
1086 * Note: if duplicate is on a vertex, the break is removed from next
1087 * segment => break on vertex is always on first segment of this vertex
1088 * (used below)
1089 */
1090 last = -1;
1091 for (i = 0; i < n_cross; i++) {
1092 if (use_cross[i] == 0)
1093 continue;
1094 if (last == -1) { /* set first alive */
1095 last = i;
1096 continue;
1097 }
1098 seg = cross[i].segment[current];
1099 /* compare with last */
1100 G_debug(3, " duplicate ?: cross = %d seg = %d dist = %f", i,
1101 cross[i].segment[current], cross[i].distance[current]);
1102 if ((cross[i].segment[current] == cross[last].segment[current] &&
1103 cross[i].distance[current] == cross[last].distance[current]) ||
1104 (cross[i].segment[current] ==
1105 cross[last].segment[current] + 1 &&
1106 cross[i].distance[current] == 0 &&
1107 cross[i].x == cross[last].x && cross[i].y == cross[last].y)) {
1108 G_debug(3, " cross %d identical to last -> removed", i);
1109 use_cross[i] = 0; /* identical */
1110 }
1111 else {
1112 last = i;
1113 }
1114 }
1115
1116 /* Create array of new lines */
1117 /* Count alive crosses */
1118 n_alive_cross = 0;
1119 G_debug(3, " alive crosses:");
1120 for (i = 0; i < n_cross; i++) {
1121 if (use_cross[i] == 1) {
1122 G_debug(3, " %d", i);
1123 n_alive_cross++;
1124 }
1125 }
1126
1127 k = 0;
1128 if (n_alive_cross > 0) {
1129 /* Add last line point at the end of cross array (cross alley) */
1130 use_cross[n_cross] = 1;
1131 j = Points->n_points - 1;
1132 cross[n_cross].x = Points->x[j];
1133 cross[n_cross].y = Points->y[j];
1134 cross[n_cross].segment[current] = Points->n_points - 2;
1135
1136 last_seg = 0;
1137 last_x = Points->x[0];
1138 last_y = Points->y[0];
1139 last_z = Points->z[0];
1140 /* Go through all cross (+last line point) and create for each new
1141 * line starting at last_* and ending at cross (last point) */
1142 for (i = 0; i <= n_cross; i++) { /* i.e. n_cross + 1 new lines */
1143 seg = cross[i].segment[current];
1144 G_debug(2, "%d seg = %d dist = %f", i, seg,
1145 cross[i].distance[current]);
1146 if (use_cross[i] == 0) {
1147 G_debug(3, " removed -> next");
1148 continue;
1149 }
1150
1151 G_debug(2, " New line:");
1153 /* add last intersection or first point first */
1155 G_debug(2, " append last vert: %f %f", last_x, last_y);
1156
1157 /* add first points of segments between last and current seg */
1158 for (j = last_seg + 1; j <= seg; j++) {
1159 G_debug(2, " segment j = %d", j);
1160 /* skip vertex identical to last break */
1161 if ((j == last_seg + 1) && Points->x[j] == last_x &&
1162 Points->y[j] == last_y) {
1163 G_debug(2, " -> skip (identical to last break)");
1164 continue;
1165 }
1166 Vect_append_point(XLines[k], Points->x[j], Points->y[j],
1167 Points->z[j]);
1168 G_debug(2, " append first of seg: %f %f", Points->x[j],
1169 Points->y[j]);
1170 }
1171
1172 last_seg = seg;
1173 last_x = cross[i].x;
1174 last_y = cross[i].y;
1175 last_z = 0;
1176 /* calculate last_z */
1177 if (Points->z[last_seg] == Points->z[last_seg + 1]) {
1178 last_z = Points->z[last_seg + 1];
1179 }
1180 else if (last_x == Points->x[last_seg] &&
1181 last_y == Points->y[last_seg]) {
1182 last_z = Points->z[last_seg];
1183 }
1184 else if (last_x == Points->x[last_seg + 1] &&
1185 last_y == Points->y[last_seg + 1]) {
1186 last_z = Points->z[last_seg + 1];
1187 }
1188 else {
1189 dist = dist2(Points->x[last_seg], Points->x[last_seg + 1],
1190 Points->y[last_seg], Points->y[last_seg + 1]);
1191 last_z =
1192 (Points->z[last_seg] *
1193 sqrt(cross[i].distance[current]) +
1194 Points->z[last_seg + 1] *
1195 (sqrt(dist) - sqrt(cross[i].distance[current]))) /
1196 sqrt(dist);
1197 }
1198
1199 /* add current cross or end point */
1200 Vect_append_point(XLines[k], cross[i].x, cross[i].y, last_z);
1201 G_debug(2, " append cross / last point: %f %f", cross[i].x,
1202 cross[i].y);
1203
1204 /* Check if line is degenerate */
1205 if (dig_line_degenerate(XLines[k]) > 0) {
1206 G_debug(2, " line is degenerate -> skipped");
1208 }
1209 else {
1210 k++;
1211 }
1212 }
1213 }
1214 if (l == 1) {
1215 *nalines = k;
1216 *ALines = XLines;
1217 }
1218 else {
1219 *nblines = k;
1220 *BLines = XLines;
1221 }
1222 }
1223
1224 /* clean up */
1225
1226 return 1;
1227}
1228
1229static struct line_pnts *APnts, *BPnts, *IPnts;
1230
1231static int cross_found; /* set by find_cross() */
1232static int report_all; /* should all crossings be reported or just first one */
1233
1234/* break segments (called by rtree search) */
1235static int find_cross(int id, const struct RTree_Rect *rect G_UNUSED, void *arg)
1236{
1237 double x1, y1, z1, x2, y2, z2;
1238 int i, j, ret;
1239
1240 /* !!! segment number for B lines is returned as +1 */
1241 i = *(int *)arg;
1242 j = id - 1;
1243 /* Note: -1 to make up for the +1 when data was inserted */
1244
1246 APnts->x[i], APnts->y[i], APnts->z[i], APnts->x[i + 1], APnts->y[i + 1],
1247 APnts->z[i + 1], BPnts->x[j], BPnts->y[j], BPnts->z[j], BPnts->x[j + 1],
1248 BPnts->y[j + 1], BPnts->z[j + 1], &x1, &y1, &z1, &x2, &y2, &z2, 0);
1249
1250 switch (ret) {
1251 case 0:
1252 case 5:
1253 break;
1254 case 1:
1255 if (0 > Vect_append_point(IPnts, x1, y1, z1))
1256 G_warning(_("Error while adding point to array. Out of memory"));
1257 break;
1258 case 2:
1259 case 3:
1260 case 4:
1261 if (0 > Vect_append_point(IPnts, x1, y1, z1))
1262 G_warning(_("Error while adding point to array. Out of memory"));
1263 if (0 > Vect_append_point(IPnts, x2, y2, z2))
1264 G_warning(_("Error while adding point to array. Out of memory"));
1265 break;
1266 }
1267 /* add ALL (including end points and duplicates), clean later */
1268 if (ret > 0) {
1269 cross_found = 1;
1270 if (!report_all)
1271 return 0;
1272 }
1273 return 1; /* keep going */
1274}
1275
1277 struct line_pnts *BPoints, int with_z)
1278{
1279 int i;
1280 double dist, rethresh;
1281 struct RTree *MyRTree;
1282 static struct RTree_Rect rect;
1283 static int rect_init = 0;
1284
1285 if (!rect_init) {
1286 rect.boundary = G_malloc(6 * sizeof(RectReal));
1287 rect_init = 6;
1288 }
1289
1290 rethresh = 0.000001; /* TODO */
1291 APnts = APoints;
1292 BPnts = BPoints;
1293
1294 /* TODO: 3D, RE (representation error) threshold, GV_POINTS (line x point)
1295 */
1296
1297 if (!IPnts)
1298 IPnts = Vect_new_line_struct();
1299 Vect_reset_line(IPnts);
1300
1301 /* If one or both are point (Points->n_points == 1) */
1302 if (APoints->n_points == 1 && BPoints->n_points == 1) {
1303 if (APoints->x[0] == BPoints->x[0] && APoints->y[0] == BPoints->y[0]) {
1304 if (!with_z) {
1305 if (report_all &&
1306 0 > Vect_copy_xyz_to_pnts(IPnts, &APoints->x[0],
1307 &APoints->y[0], NULL, 1))
1308 G_warning(
1309 _("Error while adding point to array. Out of memory"));
1310 return 1;
1311 }
1312 else {
1313 if (APoints->z[0] == BPoints->z[0]) {
1314 if (report_all &&
1315 0 > Vect_copy_xyz_to_pnts(IPnts, &APoints->x[0],
1316 &APoints->y[0],
1317 &APoints->z[0], 1))
1318 G_warning(_("Error while adding point to array. Out of "
1319 "memory"));
1320 return 1;
1321 }
1322 else
1323 return 0;
1324 }
1325 }
1326 else {
1327 return 0;
1328 }
1329 }
1330
1331 if (APoints->n_points == 1) {
1332 Vect_line_distance(BPoints, APoints->x[0], APoints->y[0], APoints->z[0],
1333 with_z, NULL, NULL, NULL, &dist, NULL, NULL);
1334
1335 if (dist <= rethresh) {
1336 if (report_all &&
1337 0 > Vect_copy_xyz_to_pnts(IPnts, &APoints->x[0], &APoints->y[0],
1338 &APoints->z[0], 1))
1339 G_warning(
1340 _("Error while adding point to array. Out of memory"));
1341 return 1;
1342 }
1343 else {
1344 return 0;
1345 }
1346 }
1347
1348 if (BPoints->n_points == 1) {
1349 Vect_line_distance(APoints, BPoints->x[0], BPoints->y[0], BPoints->z[0],
1350 with_z, NULL, NULL, NULL, &dist, NULL, NULL);
1351
1352 if (dist <= rethresh) {
1353 if (report_all &&
1354 0 > Vect_copy_xyz_to_pnts(IPnts, &BPoints->x[0], &BPoints->y[0],
1355 &BPoints->z[0], 1))
1356 G_warning(
1357 _("Error while adding point to array. Out of memory"));
1358 return 1;
1359 }
1360 else
1361 return 0;
1362 }
1363
1364 /* Take each segment from A and find if intersects any segment from B. */
1365
1366 /* Spatial index: lines may be very long (thousands of segments) and check
1367 * each segment with each from second line takes a long time (n*m). Because
1368 * of that, spatial index is build first for the second line and segments
1369 * from the first line are broken by segments in bound box */
1370
1371 /* Create rtree for B line */
1372 MyRTree = RTreeCreateTree(-1, 0, 2);
1374 for (i = 0; i < BPoints->n_points - 1; i++) {
1375 if (BPoints->x[i] <= BPoints->x[i + 1]) {
1376 rect.boundary[0] = BPoints->x[i];
1377 rect.boundary[3] = BPoints->x[i + 1];
1378 }
1379 else {
1380 rect.boundary[0] = BPoints->x[i + 1];
1381 rect.boundary[3] = BPoints->x[i];
1382 }
1383
1384 if (BPoints->y[i] <= BPoints->y[i + 1]) {
1385 rect.boundary[1] = BPoints->y[i];
1386 rect.boundary[4] = BPoints->y[i + 1];
1387 }
1388 else {
1389 rect.boundary[1] = BPoints->y[i + 1];
1390 rect.boundary[4] = BPoints->y[i];
1391 }
1392
1393 if (BPoints->z[i] <= BPoints->z[i + 1]) {
1394 rect.boundary[2] = BPoints->z[i];
1395 rect.boundary[5] = BPoints->z[i + 1];
1396 }
1397 else {
1398 rect.boundary[2] = BPoints->z[i + 1];
1399 rect.boundary[5] = BPoints->z[i];
1400 }
1401
1403 &rect, i + 1,
1404 MyRTree); /* B line segment numbers in rtree start from 1 */
1405 }
1406
1407 /* Find intersection */
1408 cross_found = 0;
1409
1410 for (i = 0; i < APoints->n_points - 1; i++) {
1411 if (APoints->x[i] <= APoints->x[i + 1]) {
1412 rect.boundary[0] = APoints->x[i];
1413 rect.boundary[3] = APoints->x[i + 1];
1414 }
1415 else {
1416 rect.boundary[0] = APoints->x[i + 1];
1417 rect.boundary[3] = APoints->x[i];
1418 }
1419
1420 if (APoints->y[i] <= APoints->y[i + 1]) {
1421 rect.boundary[1] = APoints->y[i];
1422 rect.boundary[4] = APoints->y[i + 1];
1423 }
1424 else {
1425 rect.boundary[1] = APoints->y[i + 1];
1426 rect.boundary[4] = APoints->y[i];
1427 }
1428 if (APoints->z[i] <= APoints->z[i + 1]) {
1429 rect.boundary[2] = APoints->z[i];
1430 rect.boundary[5] = APoints->z[i + 1];
1431 }
1432 else {
1433 rect.boundary[2] = APoints->z[i + 1];
1434 rect.boundary[5] = APoints->z[i];
1435 }
1436
1437 RTreeSearch(MyRTree, &rect, find_cross,
1438 &i); /* A segment number from 0 */
1439
1440 if (!report_all && cross_found) {
1441 break;
1442 }
1443 }
1444
1445 /* Free RTree */
1447
1448 return cross_found;
1449}
1450
1451/*!
1452 * \brief Check if 2 lines intersect.
1453 *
1454 * Points (Points->n_points == 1) are also supported.
1455 *
1456 * Superseded by the faster Vect_line_check_intersection2()
1457 * Kept as reference implementation
1458 *
1459 * \param APoints first input line
1460 * \param BPoints second input line
1461 * \param with_z 3D, not supported (only if one or both are points)!
1462 *
1463 * \return 0 no intersection
1464 * \return 1 intersection found
1465 */
1467 struct line_pnts *BPoints, int with_z)
1468{
1469 report_all = 0;
1470 return line_check_intersection(APoints, BPoints, with_z);
1471}
1472
1473/*!
1474 * \brief Get 2 lines intersection points.
1475 *
1476 * A wrapper around Vect_line_check_intersection() function.
1477 *
1478 * Superseded by the faster Vect_line_get_intersections2()
1479 * Kept as reference implementation
1480 *
1481 * \param APoints first input line
1482 * \param BPoints second input line
1483 * \param[out] IPoints output with intersection points
1484 * \param with_z 3D, not supported (only if one or both are points)!
1485 *
1486 * \return 0 no intersection
1487 * \return 1 intersection found
1488 */
1490 struct line_pnts *BPoints,
1491 struct line_pnts *IPoints, int with_z)
1492{
1493 int ret;
1494
1495 report_all = 1;
1496 IPnts = IPoints;
1498
1499 return ret;
1500}
#define NULL
Definition ccmath.h:32
const char * G_getenv_nofatal(const char *)
Get environment variable.
Definition env.c:403
#define G_realloc(p, n)
Definition defs/gis.h:138
void G_warning(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition defs/gis.h:136
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
int Vect_copy_xyz_to_pnts(struct line_pnts *, const double *, const double *, const double *, int)
Copy points from array to line_pnts structure.
Definition line.c:97
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_box_overlap(const struct bound_box *, const struct bound_box *)
Tests for overlap of two boxes.
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_append_point(struct line_pnts *, double, double, double)
Appends one point to the end of a line.
Definition line.c:146
int dig_line_degenerate(const struct line_pnts *)
Definition angle.c:176
#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 _(str)
Definition glocale.h:10
double l
Definition r_raster.c:37
double t
Definition r_raster.c:37
RectReal * boundary
Definition rtree.h:52
Definition rtree.h:120
Bounding box.
Definition dig_structs.h:62
double W
West.
Definition dig_structs.h:78
double T
Top.
Definition dig_structs.h:82
double S
South.
Definition dig_structs.h:70
double N
North.
Definition dig_structs.h:66
double E
East.
Definition dig_structs.h:74
double B
Bottom.
Definition dig_structs.h:86
Feature geometry info - coordinates.
double * y
Array of Y coordinates.
double * x
Array of X coordinates.
int n_points
Number of points.
double * z
Array of Z coordinates.
int line_check_intersection(struct line_pnts *APoints, struct line_pnts *BPoints, int with_z)
#define D1
#define D2
int Vect_line_check_intersection(struct line_pnts *APoints, struct line_pnts *BPoints, int with_z)
Check if 2 lines intersect.
int Vect_segment_intersection(double ax1, double ay1, double az1, double ax2, double ay2, double az2, double bx1, double by1, double bz1, double bx2, double by2, double bz2, double *x1, double *y1, double *z1, double *x2, double *y2, double *z2, int with_z)
Check for intersect of 2 line segments.
int Vect_line_get_intersections(struct line_pnts *APoints, struct line_pnts *BPoints, struct line_pnts *IPoints, int with_z)
Get 2 lines intersection points.
int Vect_line_intersection(struct line_pnts *APoints, struct line_pnts *BPoints, struct bound_box *ABox, struct bound_box *BBox, struct line_pnts ***ALines, struct line_pnts ***BLines, int *nalines, int *nblines, int with_z)
Intersect 2 lines.
#define D
void RTreeSetOverflow(struct RTree *t, char overflow)
Enable/disable R*-tree forced reinsertion (overflow)
struct RTree * RTreeCreateTree(int fd, off_t rootpos, int ndims)
Create new empty R*-Tree.
int RTreeInsertRect(struct RTree_Rect *r, int tid, struct RTree *t)
Insert an item into a R*-Tree.
void RTreeDestroyTree(struct RTree *t)
Destroy an R*-Tree.
int RTreeSearch(struct RTree *t, struct RTree_Rect *r, SearchHitCallback *shcb, void *cbarg)
Search an R*-Tree.
#define x