#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;
}