#define PROBLEM "https://judge.yosupo.jp/problem/aplusb"
#include"template/template.hpp"
#include"geometry/halfplane-intersection.hpp"Polygonhalfplane_cut_naive(constPolygon&P,constLine&l){Polygonret;for(inti=0;i<(int)P.size();++i){Pointa=P[i],b=P[(i+1)%P.size()];intsa=sign(cross(l.b-l.a,a-l.a));intsb=sign(cross(l.b-l.a,b-l.a));if(sa>=0)ret.push_back(a);if(sa*sb<0)ret.push_back(cross_point_ll(Line{a,b},l));}returnret;}intmain(){{Linesls{{{0,0},{2,0}},{{2,2},{0,2}},{{0,2},{0,0}},{{2,0},{2,2}},{{-1,-1},{3,-1}}};PolygonP=halfplane_intersection(ls);assert(P.size()==4);assert(abs(area(P)-4)<EPS);}{Linesempty{{{1,1},{1,0}},{{0,0},{0,1}}};Linesunbounded{{{0,0},{1,0}},{{0,1},{0,0}}};assert(halfplane_intersection(empty).empty());assert(halfplane_intersection(unbounded).empty());}mt19937rng(7654321);uniform_int_distribution<int>coord(-50,50);for(inttc=0;tc<1000;++tc){vector<Point>ps(30);for(auto&p:ps)p=Point{(Real)coord(rng),(Real)coord(rng)};PolygonC=convex_hull(ps);if(C.size()<3)continue;Linesls;for(inti=0;i<(int)C.size();++i)ls.emplace_back(C[i],C[(i+1)%C.size()]);shuffle(ls.begin(),ls.end(),rng);PolygonP=halfplane_intersection(ls);assert(P.size()==C.size());assert(abs(area(P)-area(C))<1e-8);}uniform_int_distribution<int>small(-80,80);for(inttc=0;tc<2000;++tc){Polygonwant{{-100,-100},{100,-100},{100,100},{-100,100}};Linesls{{{-100,-100},{100,-100}},{{100,-100},{100,100}},{{100,100},{-100,100}},{{-100,100},{-100,-100}}};for(inti=0;i<12;++i){Pointa{(Real)small(rng),(Real)small(rng)};Pointb{(Real)small(rng),(Real)small(rng)};if(a==b)b.x+=1;ls.emplace_back(a,b);if(!want.empty())want=halfplane_cut_naive(want,ls.back());}shuffle(ls.begin(),ls.end(),rng);Polygongot=halfplane_intersection(ls);Realwant_area=want.empty()?0:area(want);Realgot_area=got.empty()?0:area(got);assert(abs(want_area-got_area)<1e-7);}inta,b;in(a,b);out(a+b);}
#line 1 "verify/geometry/UNIT_halfplane_intersection.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/aplusb"
#line 2 "template/template.hpp"
#include<bits/stdc++.h>usingnamespacestd;#line 2 "template/macro.hpp"
#define rep(i, a, b) for (int i = (a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b) - 1; i >= (a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())
#define YN(b) cout << ((b) ? "YES" : "NO") << "\n";
#define Yn(b) cout << ((b) ? "Yes" : "No") << "\n";
#define yn(b) cout << ((b) ? "yes" : "no") << "\n";
#line 6 "template/template.hpp"
#line 2 "template/util.hpp"
usinguint=unsignedint;usingll=longlongint;usingull=unsignedlonglong;usingi128=__int128_t;usingu128=__uint128_t;template<classT>usingpriority_queue_asc=priority_queue<T,vector<T>,greater<T>>;template<classT,classS=T>SSUM(constvector<T>&a){returnaccumulate(ALL(a),S(0));}template<classT1,classT2>inlineboolchmin(T1&a,T2b){if(a>b){a=b;returntrue;}returnfalse;}template<classT1,classT2>inlineboolchmax(T1&a,T2b){if(a<b){a=b;returntrue;}returnfalse;}template<classT1,classT2>inlineboolchmin_opt(optional<T1>&a,T2b){if(!a||a>b){a=b;returntrue;}returnfalse;}template<classT1,classT2>inlineboolchmax_opt(optional<T1>&a,T2b){if(!a||a<b){a=b;returntrue;}returnfalse;}template<classT>intpopcnt(Tx){return__builtin_popcountll(x);}template<classT>inttopbit(Tx){return(x==0?-1:63-__builtin_clzll(x));}template<classT>intlowbit(Tx){return(x==0?-1:__builtin_ctzll(x));}#line 8 "template/template.hpp"
#line 2 "template/inout.hpp"
structFast{Fast(){cin.tie(nullptr);ios_base::sync_with_stdio(false);cout<<fixed<<setprecision(15);}}fast;ostream&operator<<(ostream&os,__uint128_tx){charbuf[40];size_tk=0;while(x>0)buf[k++]=(char)(x%10+'0'),x/=10;if(k==0)buf[k++]='0';while(k)os<<buf[--k];returnos;}ostream&operator<<(ostream&os,__int128_tx){returnx<0?(os<<'-'<<(__uint128_t)(-x)):(os<<(__uint128_t)x);}template<classT,size_tN>ostream&operator<<(ostream&os,constarray<T,N>&a);template<classT1,classT2>istream&operator>>(istream&is,pair<T1,T2>&p){returnis>>p.first>>p.second;}template<classT1,classT2>ostream&operator<<(ostream&os,constpair<T1,T2>&p){returnos<<p.first<<" "<<p.second;}template<classT>istream&operator>>(istream&is,vector<T>&a){for(auto&v:a)is>>v;returnis;}template<classT>ostream&operator<<(ostream&os,constvector<T>&a){for(autoit=a.begin();it!=a.end();){os<<*it;if(++it!=a.end())os<<" ";}returnos;}template<classT,size_tN>ostream&operator<<(ostream&os,constarray<T,N>&a){for(autoit=a.begin();it!=a.end();){os<<*it;if(++it!=a.end())os<<" ";}returnos;}template<classT>ostream&operator<<(ostream&os,constset<T>&st){os<<"{";for(autoit=st.begin();it!=st.end();){os<<*it;if(++it!=st.end())os<<",";}os<<"}";returnos;}template<classT1,classT2>ostream&operator<<(ostream&os,constmap<T1,T2>&mp){os<<"{";for(autoit=mp.begin();it!=mp.end();){os<<it->first<<":"<<it->second;if(++it!=mp.end())os<<",";}os<<"}";returnos;}voidin(){}template<typenameT,class...U>voidin(T&t,U&...u){cin>>t;in(u...);}template<class...T>voidin_zip(intn,T&...t){assert(n>=0&&((size(t)>=static_cast<size_t>(n))&&...));for(inti=0;i<n;i++)in(t[i]...);}voidout(){cout<<"\n";}template<typenameT,class...U,charsep=' '>voidout(constT&t,constU&...u){cout<<t;if(sizeof...(u))cout<<sep;out(u...);}template<classT,classU>voidout_opt(constoptional<T>&opt,constU&fallback,ostream&os=cout){if(opt.has_value())os<<opt.value();elseos<<fallback;os<<"\n";}template<classT,classU>voidout_opt(constvector<optional<T>>&vec,constU&fallback,ostream&os=cout){for(autoit=vec.begin();it!=vec.end();){if((*it).has_value())os<<(*it).value();elseos<<fallback;if(++it!=vec.end())os<<" ";}os<<"\n";}namespaceIO{template<classT,class...U>Tread(U&&...u){Tt=T(forward<U>(u)...);in(t);returnt;}namespaceGraph{vector<vector<int>>unweighted(intn,intm,booldirected=false,intoffset=1){vector<vector<int>>g(n);for(inti=0;i<m;i++){intu,v;cin>>u>>v;u-=offset,v-=offset;g[u].push_back(v);if(!directed)g[v].push_back(u);}returng;}template<classT>vector<vector<pair<int,T>>>weighted(intn,intm,booldirected=false,intoffset=1){vector<vector<pair<int,T>>>g(n);for(inti=0;i<m;i++){intu,v;Tw;cin>>u>>v>>w;u-=offset,v-=offset;g[u].push_back({v,w});if(!directed)g[v].push_back({u,w});}returng;}}// namespace GraphnamespaceTree{vector<vector<int>>unweighted(intn,booldirected=false,intoffset=1){returnGraph::unweighted(n,n-1,directed,offset);}template<classT>vector<vector<pair<int,T>>>weighted(intn,booldirected=false,intoffset=1){returnGraph::weighted<T>(n,n-1,directed,offset);}vector<vector<int>>rooted(intn,boolto_root=true,boolto_leaf=true,intoffset=1){vector<vector<int>>g(n);for(inti=1;i<n;i++){intp;cin>>p;p-=offset;if(to_root)g[i].push_back(p);if(to_leaf)g[p].push_back(i);}returng;}}// namespace Tree}// namespace IO#line 10 "template/template.hpp"
#line 2 "template/debug.hpp"
#ifdef LOCAL
#define debug 1
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define debug 0
#define show(...) true
#endif
template<classT>void_show(int,T){cerr<<'\n';}template<classT1,classT2,class...T3>void_show(inti,constT1&a,constT2&b,constT3&...c){for(;a[i]!=','&&a[i]!='\0';i++)cerr<<a[i];cerr<<":"<<b<<" ";_show(i+1,a,c...);}#line 2 "geometry/halfplane-intersection.hpp"
#line 2 "geometry/line.hpp"
#line 2 "geometry/geometry-base.hpp"
#line 4 "geometry/geometry-base.hpp"
usingReal=longdouble;constexprRealEPS=1e-10;constexprRealPI=3.141592653589793238462643383279L;boolequals(Realx,Realy){returnfabs(x-y)<EPS;}intsign(Reala){returnequals(a,0)?0:(a>0?1:-1);}template<classR>structPointBase{usingP=PointBase;Rx,y;PointBase():x(0),y(0){}PointBase(R_x,R_y):x(_x),y(_y){}template<typenameT,typenameU>PointBase(constpair<T,U>&p):x(p.first),y(p.second){}Poperator+(constP&r)const{returnP{x+r.x,y+r.y};}Poperator-(constP&r)const{returnP{x-r.x,y-r.y};}Poperator-()const{returnP{-x,-y};}Poperator*(Rr)const{returnP{x*r,y*r};}Poperator/(Rr)const{returnP{x/r,y/r};}P&operator+=(constP&r){return(*this)=(*this)+r;}P&operator-=(constP&r){return(*this)=(*this)-r;}P&operator*=(Rr){return(*this)=(*this)*r;}P&operator/=(Rr){return(*this)=(*this)/r;}booloperator<(constP&r)const{returnx!=r.x?x<r.x:y<r.y;}booloperator==(constP&r)const{returnx==r.xandy==r.y;}booloperator!=(constP&r)const{return!((*this)==r);}Protate(Rrad)const{return{x*cos(rad)-y*sin(rad),x*sin(rad)+y*cos(rad)};}Protate90()const{return{-y,x};}Rreal()const{returnx;}Rimag()const{returny;}friendPoperator*(Rr,constP&p){returnp*r;}friendRreal(constP&p){returnp.x;}friendRimag(constP&p){returnp.y;}friendRdot(constP&l,constP&r){returnl.x*r.x+l.y*r.y;}friendRcross(constP&l,constP&r){returnl.x*r.y-l.y*r.x;}friendRabs(constP&p){returnsqrt(p.x*p.x+p.y*p.y);}friendRnorm(constP&p){returnp.x*p.x+p.y*p.y;}friendRarg(constP&p){returnatan2(p.y,p.x);}friendistream&operator>>(istream&is,P&p){Ra,b;is>>a>>b;p=P{a,b};returnis;}friendostream&operator<<(ostream&os,constP&p){returnos<<p.x<<" "<<p.y;}};usingPoint=PointBase<Real>;usingPoints=vector<Point>;// relative position of c from a->bintccw(constPoint&a,constPoint&b,constPoint&c){Pointx=b-a,y=c-a;if(cross(x,y)>EPS)return+1;// counter-clockwiseif(cross(x,y)<-EPS)return-1;// clockwiseif(dot(x,y)<-EPS)return+2;// collinear in the order c-a-bif(norm(x)+EPS<norm(y))return-2;// collinear in the order a-b-creturn0;// collinear in the order a-c-b}/**
* @brief 二次元幾何の基本要素
* @docs docs/geometry/geometry-base.md
*/#line 2 "geometry/polygon.hpp"
#line 4 "geometry/polygon.hpp"
// 反時計周りusingPolygon=vector<Point>;// 多角形の内部に点があるか// OUT : 0, ON : 1, IN : 2// 凸でなくてもよい, 自己交差はもたない// crossing number algorithm : x 軸正方向に伸ばした半直線が奇数回交われば内部intcontains_polygon(constPolygon&P,constPoint&p){boolin=false;for(inti=0;i<(int)P.size();i++){Pointa=P[i]-p,b=P[(i+1)%P.size()]-p;if(a.y>b.y)swap(a,b);if(equals(cross(a,b),0)&&sign(dot(a,b))<=0)return1;if(sign(a.y)<=0&&0<sign(b.y)&&sign(cross(a,b))<0)in=!in;}returnin?2:0;}// 多角形の面積Realarea(constPolygon&P){RealA=0;for(inti=0;i<(int)P.size();i++){A+=cross(P[i],P[(i+1)%P.size()]);}returnA*0.5;}boolis_convex(constPolygon&P){intn=P.size();if(n<3)returntrue;for(inti=0;i<n;++i){if(ccw(P[i],P[(i+1)%n],P[(i+2)%n])==-1)returnfalse;}returntrue;}// 頂点集合から凸包を生成// boundary : 周上の点も列挙する場合 truetemplate<boolboundary=false>Polygonconvex_hull(vector<Point>ps){sort(begin(ps),end(ps));ps.erase(unique(begin(ps),end(ps)),end(ps));intn=ps.size(),k=0;if(n<=2)returnps;ifconstexpr(boundary){boolcollinear=true;for(inti=2;i<n;++i){if(!equals(cross(ps[1]-ps[0],ps[i]-ps[0]),0)){collinear=false;break;}}if(collinear)returnps;}vector<Point>ch(2*n);// 反時計周りconstRealth=boundary?-EPS:+EPS;for(inti=0;i<n;ch[k++]=ps[i++]){while(k>=2&&cross(ch[k-1]-ch[k-2],ps[i]-ch[k-1])<th)--k;}for(inti=n-2,t=k+1;i>=0;ch[k++]=ps[i--]){while(k>=t&&cross(ch[k-1]-ch[k-2],ps[i]-ch[k-1])<th)--k;}ch.resize(k-1);returnch;}// 凸包の内部に点があるか// OUT : 0, ON : 1, IN : 2intcontains_convex(constPolygon&C,constPoint&p){intN=C.size();if(N==0)return0;if(N==1)returnabs(C[0]-p)<EPS?1:0;if(N==2)returnccw(C[0],C[1],p)==0?1:0;autob1=cross(C[1]-C[0],p-C[0]);autob2=cross(C[N-1]-C[0],p-C[0]);if(b1<-EPSorb2>EPS)return0;intL=1,R=N-1;while(L+1<R){intM=(L+R)/2;(cross(p-C[0],C[M]-C[0])>=0?R:L)=M;}autov=cross(C[L]-p,C[R]-p);if(equals(v,0)){return1;}elseif(v>0){returnequals(b1,0)orequals(b2,0)?1:2;}else{return0;}}// 凸多角形の最遠点対を返す// 返り値:頂点番号のペアpair<int,int>convex_polygon_diameter(constPolygon&C){intN=(int)C.size();assert(N>0);if(N==1)return{0,0};if(N==2)return{0,1};intis=0,js=0;for(inti=1;i<N;i++){if(C[i].y>C[is].y)is=i;if(C[i].y<C[js].y)js=i;}Realmaxdis=norm(C[is]-C[js]);intmaxi,maxj,i,j;i=maxi=is;j=maxj=js;do{if(cross(C[(i+1)%N]-C[i],C[(j+1)%N]-C[j])>=0){j=(j+1)%N;}else{i=(i+1)%N;}if(norm(C[i]-C[j])>maxdis){maxdis=norm(C[i]-C[j]);maxi=i;maxj=j;}}while(i!=is||j!=js);returnminmax(maxi,maxj);}// min argmax_i dot(C[i], p)intargmax_dot(constPolygon&C,constPoint&p){intn=C.size();assert(n>0);assert(p.x!=0||p.y!=0);if(n<=2){if(n==1||dot(C[0],p)>=dot(C[1],p))return0;return1;}autoarg_half=[](constPoint&a){returna.y<0||(a.y==0&&a.x<0);};autoarg_less=[&](constPoint&a,constPoint&b){intha=arg_half(a),hb=arg_half(b);returnha!=hb?ha<hb:cross(a,b)>0;};autoedge=[&](inti){returnC[(i+1)%n]-C[i];};intl=0,r=n-1;while(l<r){intm=(l+r)/2;if(arg_less(edge(r),edge(m)))l=m+1;elser=m;}ints=l;Pointq=p.rotate90();l=0,r=n;while(l<r){intm=(l+r)/2;if(arg_less(edge((s+m)%n),q))l=m+1;elser=m;}inti=(s+(l==n?0:l))%n;Pointe=edge(i);if(!arg_less(e,q)&&!arg_less(q,e)){intlow=l;l=low,r=n;while(l<r){intm=(l+r)/2;if(!arg_less(q,edge((s+m)%n)))l=m+1;elser=m;}intcount=l-low;returni+count>=n?0:i;}returni;}structConvexPolygonCutResult{intfirst=0,last=0;optional<Point>front,back;boolempty()const{returnfirst==last&&!front&&!back;}Polygonto_polygon(constPolygon&C)const{Polygonret;autopush=[&](constPoint&p){if(ret.empty()||abs(ret.back()-p)>=EPS)ret.push_back(p);};if(front)push(*front);for(inti=first;i<last;++i)push(C[i%C.size()]);if(back)push(*back);if(ret.size()>=2&&abs(ret.front()-ret.back())<EPS)ret.pop_back();returnret;}};ConvexPolygonCutResultconvex_polygon_cut_info(constPolygon&C,constPoint&a,constPoint&b){intn=C.size();assert(n>0&&a!=b);Pointd=b-a,normal=d.rotate90();autoside=[&](inti){returnsign(cross(d,C[i%n]-a));};intmx=argmax_dot(C,normal),mn=argmax_dot(C,-normal);if(side(mx)<0)return{};if(side(mn)>=0)return{0,n,nullopt,nullopt};intl=mn,r=mx;if(r<l)r+=n;while(l+1<r){intm=(l+r)/2;(side(m)>=0?r:l)=m;}intfirst=r;l=mx,r=mn;if(r<=l)r+=n;while(l+1<r){intm=(l+r)/2;(side(m)<0?r:l)=m;}intlast=r;if(last<first)last+=n;intcount=last-first;first%=n;ConvexPolygonCutResultret{first,first+count,nullopt,nullopt};autocross_point=[&](constPoint&p,constPoint&q){returnp+(q-p)*(cross(d,a-p)/cross(d,q-p));};if(side(first)>0)ret.front=cross_point(C[(first+n-1)%n],C[first]);intback=(ret.last-1)%n;if(side(back)>0)ret.back=cross_point(C[back],C[(back+1)%n]);returnret;}Polygonconvex_polygon_cut(constPolygon&C,constPoint&a,constPoint&b){returnconvex_polygon_cut_info(C,a,b).to_polygon(C);}/**
* @brief 多角形
* @docs docs/geometry/polygon.md
*/#line 5 "geometry/line.hpp"
structLine{usingP=Point;Pa,b;Line()=default;Line(constP&_a,constP&_b):a(_a),b(_b){}// Ax + By = CLine(RealA,RealB,RealC){assert(!equals(A,0)||!equals(B,0));if(!equals(B,0)){a=P{0,C/B};b=P{1,(C-A)/B};}else{a=P{C/A,0};b=P{C/A,1};}}friendistream&operator>>(istream&is,Line&l){returnis>>l.a>>l.b;}friendostream&operator<<(ostream&os,constLine&l){returnos<<l.a<<" to "<<l.b;}};usingLines=vector<Line>;boolis_parallel(constLine&l,constLine&m){returnequals(cross(l.b-l.a,m.b-m.a),0);}boolis_orthogonal(constLine&l,constLine&m){returnequals(dot(l.b-l.a,m.b-m.a),0);}boolis_intersect_ll(constLine&l,constLine&m){return!is_parallel(l,m)||equals(cross(l.b-l.a,m.a-l.a),0);}// Parallel distinct lines must not be given.Pointcross_point_ll(constLine&l,constLine&m){Pointu=l.b-l.a,v=m.b-m.a;Reald=cross(u,v);if(equals(d,0)){assert(equals(cross(u,m.a-l.a),0));returnm.a;}returnl.a+u*(cross(m.a-l.a,v)/d);}Pointprojection(constLine&l,constPoint&p){Pointd=l.b-l.a;returnl.a+d*(dot(p-l.a,d)/norm(d));}Pointreflection(constLine&l,constPoint&p){returnprojection(l,p)*2-p;}Realdistance_lp(constLine&l,constPoint&p){returnabs(p-projection(l,p));}// Returns the left side of the directed line l.a -> l.b.Polygonconvex_polygon_cut(constPolygon&P,constLine&l){returnconvex_polygon_cut(P,l.a,l.b);}ConvexPolygonCutResultconvex_polygon_cut_info(constPolygon&P,constLine&l){returnconvex_polygon_cut_info(P,l.a,l.b);}/**
* @brief 直線
* @docs docs/geometry/line.md
*/#line 4 "geometry/halfplane-intersection.hpp"
// Returns the bounded, positive-area intersection of left half-planes.// Returns an empty polygon if the intersection is empty, degenerate, or unbounded.Polygonhalfplane_intersection(Linesls){autodirection=[](constLine&l){returnl.b-l.a;};autoarg_half=[](constPoint&a){returna.y<0||(a.y==0&&a.x<0);};autoarg_less=[&](constLine&l,constLine&r){Pointa=direction(l),b=direction(r);intha=arg_half(a),hb=arg_half(b);returnha!=hb?ha<hb:cross(a,b)>0;};for(constauto&l:ls)assert(l.a!=l.b);sort(ls.begin(),ls.end(),arg_less);Lineslines;for(constauto&l:ls){if(!lines.empty()&&is_parallel(lines.back(),l)&&dot(direction(lines.back()),direction(l))>0){if(sign(cross(direction(lines.back()),l.a-lines.back().a))>0)lines.back()=l;}else{lines.push_back(l);}}autooutside=[&](constLine&l,constPoint&p){returnsign(cross(direction(l),p-l.a))<0;};deque<Line>dq;for(constauto&l:lines){while(dq.size()>=2&&outside(l,cross_point_ll(dq[dq.size()-2],dq.back())))dq.pop_back();while(dq.size()>=2&&outside(l,cross_point_ll(dq[0],dq[1])))dq.pop_front();if(!dq.empty()&&is_parallel(dq.back(),l))return{};dq.push_back(l);}while(dq.size()>=3&&outside(dq.front(),cross_point_ll(dq[dq.size()-2],dq.back())))dq.pop_back();while(dq.size()>=3&&outside(dq.back(),cross_point_ll(dq[0],dq[1])))dq.pop_front();if(dq.size()<3)return{};intn=dq.size();for(inti=0;i<n;++i){if(sign(cross(direction(dq[i]),direction(dq[(i+1)%n])))<=0)return{};}Polygonret;for(inti=0;i<n;++i)ret.push_back(cross_point_ll(dq[i],dq[(i+1)%n]));returnret;}/**
* @brief 半平面交差
* @docs docs/geometry/halfplane-intersection.md
*/#line 5 "verify/geometry/UNIT_halfplane_intersection.test.cpp"
Polygonhalfplane_cut_naive(constPolygon&P,constLine&l){Polygonret;for(inti=0;i<(int)P.size();++i){Pointa=P[i],b=P[(i+1)%P.size()];intsa=sign(cross(l.b-l.a,a-l.a));intsb=sign(cross(l.b-l.a,b-l.a));if(sa>=0)ret.push_back(a);if(sa*sb<0)ret.push_back(cross_point_ll(Line{a,b},l));}returnret;}intmain(){{Linesls{{{0,0},{2,0}},{{2,2},{0,2}},{{0,2},{0,0}},{{2,0},{2,2}},{{-1,-1},{3,-1}}};PolygonP=halfplane_intersection(ls);assert(P.size()==4);assert(abs(area(P)-4)<EPS);}{Linesempty{{{1,1},{1,0}},{{0,0},{0,1}}};Linesunbounded{{{0,0},{1,0}},{{0,1},{0,0}}};assert(halfplane_intersection(empty).empty());assert(halfplane_intersection(unbounded).empty());}mt19937rng(7654321);uniform_int_distribution<int>coord(-50,50);for(inttc=0;tc<1000;++tc){vector<Point>ps(30);for(auto&p:ps)p=Point{(Real)coord(rng),(Real)coord(rng)};PolygonC=convex_hull(ps);if(C.size()<3)continue;Linesls;for(inti=0;i<(int)C.size();++i)ls.emplace_back(C[i],C[(i+1)%C.size()]);shuffle(ls.begin(),ls.end(),rng);PolygonP=halfplane_intersection(ls);assert(P.size()==C.size());assert(abs(area(P)-area(C))<1e-8);}uniform_int_distribution<int>small(-80,80);for(inttc=0;tc<2000;++tc){Polygonwant{{-100,-100},{100,-100},{100,100},{-100,100}};Linesls{{{-100,-100},{100,-100}},{{100,-100},{100,100}},{{100,100},{-100,100}},{{-100,100},{-100,-100}}};for(inti=0;i<12;++i){Pointa{(Real)small(rng),(Real)small(rng)};Pointb{(Real)small(rng),(Real)small(rng)};if(a==b)b.x+=1;ls.emplace_back(a,b);if(!want.empty())want=halfplane_cut_naive(want,ls.back());}shuffle(ls.begin(),ls.end(),rng);Polygongot=halfplane_intersection(ls);Realwant_area=want.empty()?0:area(want);Realgot_area=got.empty()?0:area(got);assert(abs(want_area-got_area)<1e-7);}inta,b;in(a,b);out(a+b);}