|
1 | 1 | /**
|
2 |
| - * Author: Ulf Lundstrom |
3 |
| - * Date: 2009-03-21 |
| 2 | + * Author: Victor Lecomte, chilli |
| 3 | + * Date: 2019-04-27 |
4 | 4 | * License: CC0
|
5 |
| - * Source: |
| 5 | + * Source: https://vlecomte.github.io/cp-geo.pdf |
6 | 6 | * Description:\\
|
7 | 7 | \begin{minipage}{75mm}
|
8 |
| -If a unique intersetion point between the line segments going from s1 to e1 and from s2 to e2 exists r1 is set to this point and 1 is returned. |
9 |
| -If no intersection point exists 0 is returned and if infinitely many exists 2 is returned and r1 and r2 are set to the two ends of the common line. |
10 |
| -The wrong position will be returned if P is Point<int> and the intersection point does not have integer coordinates. |
| 8 | +If a unique intersection point between the line segments going from s1 to e1 and from s2 to e2 exists then it is returned. |
| 9 | +If no intersection point exists an empty vector is returned. If infinitely many exist a vector with 2 elements is returned, containing the endpoints of the common line segment. |
| 10 | +The wrong position will be returned if P is Point<ll> and the intersection point does not have integer coordinates. |
11 | 11 | Products of three coordinates are used in intermediate steps so watch out for overflow if using int or long long.
|
12 |
| -Use segmentIntersectionQ to get just a true/false answer. |
13 | 12 | \end{minipage}
|
14 | 13 | \begin{minipage}{15mm}
|
15 | 14 | \includegraphics[width=\textwidth]{content/geometry/SegmentIntersection}
|
16 | 15 | \end{minipage}
|
17 |
| - * Status: Well tested with unitTest and with Kattis problem intersection. |
| 16 | + * Status: Well tested with fuzz-test and with Kattis problem intersection. |
18 | 17 | * Usage:
|
19 |
| - * Point<double> intersection, dummy; |
20 |
| - * if (segmentIntersection(s1,e1,s2,e2,intersection,dummy)==1) |
21 |
| - * cout << "segments intersect at " << intersection << endl; |
| 18 | + * vector<P> inter = segInter(s1,e1,s2,e2); |
| 19 | + * if (sz(inter)==1) |
| 20 | + * cout << "segments intersect at " << inter[0] << endl; |
22 | 21 | */
|
23 | 22 | #pragma once
|
24 | 23 |
|
25 | 24 | #include "Point.h"
|
| 25 | +#include "onSegment.h" |
26 | 26 |
|
27 |
| -template<class P> |
28 |
| -int segmentIntersection(const P& s1, const P& e1, |
29 |
| - const P& s2, const P& e2, P& r1, P& r2) { |
30 |
| - if (e1==s1) { |
31 |
| - if (e2==s2) { |
32 |
| - if (e1==e2) { r1 = e1; return 1; } //all equal |
33 |
| - else return 0; //different point segments |
34 |
| - } else return segmentIntersection(s2,e2,s1,e1,r1,r2);//swap |
35 |
| - } |
36 |
| - //segment directions and separation |
37 |
| - P v1 = e1-s1, v2 = e2-s2, d = s2-s1; |
38 |
| - auto a = v1.cross(v2), a1 = v1.cross(d), a2 = v2.cross(d); |
39 |
| - if (a == 0) { //if parallel |
40 |
| - auto b1=s1.dot(v1), c1=e1.dot(v1), |
41 |
| - b2=s2.dot(v1), c2=e2.dot(v1); |
42 |
| - if (a1 || a2 || max(b1,min(b2,c2))>min(c1,max(b2,c2))) |
43 |
| - return 0; |
44 |
| - r1 = min(b2,c2)<b1 ? s1 : (b2<c2 ? s2 : e2); |
45 |
| - r2 = max(b2,c2)>c1 ? e1 : (b2>c2 ? s2 : e2); |
46 |
| - return 2-(r1==r2); |
47 |
| - } |
48 |
| - if (a < 0) { a = -a; a1 = -a1; a2 = -a2; } |
49 |
| - if (0<a1 || a<-a1 || 0<a2 || a<-a2) |
50 |
| - return 0; |
51 |
| - r1 = s1-v1*a2/a; |
52 |
| - return 1; |
| 27 | +template<class P> vector<P> segInter(P a, P b, P c, P d) { |
| 28 | + auto oa = c.cross(d, a), ob = c.cross(d, b), |
| 29 | + oc = a.cross(b, c), od = a.cross(b, d); |
| 30 | + // Checks if intersection is single non-endpoint point. |
| 31 | + if (sgn(oa) * sgn(ob) < 0 && sgn(oc) * sgn(od) < 0) |
| 32 | + return {(a * ob - b * oa) / (ob - oa)}; |
| 33 | + set<P> s; |
| 34 | + if (onSegment(c, d, a)) s.insert(a); |
| 35 | + if (onSegment(c, d, b)) s.insert(b); |
| 36 | + if (onSegment(a, b, c)) s.insert(c); |
| 37 | + if (onSegment(a, b, d)) s.insert(d); |
| 38 | + return {all(s)}; |
53 | 39 | }
|
0 commit comments