Skip to content

Commit 7134ff0

Browse files
committed
Added some unit tests for halfplane
1 parent ed75bf9 commit 7134ff0

File tree

2 files changed

+162
-3
lines changed

2 files changed

+162
-3
lines changed

content/geometry/halfPlane.h renamed to content/geometry/HalfPlane.h

+2-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include "Point.h"
1515
#include "sideOf.h"
16+
#include "lineIntersection.h"
1617

1718
typedef Point<double> P;
1819
typedef array<P, 2> Line;
@@ -39,7 +40,5 @@ vector<P> halfPlaneIntersection(vector<Line> vs) {
3940
while (ah < at && sideOf(sp(deq[dt]), ans[ah]) < 0) ah++, dh++;
4041
if (dt-dh <= 2) return {};
4142
ans[at++] = lineInter(sp(deq[dh]), sp(deq[dt-1])).second;
42-
vector<P> res = {ans.begin()+ah, ans.begin()+at};
43-
res.erase(unique(all(res)), res.end());
44-
return res;
43+
return {ans.begin()+ah, ans.begin()+at};
4544
}

fuzz-tests/geometry/HalfPlane.cpp

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
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+
#include "../../content/geometry/HalfPlane.h"
14+
#include "../../content/geometry/PolygonArea.h"
15+
typedef Point<double> P;
16+
17+
ostream &operator<<(ostream &os, P p) { return cout << "(" << p.x << "," << p.y << ")"; }
18+
19+
namespace MIT {
20+
#define eps 1e-8
21+
typedef Point<double> P;
22+
23+
template<class P>
24+
pair<int, P> lineIntersection(P s1, P e1, P s2, P e2) {
25+
auto d = (e1-s1).cross(e2-s2);
26+
if (d == 0) //if parallel
27+
return {-((e1-s1).cross(s2-s1)==0 || s2==e2), P(0,0)};
28+
else
29+
return {1, s2-(e2-s2)*(e1-s1).cross(s2-s1)/d};
30+
}
31+
32+
struct Line {
33+
P P1, P2;
34+
// Right hand side of the ray P1 -> P2
35+
explicit Line(P a = P(), P b = P()) : P1(a), P2(b) {};
36+
P intpo(Line y) {
37+
auto res = lineIntersection(P1, P2, y.P1, y.P2);
38+
assert(res.first == 1);
39+
return res.second;
40+
}
41+
P dir() {
42+
return P2 - P1;
43+
}
44+
bool contains(P x) {
45+
return (P2 - P1).cross(x - P1) < eps;
46+
}
47+
bool out(P x) {
48+
return !contains(x);
49+
}
50+
};
51+
52+
template<class T>
53+
bool mycmp(Point<T> a, Point<T> b) {
54+
// return atan2(a.y, a.x) < atan2(b.y, b.x);
55+
if (a.x * b.x < 0) return a.x < 0;
56+
if (abs(a.x) < eps) {
57+
if (abs(b.x) < eps) return a.y > 0 && b.y < 0;
58+
if (b.x < 0) return a.y > 0;
59+
if (b.x > 0) return true;
60+
}
61+
if (abs(b.x) < eps) {
62+
if (a.x < 0) return b.y < 0;
63+
if (a.x > 0) return false;
64+
}
65+
return a.cross(b) > 0;
66+
}
67+
68+
bool cmp(Line a, Line b) {
69+
return mycmp(a.dir(), b.dir());
70+
}
71+
72+
double Intersection_Area(vector <Line> b) {
73+
sort(b.begin(), b.end(), cmp);
74+
int n = b.size();
75+
int q = 1, h = 0, i;
76+
vector <Line> ca(b.size() + 10);
77+
for (i = 0; i < n; i++) {
78+
while (q < h && b[i].out(ca[h].intpo(ca[h - 1]))) h--;
79+
while (q < h && b[i].out(ca[q].intpo(ca[q + 1]))) q++;
80+
ca[++h] = b[i];
81+
if (q < h && abs(ca[h].dir().cross(ca[h - 1].dir())) < eps) {
82+
h--;
83+
if (b[i].out(ca[h].P1)) ca[h] = b[i];
84+
}
85+
}
86+
while (q < h - 1 && ca[q].out(ca[h].intpo(ca[h - 1]))) h--;
87+
while (q < h - 1 && ca[h].out(ca[q].intpo(ca[q + 1]))) q++;
88+
// Intersection is empty. This is sometimes different from the case when
89+
// the intersection area is 0.
90+
if (h - q <= 1) return 0;
91+
ca[h + 1] = ca[q];
92+
vector <P> s;
93+
for (i = q; i <= h; i++) s.push_back(ca[i].intpo(ca[i + 1]));
94+
s.push_back(s[0]);
95+
double ans = 0;
96+
for (i = 0; i < (int) s.size() - 1; i++) ans += s[i].cross(s[i + 1]);
97+
return ans / 2;
98+
}
99+
}
100+
vector<MIT::Line> convert(vector<Line> x) {
101+
vector<MIT::Line> res;
102+
for (auto i: x)
103+
res.push_back(MIT::Line(i[1], i[0]));
104+
return res;
105+
}
106+
107+
const double INF = 1e9;
108+
void addInf(vector<Line> &res) {
109+
vector<P> infPts({P(INF, INF), P(-INF, INF), P(-INF, -INF), P(INF, -INF)});
110+
for (int i=0; i<4; i++)
111+
res.push_back({infPts[i], infPts[(i+1)%4]});
112+
}
113+
void test1() {
114+
vector<Line> t({{P(0,0),P(5,0)}, {P(5,-2), P(5,2)}, {P(5,2),P(2,2)}, {P(0,3),P(0,-3)}});
115+
auto res = halfPlaneIntersection(t);
116+
cout<<MIT::Intersection_Area(convert(t))<<endl;
117+
assert(polygonArea2(res) == 20);
118+
addInf(t);
119+
res = halfPlaneIntersection(t);
120+
assert(polygonArea2(res) == 20);
121+
}
122+
void testInf() {
123+
vector<Line> t({{P(0,0), P(5,0)}});
124+
addInf(t);
125+
auto res = halfPlaneIntersection(t);
126+
assert(polygonArea2(res)/4e18);
127+
t = vector<Line>({{P(0,0), P(5,0)}, {P(0,0), P(0,5)}});
128+
addInf(t);
129+
res = halfPlaneIntersection(t);
130+
assert(polygonArea2(res)/2e18 == 1);
131+
}
132+
void testLine() {
133+
vector<Line> t({{P(0,0), P(5,0)}, {P(5,0), P(0,0)}});
134+
addInf(t);
135+
auto res = halfPlaneIntersection(t);
136+
assert(sz(res) >= 2);
137+
assert(polygonArea2(res) == 0);
138+
}
139+
void testPoint() {
140+
vector<Line> t({{P(0,0), P(5,0)}, {P(5,0), P(0,0)}, {P(0,0), P(0,5)}, {P(0,5), P(0,0)}});
141+
addInf(t);
142+
auto res = halfPlaneIntersection(t);
143+
assert(sz(res) >= 1);
144+
assert(polygonArea2(res) == 0);
145+
}
146+
void testEmpty() {
147+
vector<Line> t({{P(0,0), P(5,0)}, {P(5,0), P(0,0)}, {P(0,0), P(0,5)}, {P(0,5), P(0,0)},
148+
{P(0,2), P(5,2)}});
149+
addInf(t);
150+
auto res = halfPlaneIntersection(t);
151+
assert(sz(res) == 0);
152+
}
153+
154+
int main() {
155+
test1();
156+
testInf();
157+
testLine();
158+
testPoint();
159+
testEmpty();
160+
}

0 commit comments

Comments
 (0)