深 圳 大 学 实 验 报 告
实验课程名称: 数字电路与逻辑设计
实验项目名称: 全加器
学院: 计算机与软件
专业: 软件工程
报告人: 学号: 2011150377 班级: 7
指导教师: 俞航
实验时间: 20##-11-09
实验报告提交时间: 20##-11-19
教务处制
实验报告包含内容
注:1、报告内的项目或内容设置,可根据实际情况加以调整和补充。
2、教师批改学生实验报告时间应在学生提交实验报告时间后10日内。
深 圳 大 学 实 验 报 告
实验课程名称: 计算机图形学
实验项目名称:
学院: 计算机与软件 专业: 计算机科学与技术
报告人: 班级:
组员:
指导教师:
实验时间:
实验报告提交时间:
教务处制
一.实验目的:
通过本实验 ,了解计算机图形学的有关原理、算法及系统,掌握基本图形显示程序设计方法,及二维和三维图形变换程序设计方法。同时也可以提高个人的编程能力。
二.实验要求:
? 基本图元绘制算法:DDA绘直线、Bresenham绘直线、Bresenham
绘圆
? 多边形扫描转换算法和区域填充算法实现(扫描线算法为必做,
基于求余运算的边缘填充和边标志算法为任选;基于种子的区域填充采用4连通区域的递归种子填充算法,或扫描线种子填充算法,要求种子点(x,y)可交互输入)。
? 线段裁剪和多边形裁剪算法的动画演示实现。(两种线段裁剪算法
和H-S多边形逐边裁剪算法)多边形裁剪算法的动画演示要求先画出一个封闭的多边形,再画矩形的裁剪窗口,然后选择裁剪按钮(或命令),按下“上边裁剪”按钮(或执行“上边裁剪”命令),多边形相对裁剪窗口的上边进行裁剪,显示上边裁剪后的多边形,依此进行其它各边裁剪。
? 用动画实现二维图形变换的各种算法,实现对指定形体的平移、
旋转和缩放。(包括类似自行车行走和绕固定点旋转的自旋转物体动画。)
? 简单三维图形系统:凸多面体的建模、透视投影,隐藏面的消除
及基本图形变换(平移、旋转、缩放)。
? 交互式Bezier曲线的输入绘制程序实现
? 选做内容:
实用算法动态图形演示:任意选择程序设计、数据结构和算法设计中的经典问题,如马跳回溯、冒泡排序、八皇后、背包问题、动态规划等等,动画策略自定
光照效应:三维图形的面着色;
分形几何:Koch雪花,L系统植物及其他有特色的图形学相关效果等。
二、开发环境:
MicroSoft VC++6.0
三、 程序设计说明及源代码::
1. 主要数据及函数
OnMxq() //消隐
On3py() //三维平移
On3sf() // 三维缩放
On3xz() //三维旋转
CohenSutherlandLineClip(float x0, float y0,float x1,float y1,CRect *rect)// C—S线段剪裁 LiangBarskyLineClip(float x0,float y0,float x1,float y1,CRect *rect) //梁友栋线段剪裁 ClipT(float q,float d,float * t0,float *t1) //显示剪裁后线段
snow (DCPoint t1, DCPoint t2) //雪花曲线
bezier_DeC ( DCPoint a, DCPoint b, DCPoint c, DCPoint d )// 贝塞尔曲线 polyhedron (int vpoint)// 三维图形建模
CreateBucket() // 多边形扫描转换建桶
EdgeOrder()// 排序
ET() // 建立活性表
Horse_Visit() //马跳
Horse_Move(int a, int b) //马移动一步
CircleBresenham(CPoint center, int r) //Bresenham画圆
OnBike() //自行车 其中Matrix为矩阵类,详细请参考Matrix类的声明
OnClock() //时钟 其中Matrix为矩阵类,详细请参考Matrix类的声明
OnSf() //缩放 其中Matrix为矩阵类,详细请参考Matrix类的声明
OnXz() //旋转 其中Matrix为矩阵类,详细请参考Matrix类的声明
OnZh() //组合变换 其中Matrix为矩阵类,详细请参考Matrix类的声明
:OnSuHo()
int COLOR; //颜色
bool up; //鼠弹起
bool sym; //覆盖标记
int flag; //操作标记
int xx1,xx2,yy1,yy2,xxx2,yyy2; //记录鼠标坐标
int save[10000][3],count;
DCPoint a, b, c, d;
int cc;
int vpoint;
int count1;
int width;
int Step;
int Qipan[8][8];
int nR;
int m_y;
int m_x;
int i_y[64];
int i_x[64];
2.部分算法源代码和截图:
(1)直线:
DDA算法:
ddaline (int x0,int y0,int x1,int y1,int color){
double dx, dy, x, y, m;
dx = x1 - x0;
dy = y1 - y0;
if (sym)
count=0;
if (dx == 0){
for (int i = min(y0,y1), j = abs(y0-y1); j >=0; j-- ) draw_point (x0, i+j, color);
}
else{
if (dx < 0){
int xBuf, yBuf;
xBuf = x0; x0 = x1; x1 = xBuf;
yBuf = y0; y0 = y1; y1 = yBuf;
dx = -dx; dy = -dy;
}
if (dx >= (dy>0?dy:-dy)){
m = dy / dx;
y = y0;
for (x = x0; x <= x1; x++){
draw_point((int)x, (int)(y+0.5), color ); y += m;
}
}
else{
m = dx / dy;
if (m < 0)
m = -m;
x = x0;
if (dy > 0){
for (y = y0; y <= y1; y++){
draw_point( (int)(x+0.5), (int)y, color); x += m;
}
}
else{
for (y = y0; y >= y1; y--){
draw_point( (int)(x+0.5), (int)y, color); x += m;
}
} } } }
Bresenham算法:
bresenhamline (int x1,int y1,int x2,int y2,int color){ int xa=x1,ya=y1,xb=x2,yb=y2,c=color; int i,s1,s2,interchange;
float x,y,deltax,deltay,f,temp;
x=x1;
y=y1;
deltax=abs(x2-x1);
deltay=abs(y2-y1);
if(x2-x1>=0) s1=1; else s1=-1;
if(y2-y1>=0) s2=1; else s2=-1;
if(deltay>deltax){
temp=deltax;
deltax=deltay;
deltay=temp;
interchange=1;
}
else interchange=0;
f=2*deltay-deltax;
draw_point(x,y,c);
while(x!=x2){
if(f>=0){
if(interchange==1) x+=s1; else y+=s2;
draw_point(x,y,c);
f=f-2*deltax;
}
else{
if(interchange==1) y+=s2; else x+=s1;
draw_point(x,y,c);
f=f+2*deltay;
}
}
}
(2)圆:
Bresenham画圆:
CircleBresenham(CPoint center, int r)
{
CClientDC dc(this);
int x,y,d;
x=0;
y=r;
d=3-2*r;
while(x<y){
dc.SetPixel(center.x+x,center.y+y,RGB(0,0,0)); dc.SetPixel(center.x-x,center.y+y,RGB(0,0,0)); dc.SetPixel(center.x+x,center.y-y,RGB(0,0,0)); dc.SetPixel(center.x-x,center.y-y,RGB(0,0,0)); dc.SetPixel(center.x+y,center.y+x,RGB(0,0,0)); dc.SetPixel(center.x-y,center.y+x,RGB(0,0,0)); dc.SetPixel(center.x+y,center.y-x,RGB(0,0,0)); dc.SetPixel(center.x-y,center.y-x,RGB(0,0,0)); if(d<0)
d=d+4*x+6;
else{
d=d+4*(x-y)+10;
y=y-1;
}
} x=x+1; } if (x==y) { dc.SetPixel(center.x+x,center.y+y,RGB(0,0,0)); dc.SetPixel(center.x-x,center.y+y,RGB(0,0,0)); dc.SetPixel(center.x+x,center.y-y,RGB(0,0,0)); dc.SetPixel(center.x-x,center.y-y,RGB(0,0,0)); dc.SetPixel(center.x+y,center.y+x,RGB(0,0,0)); dc.SetPixel(center.x-y,center.y+x,RGB(0,0,0)); dc.SetPixel(center.x+y,center.y-x,RGB(0,0,0)); dc.SetPixel(center.x-y,center.y-x,RGB(0,0,0)); }
(3)填充:
扫描线转换算法:
edge_scan(){
HeadE=NULL;
for(CurrentB=HeadB; CurrentB!=NULL;CurrentB=CurrentB->next) {
for (CurrentE=CurrentB->p;CurrentE!=NULL;CurrentE=CurrentE->next) {
上开
AET *TempEdge= new AET; TempEdge->x=CurrentE->x; TempEdge->ymax=CurrentE->ymax; TempEdge->dx=CurrentE->dx; TempEdge->next=NULL; AddEdge(TempEdge); //将该边插入活性边表中 } EdgeOrder(); //活性边表按照x值排序 T1=HeadE; //根据ymax抛弃扫描完的边节点 if (T1==NULL) { return; } while(CurrentB->ScanLine>=T1->ymax) //放弃该节点,AEL表指针后移,下闭{ T1=T1->next; HeadE=T1; if (HeadE==NULL) { return; } } if (T1->next!=NULL) { T2=T1; T1=T2->next; } while (T1!=NULL) { if (CurrentB->ScanLine>=T1->ymax) //跳过一个节点 { T2->next=T1->next; T1->next=NULL; T1=T2->next; } else { T2=T1; T1=T2->next;
} } BOOL In= false; double xb,xe; //扫描线的起点与终点 for (T1=HeadE;T1!=NULL;T1=T1->next) //填充扫描线和多边形相交的区间 {
if (In==false)
{
xb=T1->x;
In=true;
}
else
{
xe=T1->x-1; //左闭右开
CClientDC dc(this);
for (double x=xb;x<=xe; x++)
{
dc.SetPixel(INT(x),CurrentB->ScanLine,RGB(255,0,0));
}
Sleep(1); //延时 1ms, 效果
In=false;
}
}
for (T1=HeadE;T1!=NULL;T1=T1->next)
{
T1->x=T1->x+T1->dx;
}
}
delete HeadB;
delete CurrentB;
delete CurrentE;
delete HeadE;
} //填充语句
(4)二维裁剪:
多边形裁剪:
CohenSutherlandLineClip(float x0, float y0,float x1,float y1,CRect *rect) //P0(x0,y0),P1(x1,y1)为待裁剪线段
//rect 为裁剪窗口
{
//用于计算端点的编码
boolean accept,done;
OutCode outCode0,outCode1;
OutCode * outCodeOut;
float x,y;
accept = FALSE;
done = FALSE;
CompOutCode(x0,y0,rect,&outCode0);
CompOutCode(x1,y1,rect,&outCode1);
do{
if (outCode0.all == 0 && outCode1.all == 0) //完全可见 { accept = TRUE;
done = TRUE;
}
else if (outCode0.all&outCode1.all!=0) //显然不可见
done = TRUE;
else //进行求交测试
{
if(outCode0.all!=0) //判断哪一点位于窗口之外 outCodeOut=&outCode0;
else
outCodeOut=&outCode1;
if(outCodeOut->left) //线段与窗口的左边求交
{
y=y0+(y1-y0)*(rect->left-x0)/(x1-x0);
x=(float)rect->left;
}
else if (outCodeOut->bottom) //线段与窗口的上边求交 {
x=x0+(x1-x0)*(rect->bottom-y0)/(y1-y0);
y=(float)rect->bottom;
}
else if(outCodeOut->right) //线段窗口的右边求交 {
y=y0+(y1-y0)*(rect->right-x0)/(x1-x0);
x=(float)rect->right;
}
else if(outCodeOut->top) //线段与窗口的下边求交 {
x=x0+(x1-x0)*(rect->top-x0)/(y1-y0);
y=(float)rect->top;
}
if(outCodeOut->all==outCode0.all)
{
x0=x;
y0=y;
CompOutCode(x0,y0,rect,&outCode0);
}
else
{
x1=x;
y1=y;
CompOutCode(x1,y1,rect,&outCode1);
}
}
}while(! done);
if (accept){ //显示线段的可见部分
ddaline(100,110,400,500,COLOR);
::Sleep(500);
ddaline (100,110,(int)x0,(int)y0,RGB(250,250,250));
::Sleep(500);
ddaline (100,110,(int)x0,(int)y0,COLOR);
::Sleep(500);
ddaline (100,110,(int)x0,(int)y0,RGB(250,250,250));
::Sleep(500);
ddaline (100,110,(int)x0,(int)y0,COLOR);
}
}
::Sleep(500); ddaline (100,110,(int)x0,(int)y0,RGB(250,250,250)); ::Sleep(500); ddaline (400,500,(int)x1,(int)y1,RGB(250,250,250)); ::Sleep(500); ddaline (400,500,(int)x1,(int)y1,COLOR); ::Sleep(500); ddaline (400,500,(int)x1,(int)y1,RGB(250,250,250)); ::Sleep(500); ddaline (400,500,(int)x1,(int)y1,COLOR); ::Sleep(500); ddaline (400,500,(int)x1,(int)y1,RGB(250,250,250)); bresenhamline (100,110,400,500,RGB(250,250,250)); ddaline((int)x0,(int)y0,(int)x1,(int)y1,COLOR); //end of CohenSutherlandLineClip()
(5)二维基本变换:
平移:
OnPy() //平移 其中Matrix为矩阵类,详细请参考Matrix类的声明 {
// TODO: Add your command handler code here
flag=11;
OnClear();
Matrix a(200,180),b(5,5,true),c(5,-5,true);
int i,r1=100,r2=70,white=RGB(255,255,255);
midellispse(a.getx(),a.gety(),r1,r2,COLOR);
}
for(i=0;i<50;i++){ ::Sleep(100-i*2); midellispse(a.getx(),a.gety(),r1,r2,white); a=b*a; midellispse(a.getx(),a.gety(),r1,r2,COLOR); } for(i=0;i<50;i++){ ::Sleep(i*0.5); //midellispse(a.getx(),a.gety(),r1,r2,white); a=c*a; midellispse(a.getx(),a.gety(),r1,r2,COLOR); }
(6)曲线:
Bezier:
bezier_DeC ( DCPoint a, DCPoint b, DCPoint c, DCPoint d ) {
DCPoint t1, t2, t3, t4, t5;
t1.x = (a.x + b.x )/2;
t1.y = (a.y + b.y )/2;
t2.x = (c.x + b.x )/2;
t2.y = (c.y + b.y )/2;
t3.x = (c.x + d.x )/2;
t3.y = (c.y + d.y )/2;
t4.x = (a.x + b.x + c.x + b.x )/4;
t4.y = (a.y + b.y + c.y + b.y )/4;
t5.x = (c.x + d.x + c.x + b.x )/4;
t5.y = (c.y + d.y + c.y + b.y )/4;
t2.x = (a.x + b.x + c.x + b.x + c.x + d.x + c.x + b.x)/8; t2.y = (a.y + b.y + c.y + b.y + c.y + d.y + c.y + b.y)/8; if ((pow ((a.x - t2.x),2) + pow ((a.y-t2.y),2))>25){ bezier_DeC (a, t1, t4, t2 );
}
else {
::Sleep(5);
ddaline (a.x, a.y, t1.x, t1.y, COLOR);
ddaline (t1.x, t1.y, t4.x, t4.y, COLOR);
ddaline (t4.x, t4.y, t2.x, t2.y, COLOR);
}
if ((pow ((d.x - t2.x),2) + pow ((d.y-t2.y),2))>25){
bezier_DeC (t2, t5, t3, d);
}
else {
::Sleep(5);
ddaline (t2.x, t2.y, t5.x, t5.y, COLOR);
ddaline (t5.x, t5.y, t3.x, t3.y, COLOR);
ddaline (d.x, d.y, t3.x, t3.y, COLOR);
}
}
BOOL CMyView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) {
// TODO: Add your message handler code here and/or call default if (flag==17){
vpoint += zDelta/6;
if ( vpoint < 260)
vpoint = 260;
if (vpoint > 2200)
vpoint = 2200;
polyhedron (vpoint);
}
return CView::OnMouseWheel(nFlags, zDelta, pt);
}
(7)马跳回溯:
HorseTravel(Direction direct)
{
Direction last;
Step step[] = {{0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7}};
for (int loop=0; loop<8; ++loop)
{
if (Check(direct, loop))
{
last = direct + move[loop];
AccumulateDirect(last, loop, step);
}
else
step[loop].direct = 9;
}
std::stable_sort(step, (step+8), isLess);
for (loop=0; loop<8; ++loop)
{
if (step[loop].direct!=9)
{
last = direct + move[step[loop].loop];
board[last.x][last.y] = ++stage;
if (stage==8*8)
{
Direction temp;
for (int loop=0; loop<8; ++loop)
{
if (last.x+move[loop].x>=0&&last.x+move[loop].x<8
&&last.y+move[loop].y>=0&&last.y+move[loop].y<8) {
temp = last + move[loop];
if (board[temp.x][temp.y]==1)
{
state = true;
return;
}
}
}
}
else HorseTravel(last);
}
else
continue;
} }
if (state) { return; } board[last.x][last.y] = 0; --stage;
由于程序过多,上面只列出了部分算法的核心代码和截图。
2.部分算法说明:
Dda算法:
算法源于书本上代码,从鼠标点击屏幕的坐标得到直线段,利用浮点数取整得到y值,其中用到浮点数的乘法,加法和取整运算。这个算法用c来实现比较简单易懂,可是有浮点数取整运算,不利于硬件实现。
填充算法:
这个是区域填充的扫描线算法,四连通和扫描线种子填充法是可以填充任意形状的图形(曲线,多边形等)的。在使用时只需先画好需要填充的边界然后选择种子填充并用鼠标左键点击确定种子点即可填充。
扫描转换:
扫描线转换算法是固定填充的,对指定区域进行填充这个程序的程序体很复杂,涉及到很多的子函数调用,分工合作时相当困难,将其合为一个程序不利于寻找错误,也降低了程序可读性,故做此算法时我们都是集中在一起讨论,完成这个程序用时相当长。
裁剪算法:
源于书本的cohen—sutherland算法,要注意的一点就是书本上描述的坐标系跟电脑上实现坐标系不同,要修改一下在生成编码的时候因此而产生的符号问题。
二维动画:
这个作业里,实现了一个单车和时钟的动画。作业的原理使用二维坐标变换,二维旋转的原理。 作业在显示时候有点闪烁,轮子滚动过慢。
BEZIER曲线:
算法源于书上,是三次bezier曲线的算法。
Bresenham画圆和中点画圆算法:
两个算法均为书上源程序,实现并没有太大的问题,但是有一点没有处理好,就是不可以确定圆心位置,在最后实现效果上并没有做好。
雪花曲线:
Koch雪花可由一个正三角形生成,即将正三角形的每一边三等分后将中间一段向外凸起成一个以该段长度为边长的正三角形(去掉底边),然后对每一段直线又再重复上述过程,这样无休止地重复下去即得Koch雪花。
马跳回溯算法:
定义结构体:struct PLACE{int x, int y}表示棋盘上的位置。 依题意,马每跳一步之后都可以从七个不同的方向选择下一步的跳马,当然,前提是跳的这一步在棋盘内且它前面的任何一步都没跳到这一格子上(限界),就可以认为这一步跳成功,否则跳马不成功。若跳马不成功,则找下一个方向尝试跳马,若七个方向都跳马不成功,则回溯。
3.使用说明
系统操作说明
一:程序运行环境: 个人计算机,VC6环境
二: 操作说明:
直线:直线有三种算法,分别是DDA,Bresenham 和中点算法,在画直线时,先在画图区点一下,然后按住鼠标左键移动就可以动态的画直线了,到合适的时候释放左键即可。
圆:圆是用Bresenham算法实现的,在画圆时,先在画图区点一点为圆心,然后按住鼠标左键移动可以改变半径,到合适的时候释放左键即可。
椭圆:椭圆是用中点算法实现的,在画椭圆时,先在画图区点一下,然后按住鼠标左键移动可以改变椭圆短半径和长半径,到合适的时候释放左键即可。
二维填充:二维填充有三种算法,其中扫描线转换算法是固定填充的,对指定区域进行填充。四连通和扫描线种子填充法是可以填充任意形状的图形(曲线,多边形等)的。在使用时只需先画好需要填充的边界然后选择种子填充并用鼠标左键点击确定种子点即可填充。
二维裁剪:二维裁剪是演示性的功能,直接点击该菜单项就可演示。
二维基本变换:二维基本变换是演示性的功能,直接点击该菜单项就可演示。
二维动画:二维动画是演示性的功能,直接点击该菜单项就可演示。
三维图形:三维图形是演示性的功能,直接点击该菜单项就可以演示了。不过三维图形里面的凸多边形建模是交互式的,可以滚动鼠标的滑轮改变投影参考点以获得不同的视觉效果。
Bezier曲线:Bezier曲线是用DeCasteljau 算法实现的,按提示说明在画图区点四个点就可以画Bezier曲线了。
雪花曲线:雪花曲线是选做项目,是用递归实现的,点击该菜单项即可演示雪花曲线了。
跳马回溯法:跳马回溯法也是选作项目,按开始键后用左键在屏幕上点一下,释放鼠标后会显示棋盘,用回溯法跳马,跳完所有步后回到原点结束。
颜色:可以改变画图颜色。
清除:把画图区置为背景色白色。
分工情况:
参考文献:
[1]刘倩主编, 计算机图形学实验教程,西南交通大学出版社,2009
[2]张彩明等编著,计算机图形学(第二版),科学出版社,2008
[3]白建军等编著,Opengl三维图形设计与制作,人民邮电出版社,1999
[4] 孙家广,胡事民 编著, 计算机图形学基础教程,清华大学出版社,2005
[5] 孙鑫、余安萍编著,VC++深入详解,电子工业出版社,2006
[6] 侯俊杰主编,深入浅出MFC,华中科技大学出版社,2001
[7]pndn程序员联合网上的源程序----计算机图形学
[8] pndn程序员联合网上的源程序---- Graphics
[9]白燕斌,史惠康主编,opengl三维图形库编程指南,机械工业出版社,1998
[10]周建龙 肖春主编,计算机图形学理论与Opengl编程实践,华南理工大学出版社,2007
[11] 孙鑫VC++网上视频
注:1、报告内的项目或内容设置,可根据实际情况加以调整和补充。
2、教师批改学生实验报告时间应在学生提交实验报告时间后10日内。
深圳大学实验报告课程名称学院实验时间实验报告提交时间教务部制深圳大学学生实验报告用纸注1报告内的项目或内容设置可根据实际情况加以调…
深圳大学实验报告课程名称办公软件高级应用实验项目名称Word综合设计学院专业指导教师丁慧姓名学号实验时间实验报告提交时间教务处制2…
EDA实验报告姓名学号班级实验14选1数据选择器的设计一实验目的1学习EDA软件的基本操作2学习使用原理图进行设计输入3初步掌握器…
武汉轻工大学数学与计算机学院计算机组成原理实验报告题目4位二进制计数器实验专业软件工程班级130X班学号1305110XXX姓名X…
四位全加器11微电子黄跃1117426021实验目的采用modelsim集成开发环境利用verilog硬件描述语言中行为描述模式结…
4位全加器的设计实验报告班级通信122班学号120xx216姓名韦建萍一实验目的熟悉利用QuartusII的原理图输入方法设计简单…
EDA技术及应用实验报告一位全加器VHDL的设计班级XXX姓名XXX学号XXX一位全加器的VHDL设计一实验目的1学习MAXPLU…