三角形和矩形 (半平面交)

題面
額,一個半平面交的板子題
測下板子,裏面摻雜大量無用代碼,懶得刪除了

#include <bits/stdc++.h>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <unordered_map>
#include <set>
#include <vector>
#include <assert.h>
#include <cmath>
#include <ctime>
using namespace std;
#define me(x,y) memset((x),(y),sizeof (x))
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define SGN(x) ((x)>0?1:((x)<0?-1:0))
#define ABS(x) ((x)>0?(x):-(x))
// #define int __int128_t

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

const int maxn = 1e6+10;
// const int inf = __INT32_MAX__;
const ll INF = __LONG_LONG_MAX__;
const int mod = 1e9+7;
const double eps = 1e-8;
const double pi = std::acos(-1);
// const string cars[] = {"?","?","?"};

const double inf=1e20;
const int maxp = 1010;
/**
 * Compares a double to zero
 */
int sgn(double x){
    if(fabs(x) < eps) return 0;
    if(x < 0)return -1;
    else return 1;
}

inline double sqr(double x){return x*x;}


struct Point{
    double x,y;
    Point(){}
    Point(double _x,double _y){x = _x,y = _y;}
    void input(){scanf("%lf%lf",&x,&y);}
    void output(){printf("%.2f %.2f\n",x,y);}
    bool operator == (Point b)const{return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;}
    bool operator < (Point b)const{return sgn(x-b.x) == 0 ? sgn(y-b.y)<0 : x<b.x;}
    Point operator -(const Point &b)const{return Point(x-b.x,y-b.y);}
    /**
     * 叉積
     */
    double operator ^ (const Point &b)const{return x*b.y-y*b.x;}    
    /**
     * 點積
     */
    double operator * (const Point &b)const{return x*b.x+y*b.y;}    
    /**
     * 返回長度
     */
    double len(){return hypot(x,y);}                                
    /**
     * 返回長度平方
     */
    double len2(){return x*x+y*y;}                                  
    /**
     * 返回兩點間距離
     */
    double distance(Point p){return hypot(x-p.x,y-p.y);}            
    Point operator + (const Point &b)const{return Point(x+b.x,y+b.y);}
    Point operator * (const double &k)const{return Point(x*k,y*k);} 
    Point operator / (const double &k)const{return Point(x/k,y/k);} 
    /**
     * 計算該點看a,b點的角度
     */
    double rad(Point a,Point b){Point p = *this;return fabs(atan2(fabs((a-p)^(b-p)),(a-p)*(b-p)));}
    /**
     * 化爲長度爲r的向量
     */
    Point trunc(double r){  
        double l = len();
        if(!sgn(l)) return *this;
        r /= l;
        return Point(x*r,y*r);    
    }
    /**
     * 逆時針轉90度
     */
    Point rotleft(){return Point(-y,x);}                             
    /**
     * 順時針轉90度
     */
    Point rotright(){return Point(y,-x);}                            
    /**
     * 繞p點逆時針轉angle
     */
    Point rotate(Point p,double angle){                              
        Point v = (*this)-p;
        double c = cos(angle),s = sin(angle);
        return Point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c);
    }
};

