【计算几何】半平面交

半平面交算法

对于平面上的所有有向边(角度范围​)

  • 将向量按照角度排序(atan2(y,x))
  • 按顺序扫描所有向量,用双端队列维护双平面交轮廓
    • 只要队尾的两个线和队头的两个线的交点在当前直线的右侧(因为保存左侧),将队尾或者队头删除
  • 用直线的参数方程存储直线
  • 时间复杂度
int cnt;
struct Line{
    PDD st,ed;
}line[N];
int q[N];
PDD pg[N],ans[N];

int sign(double x){
    if (fabs(x) < eps)    return 0;
    if (x < 0)    return -1;
    return 1;
}

int dcmp(double a,double b){
    if (fabs(a - b) < eps)    return 0;
    if (a < b)    return -1;
    return 1;
}

double get_angle(const Line& a){
    return atan2(a.ed.y - a.st.y,a.ed.x - a.st.x);
}


PDD operator - (PDD a,PDD b){
    return {a.x - b.x,a.y - b.y};
}

double cross(PDD a,PDD b){
    return a.x * b.y - a.y * b.x;
}

double area(PDD a,PDD b,PDD c){
    return cross(b - a,c - a);
}

bool cmp(const Line& a,const Line& b){
    double A = get_angle(a), B = get_angle(b);
    if (!dcmp(A,B))    return sign(area(a.st,a.ed,b.ed)) < 0;
    return A < B;
}

PDD get_line_intersection(PDD p,PDD v,PDD q,PDD w){
    auto u = p - q;
    double t = cross(w,u) / cross(v,w);
    return {p.x + v.x * t,p.y + v.y * t};
}

PDD get_line_intersection(Line a,Line b){
    return get_line_intersection(a.st,a.ed - a.st,b.st,b.ed - b.st);
}

bool on_right(Line& a,Line& b,Line& c){
    auto o = get_line_intersection(b,c);
    return sign(area(a.st,a.ed,o)) <= 0;
}

double half_plane_intersection(){
    sort(line,line + cnt,cmp);
    int head = 0,tail = -1;
    for (int i = 0;i < cnt;++i){
        if (i && !dcmp(get_angle(line[i]),get_angle(line[i-1])))    continue;
        while (head + 1 <= tail && on_right(line[i],line[q[tail - 1]],line[q[tail]]))    tail--;
        while (head + 1 <= tail && on_right(line[i],line[q[head]],line[q[head + 1]]))    head++;
        q[++tail] = i;
    }
    while (head + 1 <= tail && on_right(line[q[head]],line[q[tail - 1]],line[q[tail]])) tail--;
    while (head + 1 <= tail && on_right(line[q[tail]],line[q[head]],line[q[head + 1]])) head++;
}
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务