扫描线填充多边形

#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/opencv.hpp>
#include<bits/stdc++.h>
#define N 1000010
#define For(i,a,b) for(int i=a;i<=b;++i)

using namespace cv;
using namespace std;

int n,cnt,flag;
int x[10],y[10];
vector<Point>a;

Mat src;
Mat dst;
Point pre_pt ,fir_pt;
Point cur_pt ;
double ymin=1000000.0,ymax=-1.0,k,eps=1e-7;

struct node{
    double x;
    double dx;
    int ymax;
    node *next;
}*NET[N],*AET;

void push(double x,double dx,int ymax,int ymin){
    node *p;
    p=new node();
    p->x=x;
    p->dx=dx;
    p->ymax=ymax;
    if(NET[ymin]==0) NET[ymin]=p;
    else{
        p->next=NET[ymin]->next;
        NET[ymin]->next=p;
    }
}

void polygon(){
    AET=new node();
    For(i,0,a.size()-1){
        ymax=max(ymax,(double)a[i].y);
        ymin=min(ymin,(double)a[i].y);
    }
    For(i,0,a.size()-1){
        For(j,-1,2){
            x[j+1] = a[(i + j + a.size()) % a.size()].x;
            y[j+1] = a[(i + j + a.size()) % a.size()].y;
        }
        
        if(y[1] == y[2]) continue;
        if((y[2]>y[1] && y[1]>y[0]) || (y[1]>y[2] && y[2]>y[3])){
            push((double)(y[1]>y[2]?x[2]:x[1])+(double)(x[1]-x[2])/(double)(y[1]-y[2]),(double)(x[1]-x[2])/(double)(y[1]-y[2]),max(y[1],y[2]),min(y[1],y[2])+1);

        }
        else
            push((double)(y[1]>y[2]?x[2]:x[1]),(double)(x[1]-x[2])/(double)(y[1]-y[2]),max(y[1],y[2]),min(y[1],y[2]));
    }
    For(i,ymin,ymax){
        node *p;
        for(node *j=NET[i]; j; j=j->next){
            p=AET;
            node *temp=new node();
            while(p->next){
                
                if(j->x > p->next->x ||(j->x == p->next->x && j->dx - p->next->dx > eps)){
                    p=p->next;
                    continue;
                }
                break;
            }
            
            temp->x=j->x;
            temp->dx=j->dx;
            temp->ymax=j->ymax;
            temp->next=p->next;
            p->next=temp;
        }

        for(node *j=AET->next;j && j->next;j=j->next->next){
            For(k,j->x,j->next->x){
                circle(src, Point(k,i), 1.5, Scalar(0, 255, 0), FILLED, 0);
            }
        }

        p=AET;
        while(p->next){
            if(p->next->ymax == i){
                p->next=p->next->next;
            }
            else p = p->next;
        }

        p=AET;
        while(p->next){
            p->next->x += p->next->dx;
            p = p->next;
        }
    }
    imshow("扫描线填充多边形", src);
}

void on_mouse(int event, int x, int y, int flags, void* ustc){
    if (event == EVENT_LBUTTONDOWN){
        cnt++;
        a.push_back(Point(x,y));
        if(cnt==1){
            pre_pt=Point(x,y);
            fir_pt=pre_pt;
            imshow("扫描线填充多边形", src);
        }
        if(cnt>1&&cnt<=n){
            cur_pt=Point(x,y);
            line(src, pre_pt, cur_pt, Scalar(0, 255,0), 2, 4, 0);
            pre_pt=cur_pt;
            imshow("扫描线填充多边形", src);
        }
        if(cnt==n){
            a.push_back(fir_pt);
            line(src, cur_pt, fir_pt, Scalar(0, 255,0), 2, 4, 0);
            imshow("扫描线填充多边形", src);
            polygon();
            return;
        }

    }
}
 
int main(){
    cout<<"请输入多边形的顶点数"<<endl;
    cin>>n;
    if(n<3){
        cout<<"至少需要三个顶点哦😊"<<endl;
        return 0;
    }
    namedWindow("扫描线填充多边形", WINDOW_AUTOSIZE);
    src=Mat(1000, 1000, CV_8UC3, Scalar(0));
    src.copyTo(dst);
    setMouseCallback("扫描线填充多边形", on_mouse, 0);
    imshow("扫描线填充多边形", src);
    waitKey(0);
    return 0;
}

 

posted @ 2020-09-06 10:59  WeiAR  阅读(172)  评论(0编辑  收藏  举报