GRASS 8 Programmer's Manual 8.6.0dev(2026)-4bb960b182
Loading...
Searching...
No Matches
intersect2.c
Go to the documentation of this file.
1/*!
2 \file lib/vector/Vlib/intersect2.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-2014, 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 \author Update to GRASS 7 Markus Metz.
65 */
66
67#include <stdlib.h>
68#include <stdio.h>
69#include <unistd.h>
70#include <math.h>
71#include <grass/vector.h>
72#include <grass/rbtree.h>
73#include <grass/glocale.h>
74
75/* function prototypes */
76static int cmp_cross(const void *pa, const void *pb);
77static void add_cross(int asegment, double adistance, int bsegment,
78 double bdistance, double x, double y);
79static double dist2(double x1, double y1, double x2, double y2);
80
81static int debug_level = -1;
82
83#if 0
84static int ident(double x1, double y1, double x2, double y2, double thresh);
85#endif
86static int snap_cross(int asegment, double *adistance, int bsegment,
87 double *bdistance, double *xc, double *yc);
88static int cross_seg(int i, int j, int b);
89static int find_cross(int i, int j, int b);
91 struct line_pnts *BPoints, int with_z, int all);
92
93typedef struct { /* in arrays 0 - A line , 1 - B line */
94 int segment[2]; /* segment number, start from 0 for first */
95 double distance[2];
96 double x, y, z;
97} CROSS;
98
99/* Current line in arrays is for some functions like cmp() set by: */
100static int current;
101static int second; /* line which is not current */
102
103static int a_cross = 0;
104static int n_cross;
105static CROSS *cross = NULL;
106static int *use_cross = NULL;
107
108/* static double rethresh = 0.000001; */ /* TODO */
109
110static double d_ulp(double a, double b)
111{
112 double fa = fabs(a);
113 double fb = fabs(b);
114 double dmax, result;
115 int exp;
116
117 dmax = fa;
118 if (dmax < fb)
119 dmax = fb;
120
121 /* unit in the last place (ULP):
122 * smallest representable difference
123 * shift of the exponent
124 * float: 23, double: 52, middle: 37.5 */
125 result = frexp(dmax, &exp);
126 exp -= 38;
127 result = ldexp(result, exp);
128
129 return result;
130}
131
132static void add_cross(int asegment, double adistance, int bsegment,
133 double bdistance, double x, double y)
134{
135 if (n_cross == a_cross) {
136 /* Must be space + 1, used later for last line point, do it better */
137 cross =
138 (CROSS *)G_realloc((void *)cross, (a_cross + 101) * sizeof(CROSS));
139 use_cross =
140 (int *)G_realloc((void *)use_cross, (a_cross + 101) * sizeof(int));
141 a_cross += 100;
142 }
143
144 G_debug(
145 5,
146 " add new cross: aseg/dist = %d/%f bseg/dist = %d/%f, x = %f y = %f",
148 cross[n_cross].segment[0] = asegment;
149 cross[n_cross].distance[0] = adistance;
150 cross[n_cross].segment[1] = bsegment;
151 cross[n_cross].distance[1] = bdistance;
152 cross[n_cross].x = x;
153 cross[n_cross].y = y;
154 n_cross++;
155}
156
157static int cmp_cross(const void *pa, const void *pb)
158{
159 CROSS *p1 = (CROSS *)pa;
160 CROSS *p2 = (CROSS *)pb;
161
162 if (p1->segment[current] < p2->segment[current])
163 return -1;
164 if (p1->segment[current] > p2->segment[current])
165 return 1;
166 /* the same segment */
167 if (p1->distance[current] < p2->distance[current])
168 return -1;
169 if (p1->distance[current] > p2->distance[current])
170 return 1;
171 return 0;
172}
173
174static double dist2(double x1, double y1, double x2, double y2)
175{
176 double dx, dy;
177
178 dx = x2 - x1;
179 dy = y2 - y1;
180 return (dx * dx + dy * dy);
181}
182
183#if 0
184/* returns 1 if points are identical */
185static int ident(double x1, double y1, double x2, double y2, double thresh)
186{
187 double dx, dy;
188
189 dx = x2 - x1;
190 dy = y2 - y1;
191 if ((dx * dx + dy * dy) <= thresh * thresh)
192 return 1;
193
194 return 0;
195}
196#endif
197
198/* shared by Vect_line_intersection, Vect_line_check_intersection, cross_seg,
199 * find_cross */
200static struct line_pnts *APnts, *BPnts, *ABPnts[2], *IPnts;
201
202/* Snap breaks to nearest vertices within RE threshold */
203/* Calculate distances along segments */
204static int snap_cross(int asegment, double *adistance, int bsegment,
205 double *bdistance, double *xc, double *yc)
206{
207 int seg;
208 double x, y;
209 double dist, curdist, dthresh;
210
211 /* 1. of A seg */
212 seg = asegment;
213 curdist = dist2(*xc, *yc, APnts->x[seg], APnts->y[seg]);
214 x = APnts->x[seg];
215 y = APnts->y[seg];
216
218
219 /* 2. of A seg */
220 dist = dist2(*xc, *yc, APnts->x[seg + 1], APnts->y[seg + 1]);
221 if (dist < curdist) {
222 curdist = dist;
223 x = APnts->x[seg + 1];
224 y = APnts->y[seg + 1];
225 }
226
227 /* 1. of B seg */
228 seg = bsegment;
229 dist = dist2(*xc, *yc, BPnts->x[seg], BPnts->y[seg]);
230 *bdistance = dist;
231
232 if (dist < curdist) {
233 curdist = dist;
234 x = BPnts->x[seg];
235 y = BPnts->y[seg];
236 }
237 /* 2. of B seg */
238 dist = dist2(*xc, *yc, BPnts->x[seg + 1], BPnts->y[seg + 1]);
239 if (dist < curdist) {
240 curdist = dist;
241 x = BPnts->x[seg + 1];
242 y = BPnts->y[seg + 1];
243 }
244
245 /* the threshold should not be too small, otherwise we get
246 * too many tiny new segments
247 * the threshold should not be too large, otherwise we might
248 * introduce new crossings
249 * the smallest difference representable with
250 * single precision floating point works well with pathological input
251 * regular input is not affected */
252 dthresh = d_ulp(x, y);
253 if (curdist < dthresh * dthresh) { /* was rethresh * rethresh */
254 *xc = x;
255 *yc = y;
256
257 /* Update distances along segments */
258 seg = asegment;
259 *adistance = dist2(*xc, *yc, APnts->x[seg], APnts->y[seg]);
260 seg = bsegment;
261 *bdistance = dist2(*xc, *yc, BPnts->x[seg], BPnts->y[seg]);
262
263 return 1;
264 }
265
266 return 0;
267}
268
269/* break segments */
270static int cross_seg(int i, int j, int b)
271{
272 double x1, y1, z1, x2, y2, z2;
273 double y1min, y1max, y2min, y2max;
274 double adist, bdist;
275 int ret;
276
277 y1min = APnts->y[i];
278 y1max = APnts->y[i + 1];
279 if (APnts->y[i] > APnts->y[i + 1]) {
280 y1min = APnts->y[i + 1];
281 y1max = APnts->y[i];
282 }
283
284 y2min = BPnts->y[j];
285 y2max = BPnts->y[j + 1];
286 if (BPnts->y[j] > BPnts->y[j + 1]) {
287 y2min = BPnts->y[j + 1];
288 y2max = BPnts->y[j];
289 }
290
291 if (y1min > y2max || y1max < y2min)
292 return 0;
293
294 if (b) {
296 APnts->x[i], APnts->y[i], APnts->z[i], APnts->x[i + 1],
297 APnts->y[i + 1], APnts->z[i + 1], BPnts->x[j], BPnts->y[j],
298 BPnts->z[j], BPnts->x[j + 1], BPnts->y[j + 1], BPnts->z[j + 1], &x1,
299 &y1, &z1, &x2, &y2, &z2, 0);
300 }
301 else {
303 BPnts->x[j], BPnts->y[j], BPnts->z[j], BPnts->x[j + 1],
304 BPnts->y[j + 1], BPnts->z[j + 1], APnts->x[i], APnts->y[i],
305 APnts->z[i], APnts->x[i + 1], APnts->y[i + 1], APnts->z[i + 1], &x1,
306 &y1, &z1, &x2, &y2, &z2, 0);
307 }
308
309 /* add ALL (including end points and duplicates), clean later */
310 if (ret > 0) {
311 G_debug(2, " -> %d x %d: intersection type = %d", i, j, ret);
312 if (ret == 1) { /* one intersection on segment A */
313 G_debug(3, " in %f, %f ", x1, y1);
314 /* snap intersection only once */
315 snap_cross(i, &adist, j, &bdist, &x1, &y1);
316 add_cross(i, adist, j, bdist, x1, y1);
317 if (APnts == BPnts)
318 add_cross(j, bdist, i, adist, x1, y1);
319 }
320 else if (ret == 2 || ret == 3 || ret == 4 || ret == 5) {
321 /* partial overlap; a broken in one, b broken in one
322 * or a contains b; a is broken in 2 points (but 1 may be end)
323 * or b contains a; b is broken in 2 points (but 1 may be end)
324 * or identical */
325 G_debug(3, " in %f, %f; %f, %f", x1, y1, x2, y2);
326 snap_cross(i, &adist, j, &bdist, &x1, &y1);
327 add_cross(i, adist, j, bdist, x1, y1);
328 if (APnts == BPnts)
329 add_cross(j, bdist, i, adist, x1, y1);
330 snap_cross(i, &adist, j, &bdist, &x2, &y2);
331 add_cross(i, adist, j, bdist, x2, y2);
332 if (APnts == BPnts)
333 add_cross(j, bdist, i, adist, x2, y2);
334 }
335 }
336 return 1; /* keep going */
337}
338
339/* event queue for Bentley-Ottmann */
340#define QEVT_IN 1
341#define QEVT_OUT 2
342#define QEVT_CRS 3
343
344#define GET_PARENT(p, c) ((p) = (int)(((c) - 2) / 3 + 1))
345#define GET_CHILD(c, p) ((c) = (int)(((p) * 3) - 1))
346
347struct qitem {
348 int l; /* line 0 - A line , 1 - B line */
349 int s; /* segment index */
350 int p; /* point index */
351 int e; /* event type */
352};
353
354struct boq {
355 int count;
356 int alloc;
357 struct qitem *i;
358};
359
360/* compare two queue points */
361/* return 1 if a < b else 0 */
362static int cmp_q_x(struct qitem *a, struct qitem *b)
363{
364 double x1, y1, z1, x2, y2, z2;
365
366 x1 = ABPnts[a->l]->x[a->p];
367 y1 = ABPnts[a->l]->y[a->p];
368 z1 = ABPnts[a->l]->z[a->p];
369
370 x2 = ABPnts[b->l]->x[b->p];
371 y2 = ABPnts[b->l]->y[b->p];
372 z2 = ABPnts[b->l]->z[b->p];
373
374 if (x1 < x2)
375 return 1;
376 if (x1 > x2)
377 return 0;
378
379 if (y1 < y2)
380 return 1;
381 if (y1 > y2)
382 return 0;
383
384 if (z1 < z2)
385 return 1;
386 if (z1 > z2)
387 return 0;
388
389 if (a->e < b->e)
390 return 1;
391
392 if (a->l < b->l)
393 return 1;
394
395 if (a->s < b->s)
396 return 1;
397
398 return 0;
399}
400
401/* sift up routine for min heap */
402static int sift_up(struct boq *q, int start)
403{
404 register int parent, child;
405 struct qitem a, *b;
406
407 child = start;
408 a = q->i[child];
409
410 while (child > 1) {
411 GET_PARENT(parent, child);
412
413 b = &q->i[parent];
414 /* child smaller */
415 if (cmp_q_x(&a, b)) {
416 /* push parent point down */
417 q->i[child] = q->i[parent];
418 child = parent;
419 }
420 else
421 /* no more sifting up, found new slot for child */
422 break;
423 }
424
425 /* put point in new slot */
426 if (child < start) {
427 q->i[child] = a;
428 }
429
430 return child;
431}
432
433static int boq_add(struct boq *q, struct qitem *i)
434{
435 if (q->count + 2 >= q->alloc) {
436 q->alloc = q->count + 100;
437 q->i = G_realloc(q->i, q->alloc * sizeof(struct qitem));
438 }
439 q->i[q->count + 1] = *i;
440 sift_up(q, q->count + 1);
441
442 q->count++;
443
444 return 1;
445}
446
447/* drop point routine for min heap */
448static int boq_drop(struct boq *q, struct qitem *qi)
449{
450 register int child, childr, parent;
451 register int i;
452 struct qitem *a, *b;
453
454 if (q->count == 0)
455 return 0;
456
457 *qi = q->i[1];
458
459 if (q->count == 1) {
460 q->count = 0;
461 return 1;
462 }
463
464 /* start with root */
465 parent = 1;
466
467 /* sift down: move hole back towards bottom of heap */
468
469 while (GET_CHILD(child, parent) <= q->count) {
470 a = &q->i[child];
471 i = child + 3;
472 for (childr = child + 1; childr <= q->count && childr < i; childr++) {
473 b = &q->i[childr];
474 if (cmp_q_x(b, a)) {
475 child = childr;
476 a = &q->i[child];
477 }
478 }
479
480 /* move hole down */
481 q->i[parent] = q->i[child];
482 parent = child;
483 }
484
485 /* hole is in lowest layer, move to heap end */
486 if (parent < q->count) {
487 q->i[parent] = q->i[q->count];
488
489 /* sift up last swapped point, only necessary if hole moved to heap end
490 */
491 sift_up(q, parent);
492 }
493
494 /* the actual drop */
495 q->count--;
496
497 return 1;
498}
499
500/* compare two tree points */
501/* return -1 if a < b, 1 if a > b, 0 if a == b */
502static int cmp_t_y(const void *aa, const void *bb)
503{
504 double x1, y1, z1, x2, y2, z2;
505 struct qitem *a = (struct qitem *)aa;
506 struct qitem *b = (struct qitem *)bb;
507
508 x1 = ABPnts[a->l]->x[a->p];
509 y1 = ABPnts[a->l]->y[a->p];
510 z1 = ABPnts[a->l]->z[a->p];
511
512 x2 = ABPnts[b->l]->x[b->p];
513 y2 = ABPnts[b->l]->y[b->p];
514 z2 = ABPnts[b->l]->z[b->p];
515
516 if (y1 < y2)
517 return -1;
518 if (y1 > y2)
519 return 1;
520
521 if (x1 < x2)
522 return -1;
523 if (x1 > x2)
524 return 1;
525
526 if (z1 < z2)
527 return -1;
528 if (z1 > z2)
529 return 1;
530
531 if (a->s < b->s)
532 return -1;
533 if (a->s > b->s)
534 return 1;
535
536 return 0;
537}
538
539static int boq_load(struct boq *q, struct line_pnts *Pnts,
540 struct bound_box *abbox, int l, int with_z)
541{
542 int i, loaded;
543 int vi, vo;
544 double x1, y1, z1, x2, y2, z2;
545 struct bound_box box;
546 struct qitem qi;
547
548 /* load Pnts to queue */
549 qi.l = l;
550 loaded = 0;
551
552 for (i = 0; i < Pnts->n_points - 1; i++) {
553 x1 = Pnts->x[i];
554 y1 = Pnts->y[i];
555 z1 = Pnts->z[i];
556
557 x2 = Pnts->x[i + 1];
558 y2 = Pnts->y[i + 1];
559 z2 = Pnts->z[i + 1];
560
561 if (x1 == x2 && y1 == y2 && (!with_z || z1 == z2))
562 continue;
563
564 if (x1 < x2) {
565 box.W = x1;
566 box.E = x2;
567 }
568 else {
569 box.E = x1;
570 box.W = x2;
571 }
572 if (y1 < y2) {
573 box.S = y1;
574 box.N = y2;
575 }
576 else {
577 box.N = y1;
578 box.S = y2;
579 }
580 if (z1 < z2) {
581 box.B = z1;
582 box.T = z2;
583 }
584 else {
585 box.T = z1;
586 box.B = z2;
587 }
588 box.W -= d_ulp(box.W, box.W);
589 box.S -= d_ulp(box.S, box.S);
590 box.B -= d_ulp(box.B, box.B);
591 box.E += d_ulp(box.E, box.E);
592 box.N += d_ulp(box.N, box.N);
593 box.T += d_ulp(box.T, box.T);
594
595 if (!Vect_box_overlap(abbox, &box))
596 continue;
597
598 vi = i;
599 vo = i + 1;
600
601 if (x1 < x2) {
602 vi = i;
603 vo = i + 1;
604 }
605 else if (x1 > x2) {
606 vi = i + 1;
607 vo = i;
608 }
609 else {
610 if (y1 < y2) {
611 vi = i;
612 vo = i + 1;
613 }
614 else if (y1 > y2) {
615 vi = i + 1;
616 vo = i;
617 }
618 else {
619 if (z1 < z2) {
620 vi = i;
621 vo = i + 1;
622 }
623 else if (z1 > z2) {
624 vi = i + 1;
625 vo = i;
626 }
627 else {
628 G_fatal_error("Identical points");
629 }
630 }
631 }
632
633 qi.s = i;
634
635 /* event in */
636 qi.e = QEVT_IN;
637 qi.p = vi;
638 boq_add(q, &qi);
639
640 /* event out */
641 qi.e = QEVT_OUT;
642 qi.p = vo;
643 boq_add(q, &qi);
644
645 loaded += 2;
646 }
647
648 return loaded;
649}
650
651/*!
652 * \brief Intersect 2 lines.
653 *
654 * Creates array of new lines created from original A line, by
655 * intersection with B line. Points (Points->n_points == 1) are not
656 * supported. If B line is NULL, A line is intersected with itself.
657 *
658 * simplified Bentley–Ottmann Algorithm:
659 * similar to Vect_line_intersection(), but faster
660 * additionally, self-intersections of a line are handled more efficiently
661 *
662 * \param APoints first input line
663 * \param BPoints second input line or NULL
664 * \param[out] ALines array of new lines created from original A line
665 * \param[out] BLines array of new lines created from original B line
666 * \param pABox
667 * \param pBBox
668 * \param[out] nalines number of new lines (ALines)
669 * \param[out] nblines number of new lines (BLines)
670 * \param with_z 3D, not supported!
671 *
672 * \return 0 no intersection
673 * \return 1 intersection found
674 */
676 struct line_pnts *BPoints, struct bound_box *pABox,
677 struct bound_box *pBBox, struct line_pnts ***ALines,
678 struct line_pnts ***BLines, int *nalines,
679 int *nblines, int with_z)
680{
681 int i, j, k, l, nl, last_seg, seg, last;
682 int n_alive_cross;
683 double dist, last_x, last_y, last_z;
684 struct line_pnts **XLines, *Points;
685 struct line_pnts *Points1, *Points2; /* first, second points */
686 int seg1, seg2, vert1, vert2;
687 struct bound_box ABox, BBox, abbox;
688 struct boq bo_queue;
689 struct qitem qi, *found;
690 struct RB_TREE *bo_ta, *bo_tb;
691 struct RB_TRAV bo_t_trav;
692 int same = 0;
693
694 if (debug_level == -1) {
695 const char *dstr = G_getenv_nofatal("DEBUG");
696
697 if (dstr != NULL)
698 debug_level = atoi(dstr);
699 else
700 debug_level = 0;
701 }
702
703 n_cross = 0;
704 APnts = APoints;
705 BPnts = BPoints;
706
707 same = 0;
708 if (!BPoints) {
709 BPnts = APoints;
710 same = 1;
711 }
712
713 ABPnts[0] = APnts;
714 ABPnts[1] = BPnts;
715
716 *nalines = 0;
717 *nblines = 0;
718
719 /* RE (representation error).
720 * RE thresh above is nonsense of course, the RE threshold should be based
721 * on number of significant digits for double (IEEE-754) which is 15 or 16
722 * and exponent. The number above is in fact not required threshold, and
723 * will not work for example: equator length is 40.075,695 km (8 digits),
724 * units are m (+3) and we want precision in mm (+ 3) = 14 -> minimum
725 * rethresh may be around 0.001 ?Maybe all nonsense? Use rounding error of
726 * the unit in the last place ? max of fabs(x), fabs(y) rethresh = pow(2,
727 * log2(max) - 53) */
728
729 /* Warning: This function is also used to intersect the line by itself i.e.
730 * APoints and BPoints are identical. I am not sure if it is clever, but it
731 * seems to work, but we have to keep this in mind and handle some special
732 * cases (maybe) */
733
734 /* TODO: 3D, RE threshold, GV_POINTS (line x point) */
735
736 /* Take each segment from A and intersect by each segment from B.
737 *
738 * All intersections are found first and saved to array, then sorted by a
739 * distance along the line, and then the line is split to pieces.
740 *
741 * Note: If segments are collinear, check if previous/next segments are
742 * also collinear, in that case do not break:
743 * +----------+
744 * +----+-----+ etc.
745 * doesn't need to be broken
746 *
747 * Note: If 2 adjacent segments of line B have common vertex exactly (or
748 * within thresh) on line A, intersection points for these B segments may
749 * differ due to RE:
750 * ------------ a ----+--+---- ----+--+----
751 * /\ => / \ or maybe \/
752 * b0 / \ b1 / \ even: /\
753 *
754 * -> solution: snap all breaks to nearest vertices first within RE
755 * threshold
756 *
757 * Question: Snap all breaks to each other within RE threshold?
758 *
759 * Note: If a break is snapped to end point or two breaks are snapped to
760 * the same vertex resulting new line is degenerated => before line is added
761 * to array, it must be checked if line is not degenerated
762 *
763 * Note: to snap to vertices is important for cases where line A is broken
764 * by B and C line at the same point: \ / b no snap \ /
765 * \/ could ----+--+----
766 * ------ a result
767 * /\ in ?: /\
768 * / \ c / \
769 *
770 * Note: once we snap breaks to vertices, we have to do that for both lines
771 * A and B in the same way and because we cannot be sure that A children
772 * will not change a bit by break(s) we have to break both A and B at once
773 * i.e. in one Vect_line_intersection () call.
774 */
775
776 /* don't modify original bboxes: make a copy of the bboxes */
777 ABox = *pABox;
778 BBox = *pBBox;
779 if (!with_z) {
780 ABox.T = BBox.T = PORT_DOUBLE_MAX;
781 ABox.B = BBox.B = -PORT_DOUBLE_MAX;
782 }
783
784 if (!same && !Vect_box_overlap(&ABox, &BBox)) {
785 return 0;
786 }
787
788 /* overlap box of A line and B line */
789 abbox = BBox;
790 if (!same) {
791 if (abbox.N > ABox.N)
792 abbox.N = ABox.N;
793 if (abbox.S < ABox.S)
794 abbox.S = ABox.S;
795 if (abbox.E > ABox.E)
796 abbox.E = ABox.E;
797 if (abbox.W < ABox.W)
798 abbox.W = ABox.W;
799
800 if (with_z) {
801 if (abbox.T > BBox.T)
802 abbox.T = BBox.T;
803 if (abbox.B < BBox.B)
804 abbox.B = BBox.B;
805 }
806 }
807
808 abbox.N += d_ulp(abbox.N, abbox.N);
809 abbox.S -= d_ulp(abbox.S, abbox.S);
810 abbox.E += d_ulp(abbox.E, abbox.E);
811 abbox.W -= d_ulp(abbox.W, abbox.W);
812 if (with_z) {
813 abbox.T += d_ulp(abbox.T, abbox.T);
814 abbox.B -= d_ulp(abbox.B, abbox.B);
815 }
816
817 if (APnts->n_points < 2 || BPnts->n_points < 2) {
818 G_fatal_error("Intersection with points is not yet supported");
819 return 0;
820 }
821
822 /* initialize queue */
823 bo_queue.count = 0;
824 bo_queue.alloc = 2 * (APnts->n_points + BPnts->n_points);
825 bo_queue.i = G_malloc(bo_queue.alloc * sizeof(struct qitem));
826
827 /* load APnts to queue */
828 boq_load(&bo_queue, APnts, &abbox, 0, with_z);
829
830 if (!same) {
831 /* load BPnts to queue */
832 boq_load(&bo_queue, BPnts, &abbox, 1, with_z);
833 }
834
835 /* initialize search tree */
836 bo_ta = rbtree_create(cmp_t_y, sizeof(struct qitem));
837 if (same)
838 bo_tb = bo_ta;
839 else
840 bo_tb = rbtree_create(cmp_t_y, sizeof(struct qitem));
841
842 /* find intersections */
843 while (boq_drop(&bo_queue, &qi)) {
844
845 if (qi.e == QEVT_IN) {
846 /* not the original Bentley-Ottmann algorithm */
847 if (qi.l == 0) {
848 /* test for intersection of s with all segments in T */
850 while ((found = rbtree_traverse(&bo_t_trav))) {
851 cross_seg(qi.s, found->s, 0);
852 }
853
854 /* insert s in T */
856 }
857 else {
858 /* test for intersection of s with all segments in T */
860 while ((found = rbtree_traverse(&bo_t_trav))) {
861 cross_seg(found->s, qi.s, 1);
862 }
863
864 /* insert s in T */
866 }
867 }
868 else if (qi.e == QEVT_OUT) {
869 /* remove from T */
870
871 /* adjust p */
872 if (qi.p == qi.s)
873 qi.p++;
874 else
875 qi.p--;
876
877 if (qi.l == 0) {
878 if (!rbtree_remove(bo_ta, &qi))
879 G_fatal_error("RB tree error!");
880 }
881 else {
882 if (!rbtree_remove(bo_tb, &qi))
883 G_fatal_error("RB tree error!");
884 }
885 }
886 }
887 G_free(bo_queue.i);
889 if (!same)
891
892 G_debug(2, "n_cross = %d", n_cross);
893 /* Lines do not cross each other */
894 if (n_cross == 0) {
895 return 0;
896 }
897
898 /* l = 1 ~ line A, l = 2 ~ line B */
899 nl = 3;
900 if (same)
901 nl = 2;
902 for (l = 1; l < nl; l++) {
903 for (i = 0; i < n_cross; i++)
904 use_cross[i] = 1;
905
906 /* Create array of lines */
907 XLines = G_malloc((n_cross + 1) * sizeof(struct line_pnts *));
908
909 if (l == 1) {
910 G_debug(2, "Clean and create array for line A");
911 Points = APnts;
912 Points1 = APnts;
913 Points2 = BPnts;
914 current = 0;
915 second = 1;
916 }
917 else {
918 G_debug(2, "Clean and create array for line B");
919 Points = BPnts;
920 Points1 = BPnts;
921 Points2 = APnts;
922 current = 1;
923 second = 0;
924 }
925
926 /* Sort points along lines */
927 qsort((void *)cross, sizeof(char) * n_cross, sizeof(CROSS), cmp_cross);
928
929 /* Print all (raw) breaks */
930 /* avoid loop when not debugging */
931 if (debug_level > 2) {
932 for (i = 0; i < n_cross; i++) {
933 G_debug(
934 3,
935 " cross = %d seg1/dist1 = %d/%f seg2/dist2 = %d/%f x = %f "
936 "y = %f",
937 i, cross[i].segment[current],
938 sqrt(cross[i].distance[current]), cross[i].segment[second],
939 sqrt(cross[i].distance[second]), cross[i].x, cross[i].y);
940 }
941 }
942
943 /* Remove breaks on first/last line vertices */
944 for (i = 0; i < n_cross; i++) {
945 if (use_cross[i] == 1) {
946 j = Points1->n_points - 1;
947
948 /* Note: */
949 if ((cross[i].segment[current] == 0 &&
950 cross[i].x == Points1->x[0] &&
951 cross[i].y == Points1->y[0]) ||
952 (cross[i].segment[current] == j - 1 &&
953 cross[i].x == Points1->x[j] &&
954 cross[i].y == Points1->y[j])) {
955 use_cross[i] = 0; /* first/last */
956 G_debug(3, "cross %d deleted (first/last point)", i);
957 }
958 }
959 }
960
961 /* Remove breaks with collinear previous and next segments on 1 and 2 */
962 /* Note: breaks with collinear previous and nex must be remove
963 * duplicates, otherwise some cross may be lost. Example (+ is vertex):
964 * B first cross intersections: A/B segment:
965 * | 0/0, 0/1, 1/0, 1/1 - collinear previous
966 * and next AB -----+----+--- A 0/4, 0/5, 1/4, 1/5 - OK
967 * \___|
968 * B
969 * This should not influence that break is always on first segment, see
970 * below (I hope)
971 */
972 /* TODO: this doesn't find identical with breaks on revious/next */
973 for (i = 0; i < n_cross; i++) {
974 if (use_cross[i] == 0)
975 continue;
976 G_debug(3, " is %d between colinear?", i);
977
978 seg1 = cross[i].segment[current];
979 seg2 = cross[i].segment[second];
980
981 /* Is it vertex on 1, which? */
982 if (cross[i].x == Points1->x[seg1] &&
983 cross[i].y == Points1->y[seg1]) {
984 vert1 = seg1;
985 }
986 else if (cross[i].x == Points1->x[seg1 + 1] &&
987 cross[i].y == Points1->y[seg1 + 1]) {
988 vert1 = seg1 + 1;
989 }
990 else {
991 G_debug(3, " -> is not vertex on 1. line");
992 continue;
993 }
994
995 /* Is it vertex on 2, which? */
996 /* For 1. line it is easy, because breaks on vertex are always at
997 * end vertex for 2. line we need to find which vertex is on break
998 * if any (vert2 starts from 0) */
999 if (cross[i].x == Points2->x[seg2] &&
1000 cross[i].y == Points2->y[seg2]) {
1001 vert2 = seg2;
1002 }
1003 else if (cross[i].x == Points2->x[seg2 + 1] &&
1004 cross[i].y == Points2->y[seg2 + 1]) {
1005 vert2 = seg2 + 1;
1006 }
1007 else {
1008 G_debug(3, " -> is not vertex on 2. line");
1009 continue;
1010 }
1011 G_debug(3, " seg1/vert1 = %d/%d seg2/ver2 = %d/%d", seg1, vert1,
1012 seg2, vert2);
1013
1014 /* Check if the second vertex is not first/last */
1015 if (vert2 == 0 || vert2 == Points2->n_points - 1) {
1016 G_debug(3, " -> vertex 2 (%d) is first/last", vert2);
1017 continue;
1018 }
1019
1020 /* Are there first vertices of this segment identical */
1021 if (!((Points1->x[vert1 - 1] == Points2->x[vert2 - 1] &&
1022 Points1->y[vert1 - 1] == Points2->y[vert2 - 1] &&
1023 Points1->x[vert1 + 1] == Points2->x[vert2 + 1] &&
1024 Points1->y[vert1 + 1] == Points2->y[vert2 + 1]) ||
1025 (Points1->x[vert1 - 1] == Points2->x[vert2 + 1] &&
1026 Points1->y[vert1 - 1] == Points2->y[vert2 + 1] &&
1027 Points1->x[vert1 + 1] == Points2->x[vert2 - 1] &&
1028 Points1->y[vert1 + 1] == Points2->y[vert2 - 1]))) {
1029 G_debug(3, " -> previous/next are not identical");
1030 continue;
1031 }
1032
1033 use_cross[i] = 0;
1034
1035 G_debug(3, " -> collinear -> remove");
1036 }
1037
1038 /* Remove duplicates, i.e. merge all identical breaks to one.
1039 * We must be careful because two points with identical coordinates may
1040 * be distant if measured along the line: | Segments b0 and b1
1041 * overlap, b0 runs up, b1 down. | Two inersections may be
1042 * merged for a, because they are identical,
1043 * -----+---- a but cannot be merged for b, because both b0 and b1
1044 * must be broken. | I.e. Breaks on b have identical
1045 * coordinates, but there are not identical b0 | b1 if measured
1046 * along line b.
1047 *
1048 * -> Breaks may be merged as identical if lay on the same segment,
1049 * or on vertex connecting 2 adjacent segments the points lay on
1050 *
1051 * Note: if duplicate is on a vertex, the break is removed from next
1052 * segment => break on vertex is always on first segment of this vertex
1053 * (used below)
1054 */
1055 last = -1;
1056 for (i = 0; i < n_cross; i++) {
1057 if (use_cross[i] == 0)
1058 continue;
1059 if (last == -1) { /* set first alive */
1060 last = i;
1061 continue;
1062 }
1063 seg = cross[i].segment[current];
1064 /* compare with last */
1065 G_debug(3, " duplicate ?: cross = %d seg = %d dist = %f", i,
1066 cross[i].segment[current], cross[i].distance[current]);
1067 if ((cross[i].segment[current] == cross[last].segment[current] &&
1068 cross[i].distance[current] == cross[last].distance[current]) ||
1069 (cross[i].segment[current] ==
1070 cross[last].segment[current] + 1 &&
1071 cross[i].distance[current] == 0 &&
1072 cross[i].x == cross[last].x && cross[i].y == cross[last].y)) {
1073 G_debug(3, " cross %d identical to last -> removed", i);
1074 use_cross[i] = 0; /* identical */
1075 }
1076 else {
1077 last = i;
1078 }
1079 }
1080
1081 /* Create array of new lines */
1082 /* Count alive crosses */
1083 n_alive_cross = 0;
1084 G_debug(3, " alive crosses:");
1085 for (i = 0; i < n_cross; i++) {
1086 if (use_cross[i] == 1) {
1087 G_debug(3, " %d", i);
1088 n_alive_cross++;
1089 }
1090 }
1091
1092 k = 0;
1093 if (n_alive_cross > 0) {
1094 /* Add last line point at the end of cross array (cross alley) */
1095 use_cross[n_cross] = 1;
1096 j = Points->n_points - 1;
1097 cross[n_cross].x = Points->x[j];
1098 cross[n_cross].y = Points->y[j];
1099 cross[n_cross].segment[current] = Points->n_points - 2;
1100
1101 last_seg = 0;
1102 last_x = Points->x[0];
1103 last_y = Points->y[0];
1104 last_z = Points->z[0];
1105 /* Go through all cross (+last line point) and create for each new
1106 * line starting at last_* and ending at cross (last point) */
1107 for (i = 0; i <= n_cross; i++) { /* i.e. n_cross + 1 new lines */
1108 seg = cross[i].segment[current];
1109 G_debug(2, "%d seg = %d dist = %f", i, seg,
1110 cross[i].distance[current]);
1111 if (use_cross[i] == 0) {
1112 G_debug(3, " removed -> next");
1113 continue;
1114 }
1115
1116 G_debug(2, " New line:");
1118 /* add last intersection or first point first */
1120 G_debug(2, " append last vert: %f %f", last_x, last_y);
1121
1122 /* add first points of segments between last and current seg */
1123 for (j = last_seg + 1; j <= seg; j++) {
1124 G_debug(2, " segment j = %d", j);
1125 /* skip vertex identical to last break */
1126 if ((j == last_seg + 1) && Points->x[j] == last_x &&
1127 Points->y[j] == last_y) {
1128 G_debug(2, " -> skip (identical to last break)");
1129 continue;
1130 }
1131 Vect_append_point(XLines[k], Points->x[j], Points->y[j],
1132 Points->z[j]);
1133 G_debug(2, " append first of seg: %f %f", Points->x[j],
1134 Points->y[j]);
1135 }
1136
1137 last_seg = seg;
1138 last_x = cross[i].x;
1139 last_y = cross[i].y;
1140 last_z = 0;
1141 /* calculate last_z */
1142 if (Points->z[last_seg] == Points->z[last_seg + 1]) {
1143 last_z = Points->z[last_seg + 1];
1144 }
1145 else if (last_x == Points->x[last_seg] &&
1146 last_y == Points->y[last_seg]) {
1147 last_z = Points->z[last_seg];
1148 }
1149 else if (last_x == Points->x[last_seg + 1] &&
1150 last_y == Points->y[last_seg + 1]) {
1151 last_z = Points->z[last_seg + 1];
1152 }
1153 else {
1154 dist = dist2(Points->x[last_seg], Points->x[last_seg + 1],
1155 Points->y[last_seg], Points->y[last_seg + 1]);
1156 if (with_z) {
1157 last_z = (Points->z[last_seg] *
1158 sqrt(cross[i].distance[current]) +
1159 Points->z[last_seg + 1] *
1160 (sqrt(dist) -
1161 sqrt(cross[i].distance[current]))) /
1162 sqrt(dist);
1163 }
1164 }
1165
1166 /* add current cross or end point */
1167 Vect_append_point(XLines[k], cross[i].x, cross[i].y, last_z);
1168 G_debug(2, " append cross / last point: %f %f", cross[i].x,
1169 cross[i].y);
1170
1171 /* Check if line is degenerate */
1172 if (dig_line_degenerate(XLines[k]) > 0) {
1173 G_debug(2, " line is degenerate -> skipped");
1175 }
1176 else {
1177 k++;
1178 }
1179 }
1180 }
1181 if (l == 1) {
1182 *nalines = k;
1183 *ALines = XLines;
1184 }
1185 else {
1186 *nblines = k;
1187 *BLines = XLines;
1188 }
1189 }
1190
1191 return 1;
1192}
1193
1194/* static int cross_found; */ /* set by find_cross() */
1195
1196/* find segment intersection, used by Vect_line_check_intersection2 */
1197static int find_cross(int i, int j, int b)
1198{
1199 double x1, y1, z1, x2, y2, z2;
1200 double y1min, y1max, y2min, y2max;
1201 int ret;
1202
1203 y1min = APnts->y[i];
1204 y1max = APnts->y[i + 1];
1205 if (APnts->y[i] > APnts->y[i + 1]) {
1206 y1min = APnts->y[i + 1];
1207 y1max = APnts->y[i];
1208 }
1209
1210 y2min = BPnts->y[j];
1211 y2max = BPnts->y[j + 1];
1212 if (BPnts->y[j] > BPnts->y[j + 1]) {
1213 y2min = BPnts->y[j + 1];
1214 y2max = BPnts->y[j];
1215 }
1216
1217 if (y1min > y2max || y1max < y2min)
1218 return 0;
1219
1220 if (b) {
1222 APnts->x[i], APnts->y[i], APnts->z[i], APnts->x[i + 1],
1223 APnts->y[i + 1], APnts->z[i + 1], BPnts->x[j], BPnts->y[j],
1224 BPnts->z[j], BPnts->x[j + 1], BPnts->y[j + 1], BPnts->z[j + 1], &x1,
1225 &y1, &z1, &x2, &y2, &z2, 0);
1226 }
1227 else {
1229 BPnts->x[j], BPnts->y[j], BPnts->z[j], BPnts->x[j + 1],
1230 BPnts->y[j + 1], BPnts->z[j + 1], APnts->x[i], APnts->y[i],
1231 APnts->z[i], APnts->x[i + 1], APnts->y[i + 1], APnts->z[i + 1], &x1,
1232 &y1, &z1, &x2, &y2, &z2, 0);
1233 }
1234
1235 if (!IPnts)
1236 IPnts = Vect_new_line_struct();
1237
1238 /* add ALL (including end points and duplicates), clean later */
1239 switch (ret) {
1240 case 0:
1241 case 5:
1242 break;
1243 case 1:
1244 if (0 > Vect_append_point(IPnts, x1, y1, z1))
1245 G_warning(_("Error while adding point to array. Out of memory"));
1246 break;
1247 case 2:
1248 case 3:
1249 case 4:
1250 if (0 > Vect_append_point(IPnts, x1, y1, z1))
1251 G_warning(_("Error while adding point to array. Out of memory"));
1252 if (0 > Vect_append_point(IPnts, x2, y2, z2))
1253 G_warning(_("Error while adding point to array. Out of memory"));
1254 break;
1255 }
1256
1257 return ret;
1258}
1259
1261 struct line_pnts *BPoints, int with_z, int all)
1262{
1263 double dist;
1264 struct bound_box ABox, BBox, abbox;
1265 struct boq bo_queue;
1266 struct qitem qi, *found;
1267 struct RB_TREE *bo_ta, *bo_tb;
1268 struct RB_TRAV bo_t_trav;
1269 int ret, intersect;
1270 double xa1, ya1, xa2, ya2, xb1, yb1, xb2, yb2, xi, yi;
1271
1272 APnts = APoints;
1273 BPnts = BPoints;
1274
1275 ABPnts[0] = APnts;
1276 ABPnts[1] = BPnts;
1277
1278 /* TODO: 3D, RE (representation error) threshold, GV_POINTS (line x point)
1279 */
1280
1281 if (!IPnts)
1282 IPnts = Vect_new_line_struct();
1283 Vect_reset_line(IPnts);
1284
1285 /* If one or both are point (Points->n_points == 1) */
1286 if (APoints->n_points == 1 && BPoints->n_points == 1) {
1287 if (APoints->x[0] == BPoints->x[0] && APoints->y[0] == BPoints->y[0]) {
1288 if (!with_z) {
1289 if (all && 0 > Vect_append_point(IPnts, APoints->x[0],
1290 APoints->y[0], APoints->z[0]))
1291 G_warning(
1292 _("Error while adding point to array. Out of memory"));
1293 return 1;
1294 }
1295 else {
1296 if (APoints->z[0] == BPoints->z[0]) {
1297 if (all &&
1298 0 > Vect_append_point(IPnts, APoints->x[0],
1299 APoints->y[0], APoints->z[0]))
1300 G_warning(_("Error while adding point to array. Out of "
1301 "memory"));
1302 return 1;
1303 }
1304 else
1305 return 0;
1306 }
1307 }
1308 else {
1309 return 0;
1310 }
1311 }
1312
1313 if (APoints->n_points == 1) {
1314 Vect_line_distance(BPoints, APoints->x[0], APoints->y[0], APoints->z[0],
1315 with_z, NULL, NULL, NULL, &dist, NULL, NULL);
1316
1317 if (dist <= d_ulp(APoints->x[0], APoints->y[0])) {
1318 if (all && 0 > Vect_append_point(IPnts, APoints->x[0],
1319 APoints->y[0], APoints->z[0]))
1320 G_warning(
1321 _("Error while adding point to array. Out of memory"));
1322 return 1;
1323 }
1324 else {
1325 return 0;
1326 }
1327 }
1328
1329 if (BPoints->n_points == 1) {
1330 Vect_line_distance(APoints, BPoints->x[0], BPoints->y[0], BPoints->z[0],
1331 with_z, NULL, NULL, NULL, &dist, NULL, NULL);
1332
1333 if (dist <= d_ulp(BPoints->x[0], BPoints->y[0])) {
1334 if (all && 0 > Vect_append_point(IPnts, BPoints->x[0],
1335 BPoints->y[0], BPoints->z[0]))
1336 G_warning(
1337 _("Error while adding point to array. Out of memory"));
1338 return 1;
1339 }
1340 else
1341 return 0;
1342 }
1343
1344 /* Take each segment from A and find if intersects any segment from B. */
1345
1348 if (!with_z) {
1349 ABox.T = BBox.T = PORT_DOUBLE_MAX;
1350 ABox.B = BBox.B = -PORT_DOUBLE_MAX;
1351 }
1352
1353 if (!Vect_box_overlap(&ABox, &BBox)) {
1354 return 0;
1355 }
1356
1357 /* overlap box */
1358 abbox = BBox;
1359 if (abbox.N > ABox.N)
1360 abbox.N = ABox.N;
1361 if (abbox.S < ABox.S)
1362 abbox.S = ABox.S;
1363 if (abbox.E > ABox.E)
1364 abbox.E = ABox.E;
1365 if (abbox.W < ABox.W)
1366 abbox.W = ABox.W;
1367
1368 abbox.N += d_ulp(abbox.N, abbox.N);
1369 abbox.S -= d_ulp(abbox.S, abbox.S);
1370 abbox.E += d_ulp(abbox.E, abbox.E);
1371 abbox.W -= d_ulp(abbox.W, abbox.W);
1372
1373 if (with_z) {
1374 if (abbox.T > ABox.T)
1375 abbox.T = ABox.T;
1376 if (abbox.B < ABox.B)
1377 abbox.B = ABox.B;
1378
1379 abbox.T += d_ulp(abbox.T, abbox.T);
1380 abbox.B -= d_ulp(abbox.B, abbox.B);
1381 }
1382
1383 /* initialize queue */
1384 bo_queue.count = 0;
1385 bo_queue.alloc = 2 * (APnts->n_points + BPnts->n_points);
1386 bo_queue.i = G_malloc(bo_queue.alloc * sizeof(struct qitem));
1387
1388 /* load APnts to queue */
1389 if (!boq_load(&bo_queue, APnts, &abbox, 0, with_z)) {
1390 G_free(bo_queue.i);
1391 return 0;
1392 }
1393
1394 /* load BPnts to queue */
1395 if (!boq_load(&bo_queue, BPnts, &abbox, 1, with_z)) {
1396 G_free(bo_queue.i);
1397 return 0;
1398 }
1399
1400 /* initialize search tree */
1401 bo_ta = rbtree_create(cmp_t_y, sizeof(struct qitem));
1402 bo_tb = rbtree_create(cmp_t_y, sizeof(struct qitem));
1403
1404 /* find intersection */
1405 xa1 = APnts->x[0];
1406 ya1 = APnts->y[0];
1407 xa2 = APnts->x[APnts->n_points - 1];
1408 ya2 = APnts->y[APnts->n_points - 1];
1409 xb1 = BPnts->x[0];
1410 yb1 = BPnts->y[0];
1411 xb2 = BPnts->x[BPnts->n_points - 1];
1412 yb2 = BPnts->y[BPnts->n_points - 1];
1413 intersect = 0;
1414 while (boq_drop(&bo_queue, &qi)) {
1415
1416 if (qi.e == QEVT_IN) {
1417 /* not the original Bentley-Ottmann algorithm */
1418 if (qi.l == 0) {
1419 /* test for intersection of s with all segments in T */
1421 while ((found = rbtree_traverse(&bo_t_trav))) {
1422 ret = find_cross(qi.s, found->s, 0);
1423
1424 if (ret > 0) {
1425 if (ret != 1) {
1426 intersect = 1;
1427 }
1428 /* intersect at one point */
1429 else if (intersect != 1) {
1430 intersect = 1;
1431 xi = IPnts->x[IPnts->n_points - 1];
1432 yi = IPnts->y[IPnts->n_points - 1];
1433 if (xi == xa1 && yi == ya1) {
1434 if ((xi == xb1 && yi == yb1) ||
1435 (xi == xb2 && yi == yb2)) {
1436 intersect = 2;
1437 }
1438 }
1439 else if (xi == xa2 && yi == ya2) {
1440 if ((xi == xb1 && yi == yb1) ||
1441 (xi == xb2 && yi == yb2)) {
1442 intersect = 2;
1443 }
1444 }
1445 }
1446 }
1447
1448 if (intersect == 1) {
1449 break;
1450 }
1451 }
1452
1453 /* insert s in T */
1455 }
1456 else {
1457 /* test for intersection of s with all segments in T */
1459 while ((found = rbtree_traverse(&bo_t_trav))) {
1460 ret = find_cross(found->s, qi.s, 1);
1461
1462 if (ret > 0) {
1463 if (ret != 1) {
1464 intersect = 1;
1465 }
1466 /* intersect at one point */
1467 else if (intersect != 1) {
1468 intersect = 1;
1469 xi = IPnts->x[IPnts->n_points - 1];
1470 yi = IPnts->y[IPnts->n_points - 1];
1471 if (xi == xa1 && yi == ya1) {
1472 if ((xi == xb1 && yi == yb1) ||
1473 (xi == xb2 && yi == yb2)) {
1474 intersect = 2;
1475 }
1476 }
1477 else if (xi == xa2 && yi == ya2) {
1478 if ((xi == xb1 && yi == yb1) ||
1479 (xi == xb2 && yi == yb2)) {
1480 intersect = 2;
1481 }
1482 }
1483 }
1484 }
1485
1486 if (intersect == 1) {
1487 break;
1488 }
1489 }
1490
1491 /* insert s in T */
1493 }
1494 }
1495 else if (qi.e == QEVT_OUT) {
1496 /* remove from T */
1497
1498 /* adjust p */
1499 if (qi.p == qi.s)
1500 qi.p++;
1501 else
1502 qi.p--;
1503
1504 if (qi.l == 0) {
1505 if (!rbtree_remove(bo_ta, &qi))
1506 G_fatal_error("RB tree error!");
1507 }
1508 else {
1509 if (!rbtree_remove(bo_tb, &qi))
1510 G_fatal_error("RB tree error!");
1511 }
1512 }
1513 if (!all && intersect == 1) {
1514 break;
1515 }
1516 }
1517 G_free(bo_queue.i);
1520
1521 return intersect;
1522}
1523
1524/*!
1525 * \brief Check if 2 lines intersect.
1526 *
1527 * Points (Points->n_points == 1) are also supported.
1528 *
1529 * simplified Bentley–Ottmann Algorithm:
1530 * similar to Vect_line_check_intersection(), but faster
1531 *
1532 * \param APoints first input line
1533 * \param BPoints second input line
1534 * \param with_z 3D, not supported (only if one or both are points)!
1535 *
1536 * \return 0 no intersection
1537 * \return 1 intersection
1538 * \return 2 end points only
1539 */
1541 struct line_pnts *BPoints, int with_z)
1542{
1543 return line_check_intersection2(APoints, BPoints, with_z, 0);
1544}
1545
1546/*!
1547 * \brief Get 2 lines intersection points.
1548 *
1549 * A wrapper around Vect_line_check_intersection2() function.
1550 *
1551 * simplified Bentley–Ottmann Algorithm:
1552 * similar to Vect_line_get_intersections(), but faster
1553 *
1554 * \param APoints first input line
1555 * \param BPoints second input line
1556 * \param[out] IPoints output with intersection points
1557 * \param with_z 3D, not supported (only if one or both are points)!
1558 *
1559 * \return 0 no intersection
1560 * \return 1 intersection found
1561 */
1563 struct line_pnts *BPoints,
1564 struct line_pnts *IPoints, int with_z)
1565{
1566 int ret;
1567
1568 IPnts = IPoints;
1570
1571 return ret;
1572}
#define NULL
Definition ccmath.h:32
const char * G_getenv_nofatal(const char *)
Get environment variable.
Definition env.c:403
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:145
#define G_realloc(p, n)
Definition defs/gis.h:138
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
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
int rbtree_insert(struct RB_TREE *, void *)
Definition rbtree.c:71
int rbtree_init_trav(struct RB_TRAV *, struct RB_TREE *)
Definition rbtree.c:262
struct RB_TREE * rbtree_create(rb_compare_fn *, size_t)
Definition rbtree.c:47
int rbtree_remove(struct RB_TREE *, const void *)
Definition rbtree.c:152
void * rbtree_traverse(struct RB_TRAV *)
Definition rbtree.c:279
void rbtree_destroy(struct RB_TREE *)
Definition rbtree.c:518
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_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.
int Vect_segment_intersection(double, double, double, double, double, double, double, double, double, double, double, double, double *, double *, double *, double *, double *, double *, int)
Check for intersect of 2 line segments.
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
#define PORT_DOUBLE_MAX
Limits for portable types.
Definition dig_defines.h:66
int dig_line_degenerate(const struct line_pnts *)
Definition angle.c:176
int dig_line_box(const struct line_pnts *, struct bound_box *)
#define _(str)
Definition glocale.h:10
int count
struct line_pnts * Pnts
int Vect_line_check_intersection2(struct line_pnts *APoints, struct line_pnts *BPoints, int with_z)
Check if 2 lines intersect.
int line_check_intersection2(struct line_pnts *APoints, struct line_pnts *BPoints, int with_z, int all)
int Vect_line_get_intersections2(struct line_pnts *APoints, struct line_pnts *BPoints, struct line_pnts *IPoints, int with_z)
Get 2 lines intersection points.
#define QEVT_OUT
Definition intersect2.c:341
#define GET_CHILD(c, p)
Definition intersect2.c:345
#define QEVT_IN
Definition intersect2.c:340
int Vect_line_intersection2(struct line_pnts *APoints, struct line_pnts *BPoints, struct bound_box *pABox, struct bound_box *pBBox, struct line_pnts ***ALines, struct line_pnts ***BLines, int *nalines, int *nblines, int with_z)
Intersect 2 lines.
Definition intersect2.c:675
#define GET_PARENT(p, c)
Definition intersect2.c:344
double b
Definition r_raster.c:37
double l
Definition r_raster.c:37
Bounding box.
Definition dig_structs.h:62
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.
#define x