Skip to content

Commit 2aad7c9

Browse files
Chilleesimonlindholm
authored andcommitted
Updated onSegment.h and both segment intersections (#78)
1 parent fb08780 commit 2aad7c9

File tree

7 files changed

+105
-80
lines changed

7 files changed

+105
-80
lines changed

content/geometry/Point.h

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

12+
template <class T> int sgn(T x) { return (x > 0) - (x < 0); }
1213
template<class T>
1314
struct Point {
1415
typedef Point P;
+23-37
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,39 @@
11
/**
2-
* Author: Ulf Lundstrom
3-
* Date: 2009-03-21
2+
* Author: Victor Lecomte, chilli
3+
* Date: 2019-04-27
44
* License: CC0
5-
* Source:
5+
* Source: https://vlecomte.github.io/cp-geo.pdf
66
* Description:\\
77
\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.
1111
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.
1312
\end{minipage}
1413
\begin{minipage}{15mm}
1514
\includegraphics[width=\textwidth]{content/geometry/SegmentIntersection}
1615
\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.
1817
* 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;
2221
*/
2322
#pragma once
2423

2524
#include "Point.h"
25+
#include "onSegment.h"
2626

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)};
5339
}

content/geometry/SegmentIntersectionQ.h

-29
This file was deleted.

content/geometry/chapter.tex

+1-3
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,13 @@ \section{Geometric primitives}
66
\kactlimport{SegmentDistance.h}
77
\columnbreak
88
\kactlimport{SegmentIntersection.h}
9-
\kactlimport{SegmentIntersectionQ.h}
10-
\columnbreak
119
\kactlimport{lineIntersection.h}
1210
\kactlimport{sideOf.h}
1311
\kactlimport{onSegment.h}
1412
\kactlimport{linearTransformation.h}
1513
\kactlimport{Angle.h}
1614

17-
\section{Circles}
15+
\section{Circles}
1816
\kactlimport{CircleIntersection.h}
1917
\kactlimport{circleTangents.h}
2018
\kactlimport{circumcircle.h}

content/geometry/onSegment.h

+6-8
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
/**
2-
* Author: Ulf Lundstrom
3-
* Date: 2009-04-09
2+
* Author: Victor Lecomte, chilli
3+
* Date: 2019-04-26
44
* License: CC0
5-
* Source: Basic geometry
6-
* Description: Returns true iff p lies on the line segment from s to e. Intended for use with e.g. Point<long long> where overflow is an issue. Use (segDist(s,e,p)<=epsilon) instead when using Point<double>.
5+
* Source: https://vlecomte.github.io/cp-geo.pdf
6+
* Description: Returns true iff p lies on the line segment from s to e. Intended for use with e.g. Point<long long> where overflow is an issue. Use (segDist(s,e,p)<=epsilon) instead when using Point<double>.
77
* Status:
88
*/
99
#pragma once
1010

1111
#include "Point.h"
1212

13-
template<class P>
14-
bool onSegment(const P& s, const P& e, const P& p) {
15-
P ds = p-s, de = p-e;
16-
return ds.cross(de) == 0 && ds.dot(de) <= 0;
13+
template <class P> bool onSegment(P s, P e, P p) {
14+
return p.cross(s, e) == 0 && (s - p).dot(e - p) <= 0;
1715
}

fuzz-tests/geometry/PolygonCut.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ int main() {
2727
P a = ps[i], b = ps[(i+1)%N];
2828
P c = ps[j], d = ps[(j+1)%N];
2929
P r1, r2;
30-
int r = segmentIntersection(a, b, c, d, r1, r2);
31-
if (r == 2) goto fail;
32-
if (r == 1) {
30+
auto r = segInter(a, b, c, d);
31+
if (sz(r) == 2) goto fail;
32+
if (sz(r) == 1) {
3333
if (i+1 == j || (j+1) % N == i) ;
3434
else goto fail;
3535
}
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)