Skip to content

Commit 95b770b

Browse files
committed
merged
2 parents e99191f + 2aad7c9 commit 95b770b

File tree

4 files changed

+82
-18
lines changed

4 files changed

+82
-18
lines changed

content/geometry/Point.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*/
1010
#pragma once
1111

12-
template <typename T> int sgn(T x) { return (x > 0) - (x < 0);}
12+
template <class T> int sgn(T x) { return (x > 0) - (x < 0); }
1313
template<class T>
1414
struct Point {
1515
typedef Point P;

content/geometry/SegmentIntersection.h

+9-16
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
* Description:\\
77
\begin{minipage}{75mm}
88
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.
10-
The wrong position will be returned if P is Point<int> and the intersection point does not have integer coordinates.
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.
1111
Products of three coordinates are used in intermediate steps so watch out for overflow if using int or long long.
1212
\end{minipage}
1313
\begin{minipage}{15mm}
@@ -16,31 +16,24 @@ Products of three coordinates are used in intermediate steps so watch out for ov
1616
* Status: Well tested with fuzz-test and with Kattis problem intersection.
1717
* Usage:
1818
* vector<P> inter = segInter(s1,e1,s2,e2);
19-
* if (inter.size()==1)
19+
* if (sz(inter)==1)
2020
* cout << "segments intersect at " << inter[0] << endl;
2121
*/
2222
#pragma once
2323

2424
#include "Point.h"
2525
#include "onSegment.h"
2626

27-
template <class P>
28-
bool segInterProper(P a, P b, P c, P d, P& out) {
29-
double oa = c.cross(d, a), ob = c.cross(d, b),
30-
oc = a.cross(b, c), od = a.cross(b, d);
31-
if (sgn(oa) * sgn(ob) < 0 && sgn(oc) * sgn(od) < 0) {
32-
out = (a * ob - b * oa) / (ob - oa);
33-
return true;
34-
}
35-
return false;
36-
}
3727
template<class P> vector<P> segInter(P a, P b, P c, P d) {
38-
P out;
39-
if (segInterProper(a, b, c, d, out)) return {out};
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)};
4033
set<P> s;
4134
if (onSegment(c, d, a)) s.insert(a);
4235
if (onSegment(c, d, b)) s.insert(b);
4336
if (onSegment(a, b, c)) s.insert(c);
4437
if (onSegment(a, b, d)) s.insert(d);
45-
return vector<P>(all(s));
38+
return {all(s)};
4639
}

content/geometry/onSegment.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@
1111
#include "Point.h"
1212

1313
template <class P> bool onSegment(P s, P e, P p) {
14-
return s.cross(e, p) == 0 && (s - p).dot(e - p) <= 0;
14+
return p.cross(s, e) == 0 && (s - p).dot(e - p) <= 0;
1515
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include <bits/stdc++.h>
2+
using namespace std;
3+
4+
#define rep(i, a, b) for(int i = a; i < int(b); ++i)
5+
#define trav(a, v) for(auto& a : v)
6+
#define all(x) x.begin(), x.end()
7+
#define sz(x) (int)(x).size()
8+
9+
typedef long long ll;
10+
typedef pair<int, int> pii;
11+
typedef vector<int> vi;
12+
13+
14+
#include "../content/geometry/SegmentIntersection.h"
15+
namespace oldImpl {
16+
template<class P>
17+
int segmentIntersection(const P& s1, const P& e1,
18+
const P& s2, const P& e2, P& r1, P& r2) {
19+
if (e1==s1) {
20+
if (e2==s2) {
21+
if (e1==e2) { r1 = e1; return 1; } //all equal
22+
else return 0; //different point segments
23+
} else return segmentIntersection(s2,e2,s1,e1,r1,r2);//swap
24+
}
25+
//segment directions and separation
26+
P v1 = e1-s1, v2 = e2-s2, d = s2-s1;
27+
auto a = v1.cross(v2), a1 = v1.cross(d), a2 = v2.cross(d);
28+
if (a == 0) { //if parallel
29+
auto b1=s1.dot(v1), c1=e1.dot(v1),
30+
b2=s2.dot(v1), c2=e2.dot(v1);
31+
if (a1 || a2 || max(b1,min(b2,c2))>min(c1,max(b2,c2)))
32+
return 0;
33+
r1 = min(b2,c2)<b1 ? s1 : (b2<c2 ? s2 : e2);
34+
r2 = max(b2,c2)>c1 ? e1 : (b2>c2 ? s2 : e2);
35+
return 2-(r1==r2);
36+
}
37+
if (a < 0) { a = -a; a1 = -a1; a2 = -a2; }
38+
if (0<a1 || a<-a1 || 0<a2 || a<-a2)
39+
return 0;
40+
r1 = s1-v1*a2/a;
41+
return 1;
42+
}
43+
}
44+
typedef Point<double> P;
45+
ostream &operator<<(ostream &os, P p) { return cout << "(" << p.x << "," << p.y << ")"; }
46+
bool eq(P a, P b) {
47+
return (a-b).dist()<1e-8;
48+
}
49+
int main() {
50+
rep(t,0,1000000) {
51+
const int GRID=6;
52+
P a(rand()%GRID, rand()%GRID), b(rand()%GRID, rand()%GRID), c(rand()%GRID, rand()%GRID), d(rand()%GRID, rand()%GRID);
53+
P tmp1, tmp2;
54+
auto res = oldImpl::segmentIntersection(a,b,c,d, tmp1, tmp2);
55+
auto res2 = segInter(a,b,c,d);
56+
if (res != sz(res2)) {
57+
cout<<a<<' '<<b<<' '<<c<<' '<<d<<endl;
58+
cout<<"old: "<<res<<" new: "<<sz(res2)<<endl;
59+
}
60+
assert(res==sz(res2));
61+
if (res==1) {
62+
assert(eq(*res2.begin(), tmp1));
63+
} else if (res==2) {
64+
vector<P> a(res2.begin(), res2.end());
65+
vector<P> b({tmp1, tmp2});
66+
sort(all(b));
67+
assert(eq(a[0], b[0]) && eq(a[1],b[1]));
68+
}
69+
}
70+
cout<<"Tests passed!"<<endl;
71+
}

0 commit comments

Comments
 (0)