1、计算机图形学课程设计-基于四叉树算法绘制颜色填充等值线图姓名:陈明学号:200905070110学院:信息科学与技术学院指导老师:黄地龙老师一、 问题提出与需求分析1、 问题及目标问题:基于四叉树算法绘制颜色填充等值线图。目标:利用四叉树思想用所给文件中的数据绘制等值线图,并绘出坐标系及颜色标识码。通过本次实验提高学生编程能力,加深对OpenGL的理解,加深对VC+6.0的认识。2、 问题概念及算法原理等值线是一组值相等的序列连线组成的图形。等值线图在实际中应用广泛,如等高线图、等气压图等等。等值线的表达形式有两类:一类是画线等值线图;另一类是颜色填充等值线图。依据数据分部不同,等值线图的绘制
2、有两类方法:三角网法和矩形网格法。三角网法是针对数据分布不规则的环境下的一种绘制方法。矩形网格法是一种针对数据分布规则的等直线图绘制方法。它是设平面区域按一定大小的网格距划分的矩形网格。由于所给数据时矩形网格数据,所以本程序采用矩形网格法,并采用颜色填充。改程序采用基于四叉树的颜色填充等值线图绘制方法。四叉树的基本算法思想是:当网格四个节点的颜色值相等时,则用该颜色值填充该矩形,否则将矩形网格等分四个小网格,并用插值方法计算每个小网格的颜色值,递归使用网格四个节点的颜色值是否相等,由此依次建立一棵四叉树。当细分至四个节点的颜色值全部都小于或等于一个像素时,则将其视为等值线上的点,用来画等值线。
3、在该程序中,对于等值线处理比较粗糙,采用的是描点的方式,当四个节点的颜色值全部都小于或等于一个像素时,对其进行描点处理,这样处理的结果导致等值线不够光滑,且颜色级数不能过大,否则效果比较难看。一般来说颜色级数为11最佳,主要是本人能力有限。二、 绘图程序设计的技术思路1、 程序总体设计利用四叉树思想绘制等颜色填充等值线图,首先应从数据文件中读取数据,用二级指针*a来存放,并求出最大值max及最小值min,接收键盘输入的颜色级数Ncolor,并求出等值颜色域的间距Dc,Dc=(max-min)/Ncolor。为了填充颜色得先建立颜色填充表,可以采用颜色类的方式,本程序中采用三个浮点型数组r、g、
4、b来建立颜色填充表,由函数void Color(int m)来构造。准备工作做好了开始构建四叉树,采用递归思想循环调用四叉树算法填充矩形网格的颜色值,当x增量和y增量都小于1个像素点时则可认为该点为等值区域的边界点,即等值线上的点,作为描绘等值线的点。填充完毕后建立平面坐标系并绘制色码标识。根据以上所述,程序设计步骤可分为以下几步:(1)读入网格数据值,并求全区网格的最大值max和最小值min。(2)给定等值线的级数Ncolor,求得等值线的间距Dc=(max-min)/Ncolor。(3)建立填充颜色表r,g,b。 (4)循环递归调用四叉树算法填充网格矩形颜色值。(5)等值线检测(6)绘制平
5、面坐标系(7)绘制色码标识2、 详细设计及各函数主要算法原理(1)void TreeMath(float x,float y,float dx,float dy,int z1,int z2,intz3,int z4); 递归调用四叉树算法填充网格矩形颜色值由下列式子分别计算z1、z1、z3、z4、的颜色索引值Ic1、Ic2、Ic3、Ic4,Ic1=int(z1-min)/Dc),Ic2=int(z2-min)/Dc),Ic3=int(z3-min)/Dc),Ic4=int(z4-min)/Dc)(Dc为等值颜色域的间距,min为数据最小值)。当它们颜色索引值相等时则说明它们位于一个等值区域(该
6、区域是以点(x,y)和(x+dx,y+dy)为对角顶点的矩形),调用函数glColor3f(rIc1,gIc1,bIc1)对该区域设置对应的颜色。若dx,dy都小于1,则说明(x,y)位于等值域的边界上。否则循环递归调用该函数直到满足上面两个条件之一。(2)void gltRasterText(float x, float y, const char *text, void *font)采用光栅思想在(x,y)处输出text的值,输出字体为font,用于描绘坐标系,输出X轴和Y轴的坐标。(3)void DrawCoordinate(float x,float y)绘制坐标系,(x,y)为图片开
7、始的坐标,即图片坐标系的原点,由于对OpenGL不是很熟悉,所以在本程序中采用的是画网格的方法绘制图片的坐标系。在边缘部分都延长出去5个像素点,从原点开始每隔20个单位分别在X轴方向和Y轴方向画一条直线,X轴方向画column(数据文件中数据的列数)条,Y轴方向画row(数据文件中数据的行数)条,再调用gltRasterText(float x, float y, const char *text, void *font)在相应的地方输出坐标轴的坐标值。网格画好了再将图贴上去则把中间的网格覆盖,只留坐标轴。由于是先画网格后画图,所以部分坐标轴会被覆盖,所以外围四条线单独在绘图完成后再画。(4)
8、void DrawCodeIdentifier(float x,float y);色码标识绘制函数,从点(x,y)开始沿X、Y的正向绘制色码标识,色码标识由Ncolor(颜色级数)个小矩形构成,其颜色是由红色到绿色连续变化的,代表值的从小到大并调用函数gltRasterText(float x, float y, const char *text, void *font)在相应地方标出其所代表的值的大小,最小值min(数据最小值),按步长Dc(等值颜色域的间距)从红色到绿色依次递增。(5)void display(void);窗口的显示回调函数。调用以上函数绘制完整的等值线图,循环调用Tree
9、Math(float x,float y,float dx,float dy,int z1,int z2,int z3,int z4)函数对整个数据网格进行填充,绘制完整的颜色填充等值线图。三、 主要程序设计的说明1、 变量说明下列变量因为要多个函数共用,为了方便,所以将其声明为全局变量。int max,min; max用来记录网格数据中的最大值,min用来记录网格数据中的最小值。int Ncolor;用来设置颜色的级数,动态设置,接收键盘的输入。int Dc;用来记录等值颜色域的间距,Dc=(max-min)/Ncolor。float *r,*g,*b;用于构建颜色填充表,其大小由颜色级数N
10、color来进行动态分配。分别代表RGB三种颜色的颜色值。int row,column; row用于记录网格数据的行数,column用于记录网格数据的列数。int *a;用于存放网格数据值。其大小由行数row和列数column动态分配。2、 函数说明这里只对各函数做功能上的说明,具体实现的源程序请见附录后的源代码。(1) void ReadData();无参函数,用于从数据文件“网格数据.txt”中读取数据到arowcolumn里面,计算最大值max和最小值min及数据的行数row和列数column,并将文件中的数据和最大、最小值输出到屏幕。(2)void Initial(void);初始化窗
11、口,设置窗口背景颜色为白色,指定设置投影参数。指定使用正投影将一个x坐标在0.0400.0,y坐标在0.0350.0的矩形坐标区域投影到窗口内。(3)void gltLine2d(float x0, float y0, float x1, float y1);用于绘制直线,直线的端点坐标分别为(x0,y0),(x1,y1),参数x0,y0,x1,y1用于从外界接收直线的端点坐标。(4)void Color(int m);建立填充颜色表,为颜色数组r、g、b赋值,是颜色呈连续变化。形参m用于设置颜色级数,接收其它函数中的值传递。(5)void TreeMath(float x,float y,f
12、loat dx,float dy,int z1,int z2,int z3,int z4);用于建立四叉树,并填充一个网格的颜色,形参x、y分别为x、y轴的坐标,形参dx、dy分别x、y轴方向的增量,参数z1、z2、z3、z4分别为网格四个顶点的高度值,即文件中数据传入的接口。(6)void gltRasterText(float x, float y, const char *text, void *font)采用光栅化思想定位输出text中的值,输出字体由font指定,参数x、y为定位坐标。(7)void DrawCoordinate(float x,float y)绘制以(x,y)为原点
13、的平面坐标系。(8)void DrawCodeIdentifier(float x,float y),在图片的右边绘制以(x,y)为起点的沿X、Y的正向绘制色码标识,其颜色是连续变化的。(9)void display(void),窗口显示回调函数,在窗口中绘制完整的颜色填充等值线图,即最终呈现的结果。(10)int main(int argc,char*argv),程序运行的主函数。其中接收键盘输入的Ncolor设置颜色级数,利用公式max=(int(max/10)+1)*10和min=(int(min/10)*10对最大、最小值进行处理,并求出等值颜色域的间距Dc,Dc=(int)(max-
14、min)/Ncolor)。glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB)初始化窗口的显示模式,glutInitWindowSize(800,500)设置窗口的尺寸,glutInitWindowPosition(100,120)设置窗口的位置,glutCreateWindow(等值线绘制)创建一个名为等值线绘制的窗口,glutDisplayFunc(display)设置当前窗口的显示回调函数,Initial()完成窗口初始化,glutMainLoop()启动主GLUT事件处理循环。四、 完成的成果与体会1、 实验结果2、 实验总结通过几周的努力,在老师的帮助下
15、终于把这次实验完成了,通过这次实验对上学期计算机图形学里面的一些不太懂的问题也算是终于弄得比较清楚了,并且对VC+6.0的认识又进了一步,现在对于程序的错误和异常终于不再感到那么迷茫了,对于以前一直感到模糊的四叉树算法和递归算法也终于弄清楚了。对于OpenGL里的一些函数也有了一定的理解,对于光栅原理也有了进一步的认识。对于一些算法也产生了一些兴趣。不过通过这次实验也认识到了自己很多的不足之处。作为软件工程的我们编程能力感觉还差得远,对于算法的理解不是很透彻,而且对于编程工具VC+6.0很不熟悉。脑袋里感觉还没形成一种程序设计的模式,拿到一个题目时感觉很迷茫,不知从何处着手,如果没有老师的指导
16、估计也很难做出来。而且对于上学期的图形学感觉也学得不怎么好。编程的时间太少了。最后,感谢老师在整个过程中对我的指导。附录:源代码:#include #include #include using namespace std;int max,min;int Dc;int Ncolor;float *r,*g,*b;int *a;int row,column;/读取文件数据void ReadData()FILE *fp;char ch;int i,j;if(fp=fopen(网格数据.txt,r)=NULL)coutopen errorn; while(!feof(fp)&(ch=fgetc(fp
17、)!=n) if(ch= )column+; column+;if(column=1)printf(no datan);/置文件首部fseek(fp,0L,0);/统计行数while(!feof(fp)if(fgetc(fp)=n)row+;row+;if(row=1)printf(no datan);/开辟内存 a=(int*)malloc(sizeof(int*)*row);if(a=NULL)printf(no memoryn);for(i=0;irow;i+)ai=(int*)malloc(sizeof(int)*column);if(ai=NULL)printf(no memoryn
18、);/置文件首部fseek(fp,0L,0);/读入数据while(!feof(fp)for(i=0;irow;i+)for(j=0;jcolumn;j+)fscanf(fp,%d,&aij);/输出显示for(i=0;irow;i+)for(j=0;jcolumn;j+)j=column-1?printf(%d,aij):printf(%d,aij);printf(n);/求最大值、最小值max=min=a00;for(i=0;irow;i+)for(j=0;jcolumn;j+)if(max=aij) min=aij;coutmax minendl;/关闭文件fclose(fp);/初始化
19、窗口void Initial(void)glClearColor(1.0f,1.0f,1.0f,1.0f);glMatrixMode(GL_PROJECTION);gluOrtho2D(0.0,400.0,0.0,350.0);/画直线void gltLine2d(float x0, float y0, float x1, float y1)glColor3f(0.0f,0.0f,0.0f); glBegin(GL_LINES); glVertex2d(x0, y0); glVertex2d(x1, y1); glEnd();/构建颜色填充表void Color(int m)r=new flo
20、atm;g=new floatm;b=new floatm;r0=1.0;gm-1=1.0;rm-1=0.0;g0=0.0;b0=0.0;bm-1=0.0;float dr=(rm-1-r0)/m;float dg=(gm-1-g0)/m;float db=(bm-1-b0)/m;for(int i=1;im-1;i+)ri=ri-1+dr;gi=gi-1+dg;bi=bi-1+db;/循环递归调用四叉树算法填充网格矩形颜色值void TreeMath(float x,float y,float dx,float dy,int z1,int z2,int z3,int z4)int Ic1,I
21、c2,Ic3,Ic4;Ic1=int(z1-min)/Dc);Ic2=int(z2-min)/Dc);Ic3=int(z3-min)/Dc);Ic4=int(z4-min)/Dc);if(Ic1=Ic2&Ic2=Ic3&Ic3=Ic4)glColor3f(rIc1,gIc1,bIc1);glRectf(x,y,x+dx,y+dy);else if(dx=1&dy=1)float dx1=dx/10;float dy1=dy/10;for(int n=0;n10;n+)glColor3f(0.0f,0.0f,0.0f);glBegin(GL_POINTS);glVertex2d(x+n*dx1,
22、 y+n*dy1);glEnd();elsedx=dx/2;dy=dy/2;TreeMath(x,y,dx,dy,z1,(z1+z2)/2,(z1+z2+z3+z4)/4,(z1+z4)/2);TreeMath(x,y+dy,dx,dy,(z1+z4)/2,(z1+z2+z3+z4)/4,(z3+z4)/2,z4);TreeMath(x+dx,y+dy,dx,dy,(z1+z2+z3+z4)/4,(z2+z3)/2,z3,(z3+z4)/2);TreeMath(x+dx,y,dx,dy,(z1+z2)/2,z2,(z2+z3)/2,(z1+z2+z3+z4)/4);/指定文本在窗口中的输出信息
23、及位置void gltRasterText(float x, float y, const char *text, void *font) if(text = NULL) return ; glRasterPos2d(x, y); for(int i=0; texti != 0; i+) glutBitmapCharacter(font, texti); /绘制坐标系void DrawCoordinate(float x,float y)int i,j;char text32;for(i=1;icolumn-1;i+)gltLine2d(x+i*20.0,y-4,x+i*20.0,y+(row
24、-1)*20.0+4);sprintf(text, %d, i*20);glColor3f(0, 0, 0);gltRasterText(x+i*20.0,y-15, text,GLUT_BITMAP_HELVETICA_18);gltRasterText(x+i*20.0,y+5+(row-1)*20.0, text,GLUT_BITMAP_HELVETICA_18);for(i=1;irow-1;i+)gltLine2d(x-3,y+i*20.0,x+(column-1)*20.0+3,y+i*20.0);sprintf(text, %d, i*20);glColor3f(0, 0, 0)
25、;gltRasterText(x-18,y+(row-1-i)*20.0-5, text,GLUT_BITMAP_HELVETICA_18);gltRasterText(x+5+(column-1)*20.0,y+(row-1-i)*20.0-5, text,GLUT_BITMAP_HELVETICA_18);glColor3f(0, 0, 0);sprintf(text, %d, 0);gltRasterText(x,y-15, text,GLUT_BITMAP_HELVETICA_18);gltRasterText(x,y+5+(row-1)*20.0, text,GLUT_BITMAP_
26、HELVETICA_18);gltRasterText(x-18,y+(row-1)*20.0-5, text,GLUT_BITMAP_HELVETICA_18);gltRasterText(x+5+(column-1)*20.0,y+(row-1)*20.0-5, text,GLUT_BITMAP_HELVETICA_18);sprintf(text, %d, (column-1)*20);gltRasterText(x+(column-1)*20.0,y-15, text,GLUT_BITMAP_HELVETICA_18);gltRasterText(x+(column-1)*20.0,y
27、+5+(row-1)*20.0, text,GLUT_BITMAP_HELVETICA_18);sprintf(text, %d, (row-1)*20);gltRasterText(x-18,y-5, text,GLUT_BITMAP_HELVETICA_18);gltRasterText(x+5+(column-1)*20.0,y-5, text,GLUT_BITMAP_HELVETICA_18);/绘制色码标识void DrawCodeIdentifier(float x,float y)int i,j;char text32;for(i=0;iNcolor;i+)glColor3f(r
28、i,gi,bi);glRectf(x+20+(column-1)*20.0+10,y+(i+1)*15.0,x+20+column*20.0,y+i*15.0);gltLine2d(x+20+(column-1)*20.0+10,y+i*15.0,x+20+column*20.0,y+i*15.0);sprintf(text, %d, min+i*Dc);glColor3f(0, 0, 0);gltRasterText(x+20+column*20.0,y+i*15.0-5, text,GLUT_BITMAP_HELVETICA_18);sprintf(text, %d, min+Ncolor
29、*Dc);glColor3f(0, 0, 0);gltRasterText(x+20+column*20.0,y+Ncolor*15.0-5, text,GLUT_BITMAP_HELVETICA_18);gltLine2d(x+20+(column-1)*20.0+10,y,x+20+(column-1)*20.0+10,y+Ncolor*15.0);gltLine2d(x+20+column*20.0,y,x+20+column*20.0,y+Ncolor*15.0);gltLine2d(x+20+(column-1)*20.0+10,y+Ncolor*15.0,x+20+column*2
30、0.0,y+Ncolor*15.0);/窗口显示回调函数void display(void)int i,j;glClear(GL_COLOR_BUFFER_BIT);float x=25;float y=100;DrawCoordinate(x,y);for(i=0;irow-1;i+)for(j=0;jcolumn-1;j+)float dx=20.0;float dy=20.0;TreeMath(x+j*dx,y+i*dy,dx,dy,aij,aij+1,ai+1j+1,ai+1j);gltLine2d(x,y-4,x,y+(row-1)*20.0+4);gltLine2d(x-3,y,x
31、+(column-1)*20.0+3,y);gltLine2d(x-3,y+(row-1)*20.0,x+(column-1)*20.0+3,y+(row-1)*20.0);gltLine2d(x+(column-1)*20.0,y-4,x+(column-1)*20.0,y+(row-1)*20.0+4);DrawCodeIdentifier(x,y);glFlush();/主函数int main(int argc,char*argv)ReadData();coutNcolor;Color(Ncolor);max=(int(max/10)+1)*10;min=(int(min/10)*10;
32、Dc=(int)(max-min)/Ncolor);glutInit(&argc,argv);glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);glutInitWindowSize(800,500);glutInitWindowPosition(100,120);glutCreateWindow(等值线绘制);glutDisplayFunc(display);Initial();glutMainLoop();return 0;网格数据.txt229 219 199 216 235 255 266 285 272 241 246 281 284 275 261
33、273221 214 195 216 234 258 273 289 281 249 259 278 287 272 275 277213 203 196 206 221 232 259 293 294 277 258 285 287 283 288 286204 195 200 201 209 218 231 259 288 306 286 291 301 311 319 298196 207 201 211 239 234 241 259 294 315 317 321 325 322 325 341208 218 204 214 235 260 239 268 298 291 331 3
34、13 281 280 280 280216 231 218 196 220 255 271 253 264 303 322 312 276 243 238 239236 242 218 198 200 215 224 238 261 294 324 312 280 255 220 200255 241 219 211 206 225 252 275 284 285 305 316 271 237 208 191245 218 207 198 214 241 261 256 273 276 291 298 281 238 197 175225 215 205 195 208 221 235 252 262 271 301 275 245 212 181 171 .17