Y-X扫描线算法:
今日白嫖1/∞ 🤣
直接上源码
后序在补上详解
#define NDEBUG
#ifndef GLUT_DISABLE_ATEXIT_HACK
#define GLUT_DISABLE_ATEXIT_HACK
#endif
#include <windows.h>
#include <gl/glut.h>
#include <cmath>
#include <vector>
#include <algorithm>
#include <list>
using namespace std;
//设置像素点
void setPixel(int xCoord, int yCoord){
glBegin (GL_POINTS);{
glVertex2i (xCoord, yCoord);
}
glEnd();
}
//设置窗口大小
const int windowHeight=400;
const int windowWidge=400;
//点类
struct Point{
int x, y;
Point():x(0), y(0){}
Point(int nx, int ny):x(nx), y(ny){}
};
//边类
struct Edge{
float x;
float dx;
int yMax;
Edge():x(0),dx(0),yMax(0){}
Edge(float nx, float ndx, int nyMax):x(nx),dx(ndx),yMax(nyMax){}
};
//sort的cmp函数
bool cmp_x(Point p1, Point p2){ //x升序排列
return p1.x<p2.x;
}
bool cmp_y(Point p1, Point p2){
return p1.y<p2.y;
}
//Y-X扫描行
void boundaryFill(vector <Point> pointList){
int pointNum=pointList.size ();
//计算maxY & minY
vector<Point> pointListCopy(pointList);
sort(pointListCopy.begin (), pointListCopy.end (), cmp_y);
int yMin=pointListCopy.at (0).y;
int yMax=pointListCopy.at (pointNum-1).y;
//初始化边表ET & 活动边表AET
list<Edge> ET[windowHeight];
list<Edge> AET;
//加入头结点, 以简化计算
AET.push_back (Edge());
//建立边表ET
for(int i=0;i<pointNum;++i){
int x0=pointList.at (i).x;
int y0=pointList.at (i).y;
int x1=pointList.at ((i+1)%pointNum).x;
int y1=pointList.at ((i+1)%pointNum).y;
//舍弃与扫描线水平的线
if(y0==y1){
continue;
}
//计算ET边的各个参数:
int yMinNow=min(y0,y1);
int yMaxNow=max(y0,y1);
float x=y0<y1?x0:x1;
float dx=(x0-x1)*1.0/(y0-y1);
ET[yMinNow].push_back (Edge(x,dx,yMaxNow));
}
//建立活动边表AET
for(int i=yMin;i<yMax;++i){
//按递增顺序建立AET
for(auto j=ET[i].begin ();j!=ET[i].end ();){
auto pAET=AET.begin ();
auto end=AET.end ();
for(;pAET!=end;++pAET){
if(pAET->x >j->x){
break;
}
if(j->x == pAET->x && j->dx < pAET->dx){
break;
}
}
AET.insert (pAET,*j);
j=ET[i].erase (j);
}
//删除当前AET中y=ymax的边
//先删除再填色, 否则在交点处会出现奇数点出错导致没填色
for(auto temp=AET.begin ();temp!=AET.end ();){
if(temp->yMax==i){
temp=AET.erase (temp);
}else{
temp++;
}
}
//填色
//一次选取两个点组成填色区间
auto pAET=AET.begin ();
pAET++; //跳过头结点
auto pAET_next=pAET;
pAET_next++;
int count=AET.size ()-1;
while(count>=2){
for(int x=pAET->x;x<pAET_next->x;++x){
setPixel (x,i);
}
pAET++;
pAET++;
pAET_next=pAET;
pAET_next++;
count-=2;
}
//更新AET中x的值
for(auto &temp:AET){
temp.x+=temp.dx;
}
}
return ;
}
//绘制程序
void display(){
//AMD YES !!!
vector <Point> pointList1;
pointList1.push_back (Point(100,100));
pointList1.push_back (Point(200,100));
pointList1.push_back (Point(270,170));
pointList1.push_back (Point(170,170));
pointList1.push_back (Point(170,270));
pointList1.push_back (Point(100,200));
vector <Point> pointList2;
pointList2.push_back (Point(170,285));
pointList2.push_back (Point(280,285));
pointList2.push_back (Point(280,170));
pointList2.push_back (Point(340,100));
pointList2.push_back (Point(340,340));
pointList2.push_back (Point(100,340));
glClear(GL_COLOR_BUFFER_BIT);//将屏幕设置为白色
glColor3f(1.0,0.0,0.0);//设置当前颜色状态为绿色
boundaryFill(pointList1);
boundaryFill (pointList2);
// glFlush();//发送缓冲区
glutSwapBuffers ();
return ;
}
//初始化绘制
void init(){
glClearColor(1.0,1.0,1.0,0.0);//清除颜色设置
glMatrixMode(GL_PROJECTION);//设置投影方式
gluOrtho2D (0.0,windowWidge*1.0,0.0,windowHeight*1.0);
return ;
}
int main(int argc, char** argv){
glutInit(&argc, argv);//初始化glut
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);//设置显示模式为单缓冲,RGB模式
glutInitWindowPosition(0,0);//设置窗口位置
glutInitWindowSize(windowWidge,windowHeight);//设置窗口大小
glutCreateWindow("GLUT_Project_1");//设置窗口标题
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
运行效果:
绘制一个看起来还挺像的AMD Logo