#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/opencv.hpp>
#include<bits/stdc++.h>
#define For(i,a,b) for(int i=a;i<=b;++i)
using namespace cv;
using namespace std;
int n,cnt;
vector<Point>a,b;
Mat src;
Mat dst;
Point pre_pt ,fir_pt;
Point cur_pt ;
double xmin,xmax,ymin,ymax,k;
int flag;
void check(int num){
pre_pt=Point(-1,-1);
if(num==4){//上侧
for(auto i:a){
if(pre_pt.x==-1){
pre_pt=i;
}
else{
cur_pt=i;
if(pre_pt.y>=ymin&&cur_pt.y<ymin){
k=(double)(cur_pt.y-ymin)*(double)(cur_pt.x-pre_pt.x)/(double)(cur_pt.y-pre_pt.y);
b.push_back(Point(cur_pt.x-k,ymin));
}
if(pre_pt.y>=ymin&&cur_pt.y>=ymin){
b.push_back(cur_pt);
}
if(pre_pt.y<ymin&&cur_pt.y>=ymin){
k=(double)(cur_pt.y-ymin)*(double)(cur_pt.x-pre_pt.x)/(double)(cur_pt.y-pre_pt.y);
b.push_back(Point(cur_pt.x-k,ymin));
b.push_back(cur_pt);
}
pre_pt=i;
}
}
}
if(num==3){//右侧
for(auto i:a){
if(pre_pt.x==-1){
pre_pt=i;
}
else{
cur_pt=i;
if(pre_pt.x<xmax&&cur_pt.x>=xmax){
k=(double)(cur_pt.x-xmax)*(double)(cur_pt.y-pre_pt.y)/(double)(cur_pt.x-pre_pt.x);
b.push_back(Point(xmax,cur_pt.y-k));
}
if(pre_pt.x<=xmax&&cur_pt.x<=xmax){
b.push_back(cur_pt);
}
if(pre_pt.x>=xmax&&cur_pt.x<xmax){
k=(double)(cur_pt.x-xmax)*(double)(cur_pt.y-pre_pt.y)/(double)(cur_pt.x-pre_pt.x);
b.push_back(Point(xmax,cur_pt.y-k));
b.push_back(cur_pt);
}
pre_pt=i;
}
}
}
if(num==2){//下侧
for(auto i:a){
if(pre_pt.x==-1){
pre_pt=i;
}
else{
cur_pt=i;
if(pre_pt.y<ymax&&cur_pt.y>=ymax){
k=(double)(cur_pt.y-ymax)*(double)(cur_pt.x-pre_pt.x)/(double)(cur_pt.y-pre_pt.y);
b.push_back(Point(cur_pt.x-k,ymax));
}
if(pre_pt.y<=ymax&&cur_pt.y<=ymax){
b.push_back(cur_pt);
}
if(pre_pt.y>=ymax&&cur_pt.y<ymax){
k=(double)(cur_pt.y-ymax)*(double)(cur_pt.x-pre_pt.x)/(double)(cur_pt.y-pre_pt.y);
b.push_back(Point(cur_pt.x-k,ymax));
b.push_back(cur_pt);
}
pre_pt=i;
}
}
}
if(num==1){//左侧
for(auto i:a){
if(pre_pt.x==-1){
pre_pt=i;
}
else{
cur_pt=i;
if(pre_pt.x<xmin&&cur_pt.x>=xmin){
k=(double)(cur_pt.x-xmin)*(double)(cur_pt.y-pre_pt.y)/(double)(cur_pt.x-pre_pt.x);
b.push_back(Point(xmin,cur_pt.y-k));
b.push_back(cur_pt);
}
if(pre_pt.x>=xmin&&cur_pt.x>=xmin){
b.push_back(cur_pt);
}
if(pre_pt.x>=xmin&&cur_pt.x<xmin){
k=(double)(cur_pt.x-xmin)*(double)(cur_pt.y-pre_pt.y)/(double)(cur_pt.x-pre_pt.x);
b.push_back(Point(xmin,cur_pt.y-k));
}
pre_pt=i;
}
}
}
}
void Sutherland_Hodgman(){
For(i,1,4){
check(i);
a.clear();
for(auto j:b) a.push_back(j);
a.push_back(b[0]);
b.clear();
}
pre_pt=Point(-1,-1);
//dst.copyTo(src);
for(auto i:a){
if(pre_pt.x==-1){
pre_pt=i;
}
else{
cur_pt=i;
line(src, pre_pt, cur_pt, Scalar(255, 0, 0), 4, 8, 0);
imshow("Sutherland-Hodgman", src);
pre_pt=i;
}
}
}
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("Sutherland-Hodgman", 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("Sutherland-Hodgman", src);
}
if(cnt==n){
a.push_back(fir_pt);
line(src, cur_pt, fir_pt, Scalar(0, 255,0), 2, 4, 0);
imshow("Sutherland-Hodgman", src);
Sutherland_Hodgman();
return;
}
}
}
int main(){
cout<<"请输入多边形的顶点数"<<endl;
cin>>n;
if(n<3){
cout<<"至少需要三个顶点哦😊"<<endl;
return 0;
}
namedWindow("Sutherland-Hodgman", WINDOW_AUTOSIZE);
src=Mat(1000, 1000, CV_8UC3, Scalar(0));
xmax=ymax=600;
xmin=ymin=200;
rectangle(src,Rect(200,200,400,400),Scalar(255,255,255),2,1,0);
src.copyTo(dst);
setMouseCallback("Sutherland-Hodgman", on_mouse, 0);
imshow("Sutherland-Hodgman", src);
waitKey(0);
return 0;
}