1
1
#include < bits/stdc++.h>
2
2
using namespace std ;
3
3
4
- #define rep (i, a, b ) for (int i = a; i < int (b); ++i)
5
- #define trav (a, v ) for (auto & a : v)
4
+ #define rep (i, a, b ) for (int i = a; i < int (b); ++i)
5
+ #define trav (a, v ) for (auto & a : v)
6
6
#define all (x ) x.begin(), x.end()
7
7
#define sz (x ) (int )(x).size()
8
8
@@ -16,179 +16,229 @@ typedef Point<double> P;
16
16
17
17
ostream &operator <<(ostream &os, P p) { return cout << " (" << p.x << " ," << p.y << " )" ; }
18
18
19
- namespace MIT {
20
- #define eps 1e-8
21
- typedef Point<double > P;
19
+ namespace sjtu {
20
+ const double EPS = 1e-8 ;
21
+ inline int sign (double a) { return a < -EPS ? -1 : a > EPS; }
22
+ struct Point {
23
+ double x, y;
24
+ Point () {}
25
+ Point (double _x, double _y) : x(_x), y(_y) {}
26
+ Point operator +(const Point &p) const { return Point (x + p.x , y + p.y ); }
27
+ Point operator -(const Point &p) const { return Point (x - p.x , y - p.y ); }
28
+ Point operator *(double d) const { return Point (x * d, y * d); }
29
+ Point operator /(double d) const { return Point (x / d, y / d); }
30
+ bool operator <(const Point &p) const {
31
+ int c = sign (x - p.x );
32
+ if (c)
33
+ return c == -1 ;
34
+ return sign (y - p.y ) == -1 ;
35
+ }
36
+ double dot (const Point &p) const { return x * p.x + y * p.y ; }
37
+ double det (const Point &p) const { return x * p.y - y * p.x ; }
38
+ double alpha () const { return atan2 (y, x); }
39
+ double distTo (const Point &p) const {
40
+ double dx = x - p.x , dy = y - p.y ;
41
+ return hypot (dx, dy);
42
+ }
43
+ double alphaTo (const Point &p) const {
44
+ double dx = x - p.x , dy = y - p.y ;
45
+ return atan2 (dy, dx);
46
+ }
47
+ // clockwise
48
+ Point rotAlpha (const double &alpha, const Point &o = Point(0 , 0 )) const {
49
+ double nx = cos (alpha) * (x - o.x ) + sin (alpha) * (y - o.y );
50
+ double ny = -sin (alpha) * (x - o.x ) + cos (alpha) * (y - o.y );
51
+ return Point (nx, ny) + o;
52
+ }
53
+ Point rot90 () const { return Point (-y, x); }
54
+ Point unit () { return *this / abs (); }
55
+ void read () { scanf (" %lf%lf" , &x, &y); }
56
+ double abs () { return hypot (x, y); }
57
+ double abs2 () { return x * x + y * y; }
58
+ void write () { cout << " (" << x << " ," << y << " )" << endl; }
59
+ };
60
+ #define cross (p1, p2, p3 ) ((p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y))
61
+ #define crossOp (p1, p2, p3 ) sign(cross(p1, p2, p3))
22
62
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};
63
+ Point isSS (Point p1, Point p2, Point q1, Point q2) {
64
+ double a1 = cross (q1, q2, p1), a2 = -cross (q1, q2, p2);
65
+ return (p1 * a2 + p2 * a1) / (a1 + a2);
30
66
}
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
- }
67
+ struct Border {
68
+ Point p1, p2;
69
+ double alpha;
70
+ void setAlpha () { alpha = atan2 (p2.y - p1.y , p2.x - p1.x ); }
71
+ void read () {
72
+ p1.read ();
73
+ p2.read ();
74
+ setAlpha ();
75
+ }
50
76
};
51
77
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 ;
78
+ int n;
79
+ const int MAX_N_BORDER = 20000 + 10 ;
80
+ Border border[MAX_N_BORDER];
81
+
82
+ bool operator <(const Border &a, const Border &b) {
83
+ int c = sign (a.alpha - b.alpha );
84
+ if (c != 0 )
85
+ return c == 1 ;
86
+ return crossOp (b.p1 , b.p2 , a.p1 ) >= 0 ;
87
+ }
88
+
89
+ bool operator ==(const Border &a, const Border &b) { return sign (a.alpha - b.alpha ) == 0 ; }
90
+
91
+ void add (double x, double y, double nx, double ny) {
92
+ border[n].p1 = Point (x, y);
93
+ border[n].p2 = Point (nx, ny);
94
+ border[n].setAlpha ();
95
+ n++;
66
96
}
67
97
68
- bool cmp (Line a, Line b) {
69
- return mycmp (a.dir (), b.dir ());
98
+ Point isBorder (const Border &a, const Border &b) { return isSS (a.p1 , a.p2 , b.p1 , b.p2 ); }
99
+
100
+ Border que[MAX_N_BORDER];
101
+ int qh, qt;
102
+
103
+ bool check (const Border &a, const Border &b, const Border &me) {
104
+ Point is = isBorder (a, b);
105
+ return crossOp (me.p1 , me.p2 , is) > 0 ;
70
106
}
71
107
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
- // for (auto i: s) cout<<i<<' ';
96
- // cout<<endl;
97
- double ans = 0 ;
98
- for (i = 0 ; i < (int ) s.size () - 1 ; i++) ans += s[i].cross (s[i + 1 ]);
99
- return ans / 2 ;
108
+ void convexIntersection () {
109
+ qh = qt = 0 ;
110
+ sort (border, border + n);
111
+ n = unique (border, border + n) - border;
112
+ for (int i = 0 ; i < n; ++i) {
113
+ Border cur = border[i];
114
+ while (qh + 1 < qt && !check (que[qt - 2 ], que[qt - 1 ], cur))
115
+ --qt;
116
+ while (qh + 1 < qt && !check (que[qh], que[qh + 1 ], cur))
117
+ ++qh;
118
+ que[qt++] = cur;
119
+ }
120
+ while (qh + 1 < qt && !check (que[qt - 2 ], que[qt - 1 ], que[qh]))
121
+ --qt;
122
+ while (qh + 1 < qt && !check (que[qh], que[qh + 1 ], que[qt - 1 ]))
123
+ ++qh;
100
124
}
125
+
126
+ double calcArea () {
127
+ static Point ps[MAX_N_BORDER];
128
+ int cnt = 0 ;
129
+
130
+ if (qt - qh <= 2 ) {
131
+ return 0 ;
132
+ }
133
+
134
+ for (int i = qh; i < qt; ++i) {
135
+ int next = i + 1 == qt ? qh : i + 1 ;
136
+ ps[cnt++] = isBorder (que[i], que[next]);
137
+ }
138
+
139
+ double area = 0 ;
140
+ for (int i = 0 ; i < cnt; ++i) {
141
+ area += ps[i].det (ps[(i + 1 ) % cnt]);
142
+ }
143
+ area /= 2 ;
144
+ area = fabsl (area);
145
+ return area;
101
146
}
102
- vector<MIT::Line> convert (vector<Line> x) {
103
- vector<MIT::Line> res;
104
- for (auto i: x)
105
- res.push_back (MIT::Line (i[1 ], i[0 ]));
106
- return res;
147
+
148
+ double halfPlaneIntersection (vector<Line> cur) {
149
+ n = 0 ;
150
+ for (auto i: cur)
151
+ add (i[0 ].x , i[0 ].y , i[1 ].x , i[1 ].y );
152
+ convexIntersection ();
153
+ return calcArea ();
107
154
}
155
+ } // namespace sjtu
108
156
109
- const double INF = 1e1 ;
157
+ const double INF = 100 ;
110
158
const double EPS = 1e-8 ;
111
- void addInf (vector<Line> &res, double INF= INF) {
159
+ void addInf (vector<Line> &res, double INF = INF) {
112
160
vector<P> infPts ({P (INF, INF), P (-INF, INF), P (-INF, -INF), P (INF, -INF)});
113
- for (int i=0 ; i<4 ; i++)
114
- res.push_back ({infPts[i], infPts[(i+1 )%4 ]});
115
- }
116
- P randPt (int lim = INF) {
117
- return P (rand () % lim, rand () % lim);
161
+ for (int i = 0 ; i < 4 ; i++)
162
+ res.push_back ({infPts[i], infPts[(i + 1 ) % 4 ]});
118
163
}
164
+ P randPt (int lim = INF) { return P (rand () % lim, rand () % lim); }
119
165
void test1 () {
120
- 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 )}});
166
+ 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 )}});
121
167
auto res = halfPlaneIntersection (t);
122
168
assert (polygonArea2 (res) == 20 );
123
169
addInf (t);
124
170
res = halfPlaneIntersection (t);
125
171
assert (polygonArea2 (res) == 20 );
126
172
}
127
173
void testInf () {
128
- vector<Line> t ({{P (0 ,0 ), P (5 ,0 )}});
174
+ vector<Line> t ({{P (0 , 0 ), P (5 , 0 )}});
129
175
addInf (t);
130
176
auto res = halfPlaneIntersection (t);
131
- assert (polygonArea2 (res)/( 4 * INF* INF) == 1 );
132
- t = vector<Line>({{P (0 ,0 ), P (5 ,0 )}, {P (0 ,0 ), P (0 ,5 )}});
177
+ assert (polygonArea2 (res) / ( 4 * INF * INF) == 1 );
178
+ t = vector<Line>({{P (0 , 0 ), P (5 , 0 )}, {P (0 , 0 ), P (0 , 5 )}});
133
179
addInf (t);
134
180
res = halfPlaneIntersection (t);
135
- assert (polygonArea2 (res)/( 2 * INF* INF) == 1 );
181
+ assert (polygonArea2 (res) / ( 2 * INF * INF) == 1 );
136
182
}
137
183
void testLine () {
138
- vector<Line> t ({{P (0 ,0 ), P (5 ,0 )}, {P (5 ,0 ), P (0 ,0 )}});
184
+ vector<Line> t ({{P (0 , 0 ), P (5 , 0 )}, {P (5 , 0 ), P (0 , 0 )}});
139
185
addInf (t);
140
186
auto res = halfPlaneIntersection (t);
141
187
assert (sz (res) >= 2 );
142
188
assert (polygonArea2 (res) == 0 );
143
189
}
144
190
void testPoint () {
145
- 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 )}});
191
+ 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 )}});
146
192
addInf (t);
147
193
auto res = halfPlaneIntersection (t);
148
194
assert (sz (res) >= 1 );
149
195
assert (polygonArea2 (res) == 0 );
150
196
}
151
197
void testEmpty () {
152
- 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 )},
153
- {P (0 ,2 ), P (5 ,2 )}});
198
+ vector<Line> t (
199
+ {{ P ( 0 , 0 ), P ( 5 , 0 )}, { P ( 5 , 0 ), P ( 0 , 0 )}, { P ( 0 , 0 ), P ( 0 , 5 )}, {P (0 , 5 ), P ( 0 , 0 )}, { P ( 0 , 2 ), P (5 , 2 )}});
154
200
addInf (t);
155
201
auto res = halfPlaneIntersection (t);
156
202
assert (sz (res) == 0 );
157
203
}
158
204
void testRandom () {
159
- for (int i=0 ; i<1000 ; i++) {
205
+ int lim = 10 ;
206
+ for (int i = 0 ; i < 1000 ; i++) {
160
207
vector<Line> t;
161
- for (int i= 0 ; i< 3 ; i++){
162
- Line cand{P (0 ,0 ), P (0 ,0 )};
208
+ for (int i = 0 ; i < 6 ; i++) {
209
+ Line cand{P (0 , 0 ), P (0 , 0 )};
163
210
while (cand[0 ] == cand[1 ])
164
- cand = {randPt (), randPt ()};
211
+ cand = {randPt (lim ), randPt (lim )};
165
212
t.push_back (cand);
166
213
}
167
- addInf (t);
214
+ addInf (t, lim );
168
215
auto res = halfPlaneIntersection (t);
169
- double area = MIT::Intersection_Area ( convert (t) );
170
- double diff = abs (2 * area - polygonArea2 (res));
216
+ double area = sjtu::halfPlaneIntersection (t );
217
+ double diff = abs (2 * area - polygonArea2 (res));
171
218
if (diff > EPS) {
172
- cout<<diff<<' ' <<area<<' ' <<endl;
173
- for (auto i: t) cout<<i[0 ]<<" ->" <<i[1 ]<<' ' ;
174
- cout<<endl;
175
- for (auto i: res) cout<<i<<' ,' ;
176
- cout<<endl;
219
+ cout << diff << ' ' << area << ' ' << endl;
220
+ for (auto i : t)
221
+ cout << i[0 ] << " ->" << i[1 ] << ' ' ;
222
+ cout << endl;
223
+ for (auto i : res)
224
+ cout << i << ' ,' ;
225
+ cout << endl;
177
226
}
178
227
assert (diff < EPS);
179
228
}
180
229
}
181
230
182
231
int main () {
183
- // test1();
184
- // testInf();
185
- // testLine();
186
- // testPoint();
187
- // testEmpty();
188
- // testRandom();
189
- vector<Line> t ({{P (9 ,8 ), P (9 ,1 )}, {P (3 ,3 ),P (3 ,5 )},{P (7 ,6 ),P (0 ,8 )}});
190
- addInf (t);
191
- cout<<polygonArea2 (halfPlaneIntersection (t))<<endl;
192
- cout<<MIT::Intersection_Area (convert (t))<<endl;
193
- cout<<" Tests passed!" <<endl;
232
+ test1 ();
233
+ testInf ();
234
+ testLine ();
235
+ testPoint ();
236
+ testEmpty ();
237
+ testRandom ();
238
+ // Failure case for MIT
239
+ // vector<Line> t({{P(9, 8), P(9, 1)}, {P(3, 3), P(3, 5)}, {P(7, 6), P(0, 8)}});
240
+ // addInf(t);
241
+ // cout << polygonArea2(halfPlaneIntersection(t)) << endl;
242
+ // cout << MIT::Intersection_Area(convert(t)) << endl;
243
+ cout << " Tests passed!" << endl;
194
244
}
0 commit comments