struct Line{
    Point s,e;
    Line(){}
    Line(Point _s,Point _e){s = _s;e = _e;}
    bool operator == (Line v){return (s == v.s) && (e == v.e);}
    /**
     * 根據一個點和傾斜角angle確定直線,0<=angle<=pi
     */
    Line(Point p,double angle){                                     
        s = p;
        if(sgn(angle-pi/2) == 0){e = (s+Point(0,1));}
        else{e = (s+Point(1,tan(angle)));}
    }
    /**
     * ax+by+c=0
     */
    Line(double a,double b,double c){                               
        if(sgn(a) == 0){s = Point(0,-c/b);e=Point(1,-c/b);}
        else if(sgn(b) == 0){s = Point(-c/a,0);e = Point(-c/a,1);}
        else{s = Point(0,-c/b);e = Point(1,(-c-a)/b);}
    }
    void input(){s.input();e.input();}                              
    void adjust(){if(e < s) swap(s,e);}
    /**
     * 求線段長度
     */
    double length(){return s.distance(e);}                          
    /**
     * 返回直線傾斜角0<=angle<=pi
     */
    double angle(){                                                 
        double k = atan2(e.y-s.y,e.x-s.x);
        if(sgn(k)<0) k+=pi;
        if(sgn(k-pi)==0) k-= pi;
        return k;
    }
    /**
     * 點和直線的關係
     * 1在左側
     * 2在右側
     * 3在直線上
     */
    int relation(Point p){                                          
        int c = sgn((p-s)^(e-s));
        if(c < 0)return 1;
        else if(c > 0) return 2;
        else return 3;
    }
    /**
     * 點在線段上的判斷
     */
    bool  pointonseg(Point p){return sgn((p-s)^(e-s)) == 0 && sgn((p-s)^(e-s)) <= 0;}   
    /**
     * 兩向量平行(對應直線平行或重合)
     */
    bool parallel(Line v){return sgn((e-s)^(v.e-v.s)) == 0;}        
    /**
     * 兩線段相交判斷
     * 2規範相交
     * 1非規範相交
     * 0不相交
     */
    int segcrosseg(Line v){                                         
        int d1 = sgn((e-s)^(v.s-s));
        int d2 = sgn((e-s)^(v.e-s));
        int d3 = sgn((v.e-v.s)^(s-v.s));
        int d4 = sgn((v.e-v.s)^(e-v.s));
        if((d1^d2) == -2 && (d3^d4) == -2)return 2;
        return (d1 == 0 && sgn((v.s-s)*(v.s-e)) <= 0) || 
               (d2 == 0 && sgn((v.e-s)*(v.e-e)) <= 0) ||
               (d3 == 0 && sgn((s-v.s)*(s-v.e)) <= 0) ||
               (d4 == 0 && sgn((e-v.s)*(e-v.e)) <= 0);
    }
    /**
     * 直線和線段相交判斷
     * 2規範相交
     * 1非規範相交
     * 0不相交
     */
    int linecrossseg(Line v){                                       
        int d1 = sgn((e-s)^(v.s-s));
        int d2 = sgn((e-s)^(v.e-s));
        if((d1^d2) == -2) return 2;
        return (d1 == 0 || d2 == 0);
    }
    /**
     * 兩直線關係
     * 0平行
     * 1重合
     * 2相交
     */
    int linecrossline(Line v){                                      
        if((*this).parallel(v)) return v.relation(s) == 3;
        return 2;
    }
    /**
     * 求兩直線焦點,要保證兩直線不平行或重合
     */
    Point crosspoint(Line v){                                       
        double a1 = (v.e-v.s)^(s-v.s);
        double a2 = (v.e-v.s)^(e-v.s);
        return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
    }
    /**
     * 點到直線的距離
     */
    double dispointtoline(Point p){return fabs((p-s)*(e-s))/length();}  
    /**
     * 點到線段的距離
     */
    double dispointtoseg(Point p){                                  
        if(sgn((p-s)*(e-s)) < 0 || sgn((p-e)*(s-e)) < 0)
            return min(p.distance(s),p.distance(e));
        return dispointtoline(p);
    }
    /**
     * 線段到線段的距離,前提是兩線段不相交,相交距離爲0
     */
    double dissegtoseg(Line v){                                     
        return min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v.dispointtoseg(s),v.dispointtoseg(e)));
    }
    /**
     * 返回點p在直線上的投影
     */
    Point lineprog(Point p){return s+(((e-s)*((e-s)*(p-s)))/((e-s).len2()));}   
    /**
     * 返回點p關於直線的對稱點
     */
    Point symmetypoint(Point p){Point q = lineprog(p);return Point(2*q.x-p.x,2*q.y-p.y);}   
};


struct polygon{
    int n;
    Point p[maxp];
    Line l[maxp];
    void input(int _n){
        n = _n;
        for(int i = 0; i < n; ++i) p[i].input();
    }
    void add(Point q){p[n++] = q;}
    void getline(){
        for(int i = 0; i < n; ++i){
            l[i] = Line(p[i],p[(i+1)%n]);
        }
    }
    struct cmp{
        Point p;
        cmp(const Point &p0){p = p0;}
        bool operator()(const Point &aa,const Point &bb){
            Point a = aa,b = bb;
            int d = sgn((a-p)^(b-p));
            if(d == 0) return sgn(a.distance(p)-b.distance(p))<0;
            return d > 0;
        }
    };
    /**
     * 進行極角排序,首先找到最左下角的點
     */
    void norm(){  
        Point mi = p[0];
        for(int i = 1; i < n; ++i) mi = min(mi,p[i]);
        sort(p,p+n,cmp(mi));
    }
    /**
     * 得到面積
     */
    double getarea(){
        double sum=0;
        for(int i = 0; i < n; ++i){
            sum += (p[i]^p[(i+1)%n]);
        }
        return fabs(sum)/2;
    }
};

