实验三画圆凸多边形填充算法.docx
《实验三画圆凸多边形填充算法.docx》由会员分享,可在线阅读,更多相关《实验三画圆凸多边形填充算法.docx(17页珍藏版)》请在冰豆网上搜索。
实验三画圆凸多边形填充算法
华北水利水电大学计算机图形学实验报告
2017--2018学年第一学期2014级计算机科学与技术专业
指导老师曹源昊班级2014157学号201415717姓名李卫朋
实验三、画圆与凸多边形填充算法
1.实验目的
练习直线和圆的光栅扫描线算法,多边形的扫描转换算法。
2.实验内容和要求
按要求完成以下三个作业。
提交纸质实验报告,同时提交实验报告和源代码的电子版。
(I).利用Bresenham直线扫描算法绘制任意直线段。
输入为起点坐标(x0,y0)和终点坐标(x1,y1)以及线宽w,利用Bresenham算法计算离散的近似像素点,并在OpenGL窗口中绘制该线段。
要求绘制至少五条线段,具有不同的斜率,不同的起点和终点,不同的线宽。
不允许直接调用GL_LINES来实现。
(II).利用中点画圆算法绘制圆。
输入为圆心(xc,yc)和圆的的半径r,利用中点画圆算法计算离散的近似像素点,并在OpenGL窗口中绘制。
要求绘制至少四个圆,构成一个图案,比如奥迪车标或五环。
(III).实现多边形的扫描转换算法。
输入一个凸多边形的顶点序列,利用活性边表计算每条扫描线上位于多边形内部的像素,并填充上一个新颜色,最终达到填充多边形内部的目的。
建议:
为了实现坐标点和像素的一一对应,建议坐标轴的范围和窗口像素宽高一致,比如:
glutInitWindowSize(800,600);//像素宽800,高600
坐标系设定为:
gluOrtho2D(-400,400,-300,300);//坐标轴x方向宽为800,y方向高为600
3.算法描述
使用OpenGL进行画图,采用VS编程环境。
4.源程序代码
(1)
//bresenham直线.cpp:
定义控制台应用程序的入口点。
//
#include"stdio.h"
#include"stdafx.h"
#include"glut.h"
#include"stdlib.h"
#include"math.h"
#include"iostream"
usingnamespacestd;
GLsizeiwinWidth=400,winHeight=300;//屏幕显示宽高.
inta[100],b[100],c[100],d[100],n=-1;
voidinit()
{
glClearColor(1.0,1.0,1.0,1.0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0,200.0,0.0,150.0);
}
voidlineBres(intx0,inty0,intxEnd,intyEnd)
{
intdx=abs(xEnd-x0),dy=abs(yEnd-y0);
intp=2*dy-dx;
inttwoDy=2*dy,twoDyMinusDx=2*(dy-dx);
intx,y;
if(x0>xEnd)
{
x=xEnd;
y=yEnd;
xEnd=x0;
}
else
{
x=x0;
y=y0;
}
glBegin(GL_POINTS);
glVertex2i(x,y);
glEnd();
while(x{
x++;
if(p<0)
p+=twoDy;
else
{
y++;
p+=twoDyMinusDx;
}
glBegin(GL_POINTS);
glVertex2i(x,y);
glEnd();
}
}
voiddisplayFcn()
{
glColor3f(1.0,0.0,0.0);
for(inti=0;i<=n;i++)
{
lineBres(a[i],b[i],c[i],d[i]);
}
glFlush();
}
voidwinReshpeFcn(GLintnewWidth,GLintnewHeight)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,GLdouble(newWidth),0.0,GLdouble(newHeight));
glClear(GL_COLOR_BUFFER_BIT);
winWidth=newWidth;
winHeight=newHeight;
}
int_tmain(intargc,char**argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowPosition(100,100);
glutInitWindowSize(winWidth,winHeight);
glutCreateWindow("bresenham直线");
init();
inth=1;
while(h==1)
{
printf("输入起点和终点的坐标");
n++;
scanf_s("%d%d%d%d",&a[n],&b[n],&c[n],&d[n]);
glutDisplayFunc(displayFcn);
printf("继续输入请按1,退出请按0");
scanf_s("%d",&h);
}
glutReshapeFunc(winReshpeFcn);
glutMainLoop();
return0;
}
(2)//中点画圆法.cpp:
定义控制台应用程序的入口点。
//
#include"stdafx.h"
#include"glut.h"
#include"stdlib.h"
#include"math.h"
#include"iostream"
usingnamespacestd;
constGLdoubletwoPi=6.283185;
GLsizeiwinWidth=400,winHeight=300;//屏幕显示宽高.
classscreenPt{
public:
screenPt(){
x=y=0;
}
GLintx,y;
voidsetCoords(GLintxCoordValue,GLintyCorrdValue){
x=xCoordValue;
y=yCorrdValue;
}
GLintgetx()const{
returnx;
}
GLintgety()const{
returny;
}
voidincrementx(){
x++;
}
voidincrementy(){
y--;
}
};
voidinit()
{
glClearColor(1.0,1.0,1.0,1.0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0,200.0,0.0,150.0);
}
voidsetPixel(GLintxCoord,GLintyCoord){
glBegin(GL_POINTS);
glVertex2i(xCoord,yCoord);
glEnd();
}
voidcircleMidpoint(GLintxc,GLintyc,GLintradius){
screenPtcircPt;
GLintp=1-radius;//中点参数初值
circPt.setCoords(0,radius);
voidcirclePlotPoints(GLint,GLint,screenPt);
circlePlotPoints(xc,yc,circPt);
while(circPt.getx()circPt.incrementx();
if(p<0)
p+=2*circPt.getx()+1;
else{
circPt.incrementy();
p+=2*(circPt.getx()-circPt.gety())+1;
}
circlePlotPoints(xc,yc,circPt);
}
}
voidcirclePlotPoints(GLintxc,GLintyc,screenPtcircPt)
{
setPixel(xc+circPt.getx(),yc+circPt.gety());
setPixel(xc-circPt.getx(),yc+circPt.gety());
setPixel(xc+circPt.getx(),yc-circPt.gety());
setPixel(xc-circPt.getx(),yc-circPt.gety());
setPixel(xc+circPt.gety(),yc+circPt.getx());
setPixel(xc-circPt.gety(),yc+circPt.getx());
setPixel(xc+circPt.gety(),yc-circPt.getx());
setPixel(xc-circPt.gety(),yc-circPt.getx());
}
voidpieChart()
{
screenPtcircCtr,piePt;
GLintradius=winWidth/16;
circCtr.x=winWidth/4;
circCtr.y=winHeight/1.5;
circleMidpoint(circCtr.x,circCtr.y,radius);//调用中点画圆方法
glColor3f(0.0,0.0,1.0);
circleMidpoint(circCtr.x+60,circCtr.y,radius);
glColor3f(0.0,0.0,0.0);
circleMidpoint(circCtr.x+120,circCtr.y,radius);
glColor3f(1.0,1.0,0.0);
circleMidpoint(circCtr.x+30,circCtr.y-30,radius);
glColor3f(0.0,1.0,0.0);
circleMidpoint(circCtr.x+90,circCtr.y-30,radius);
}
voiddisplayFcn()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,0.0,0.0);
pieChart();
glFlush();
}
voidwinReshpeFcn(GLintnewWidth,GLintnewHeight)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,GLdouble(newWidth),0.0,GLdouble(newHeight));
glClear(GL_COLOR_BUFFER_BIT);
winWidth=newWidth;
winHeight=newHeight;
}
int_tmain(intargc,char**argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowPosition(100,100);
glutInitWindowSize(winWidth,winHeight);
glutCreateWindow("PieChart");
init();
glutDisplayFunc(displayFcn);
glutReshapeFunc(winReshpeFcn);
glutMainLoop();
}
(3)
#include"stdafx.h"
constintPOINTNUM=10;//多边形点数.
/******定义结构体用于活性边表AET和新边表NET***********************************/
typedefstructXET
{
floatx;
floatdx,ymax;
XET*next;
}AET,NET;
/******定义点结构体point******************************************************/
structpoint
{
floatx;
floaty;
}
polypoint[POINTNUM]={100,200,122,131,195,131,136,88,159,19,100,62,41,19,64,88,5,131,78,131};//五角星
voidPolyScan()
{
//计算最高点的y坐标(扫描到此结束)
intMaxY=0;
inti;
for(i=0;iif(polypoint[i].y>MaxY)
MaxY=polypoint[i].y;
//初始化AET表
AET*pAET=newAET;
pAET->next=NULL;
//初始化NET表
NET*pNET[1024];
for(i=0;i<=MaxY;i++)
{
pNET[i]=newNET;
pNET[i]->next=NULL;
}
glClear(GL_COLOR_BUFFER_BIT);//赋值的窗体显示.
glColor3f(0.0,0.0,0.0);//设置直线的颜色红色
glBegin(GL_POINTS);
//扫描并建立NET表
for(i=0;i<=MaxY;i++)
{
for(intj=0;jif(polypoint[j].y==i)
{//一个点跟前面的一个点形成一条线段。
跟后面的点也形成线段
if(polypoint[(j-1+POINTNUM)%POINTNUM].y>polypoint[j].y)
{
NET*p=newNET;
p->x=polypoint[j].x;
p->ymax=polypoint[(j-1+POINTNUM)%POINTNUM].y;
p->dx=(polypoint[(j-1+POINTNUM)%POINTNUM].x-polypoint[j].x)/(polypoint[(j-1+POINTNUM)%POINTNUM].y-polypoint[j].y);
p->next=pNET[i]->next;
pNET[i]->next=p;
}
if(polypoint[(j+1+POINTNUM)%POINTNUM].y>polypoint[j].y)
{
NET*p=newNET;
p->x=polypoint[j].x;
p->ymax=polypoint[(j+1+POINTNUM)%POINTNUM].y;
p->dx=(polypoint[(j+1+POINTNUM)%POINTNUM].x-polypoint[j].x)/(polypoint[(j+1+POINTNUM)%POINTNUM].y-polypoint[j].y);
p->next=pNET[i]->next;
pNET[i]->next=p;
}
}
}
//建立并更新活性边表AET
for(i=0;i<=MaxY;i++)
{
//计算新的交点x,更新AET
NET*p=pAET->next;
while(p)
{
p->x=p->x+p->dx;
p=p->next;
}
//更新后新AET先排序
//断表排序,不再开辟空间
AET*tq=pAET;
p=pAET->next;
tq->next=NULL;
while(p)
{
while(tq->next&&p->x>=tq->next->x)
tq=tq->next;
NET*s=p->next;
p->next=tq->next;
tq->next=p;
p=s;
tq=pAET;
}
//(改进算法)先从AET表中删除ymax==i的结点
AET*q=pAET;
p=q->next;
while(p)
{
if(p->ymax==i)
{
q->next=p->next;
deletep;
p=q->next;
}
else
{
q=q->next;
p=q->next;
}
}
//将NET中的新点增加AET,并用插入法按X值递增排序
p=pNET[i]->next;
q=pAET;
while(p)
{
while(q->next&&p->x>=q->next->x)
q=q->next;
NET*s=p->next;
p->next=q->next;
q->next=p;
p=s;
q=pAET;
}
//配对填充颜色
p=pAET->next;
while(p&&p->next)
{
for(floatj=p->x;j<=p->next->x;j++)
glVertex2i(static_cast(j),i);
p=p->next->next;//考虑端点情况
}
}
glEnd();
glFlush();
}
voidinit(void)
{glClearColor(1.0,1.0,1.0,1.0);
//窗体的背景颜色设置为白色
glMatrixMode(GL_PROJECTION);
//gluOrtho2D(0.0,600.0,0.0,450.0);
gluOrtho2D(-400,400,-300,300);
}
voidmain(intargc,char*argv)
{
glutInit(&argc,&argv);//I初始化GLUT.
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);//设置显示模式:
单个缓存和使用RGB模型
glutInitWindowPosition(50,100);//设置窗体的顶部和左边位置
glutInitWindowSize(800,600);//设置窗体的高度和宽度
glutCreateWindow("五角星");//创建显示窗体
init();
glutDisplayFunc(PolyScan);
glutMainLoop();
}
5.实验结果
(1)
(2)
(3)