50 lines
1.5 KiB
C++
50 lines
1.5 KiB
C++
using ld = long double;
|
|
using pdd = pair<ld, ld>;
|
|
using line = pair<pdd, pdd>; // half plane : left side of vector fi->se
|
|
|
|
const ld eps = 1e-9;
|
|
pdd operator*(const pdd& a, ld s) { return {a.fi * s, a.se * s}; }
|
|
inline bool equals(ld a, ld b) { return abs(a - b) < eps; }
|
|
|
|
bool line_intersect(line& a, line& b, pdd& v) {
|
|
ld det = (a.se - a.fi) / (b.se - b.fi);
|
|
if (equals(det, 0)) return 0;
|
|
ld t = ((b.fi - a.fi) / (b.se - b.fi)) / det;
|
|
v = a.fi + (a.se - a.fi) * t;
|
|
return 1;
|
|
}
|
|
|
|
bool bad(line& a, line& b, line& c) {
|
|
pdd v; if(!line_intersect(a, b, v)) return 0;
|
|
return (c.se - c.fi) / (v - c.fi) <= eps;
|
|
}
|
|
|
|
vector<pdd> HPI(vector<line>& lns) {
|
|
auto lsgn = [&](const line& a) {
|
|
if(a.fi.se == a.se.se) return a.fi.fi > a.se.fi;
|
|
return a.fi.se > a.se.se;
|
|
};
|
|
sort(lns.begin(), lns.end(), [&](const line& a, const line& b) {
|
|
if(lsgn(a) != lsgn(b)) return lsgn(a) < lsgn(b);
|
|
return (a.se - a.fi) / (b.se - b.fi) > 0;
|
|
});
|
|
|
|
deque<line> dq;
|
|
for(auto l : lns){
|
|
while(dq.size() >= 2 && bad(dq[dq.size()-2], dq.back(), l)) dq.pop_back();
|
|
while(dq.size() >= 2 && bad(dq[0], dq[1], l)) dq.pop_front();
|
|
|
|
if(dq.size() < 2 || !bad(dq.back(), l, dq[0])) dq.pb(l);
|
|
}
|
|
|
|
vector<pdd> res;
|
|
if(dq.size() >= 3) {
|
|
for(int i = 0; i < (int)dq.size(); i++) {
|
|
int j = (i + 1) % (int)dq.size();
|
|
pdd v;
|
|
if(!line_intersect(dq[i], dq[j], v)) continue;
|
|
res.push_back(v);
|
|
}
|
|
}
|
|
return res;
|
|
} |