|
| 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