//半平面交
struct halfplane:public Line{
    double angle;
    halfplane(){}
    //表示向量 s->e 逆時針 (左側) 的半平面
    halfplane(Point _s,Point _e){
        s = _s;
        e = _e;
    }
    halfplane(Line v){
        s = v.s;
        e = v.e;
    }
    void calcangle(){
        angle = atan2(e.y-s.y,e.x-s.x);
    }
    bool operator <(const halfplane &b)const{
        return angle < b.angle;
    }
};
struct halfplanes{
    int n;
    halfplane hp[maxp];
    Point p[maxp];
    int que[maxp];
    int st,ed;
    void push(halfplane tmp){
        hp[n++] = tmp;
    }
    //去重
    void unique(){
        int m = 1;
        for(int i = 1;i < n;i++){
            if(sgn(hp[i].angle-hp[i-1].angle) != 0)
                hp[m++] = hp[i];
            else if(sgn( (hp[m-1].e-hp[m-1].s)^(hp[i].s-hp[m-1].s)) > 0)
                hp[m-1] = hp[i];
        }
        n = m;
    }
    bool halfplaneinsert(){
        for(int i = 0;i < n;i++)hp[i].calcangle();
        sort(hp,hp+n);
        unique();
        que[st=0] = 0;
        que[ed=1] = 1;
        p[1] = hp[0].crosspoint(hp[1]);
        for(int i = 2;i < n;i++){
            while(st<ed && sgn((hp[i].e-hp[i].s)^(p[ed]-hp[i].s))<0)ed--;
            while(st<ed && sgn((hp[i].e-hp[i].s)^(p[st+1]-hp[i].s))<0)st++;
            que[++ed] = i;
            if(hp[i].parallel(hp[que[ed-1]])) return false;
            p[ed]=hp[i].crosspoint(hp[que[ed-1]]);
        }
        while(st<ed && sgn((hp[que[st]].e-hp[que[st]].s)^(p[ed]-hp[que[st]].s))<0)ed--;
        while(st<ed && sgn((hp[que[ed]].e-hp[que[ed]].s)^(p[st+1]-hp[que[ed]].s))<0)st++;
        if(st+1>=ed)return false;
        return true;
    }
    //得到最後半平面交得到的凸多邊形
    //需要先調用 halfplaneinsert() 且返回 true
    void getconvex(polygon &con){
        p[st] = hp[que[st]].crosspoint(hp[que[ed]]);
        con.n = ed-st+1;
        for(int j = st,i = 0;j <= ed;i++,j++)
            con.p[i] = p[j];
    }
};

int main(){
    // ios::sync_with_stdio(false);
    #ifndef ONLINE_JUDGE
        freopen("1in.in","r",stdin);
        freopen("1out.out","w",stdout);
    #endif
    double x1,x2,x3,x4,y1,y2,y3,y4;
    while(cin>>x1>>y1>>x2>>y2>>x3>>y3>>x4>>y4){
        polygon tr;
        tr.n = 3;
        tr.p[0] = Point(x1,y1),tr.p[1] = Point(x1,y2),tr.p[2] = Point(x2,y1);
        tr.norm();
        halfplanes re;
        re.n=0;
        re.push(halfplane(Line(tr.p[0],tr.p[1])));
        re.push(halfplane(Line(tr.p[1],tr.p[2])));
        re.push(halfplane(Line(tr.p[2],tr.p[0])));
        re.push(halfplane(Line(Point(x3,y3),Point(x4,y3))));
        re.push(halfplane(Line(Point(x4,y3),Point(x4,y4))));
        re.push(halfplane(Line(Point(x4,y4),Point(x3,y4))));
        re.push(halfplane(Line(Point(x3,y4),Point(x3,y3))));
        polygon ans;
        if(re.halfplaneinsert()) re.getconvex(ans),printf("%.8f\n",ans.getarea());
        else cout<<"0.00000000"<<endl;
        // cout<<ans.getarea()<<endl;
        
    }
    
    
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章