1计算机图形学实验报告班级应数0702学号1301070214姓名陶果2实验一:二维线画图元的生成实验目的:掌握直线段的生成算法,并用C/WIN-TC/VC++实现算法,包括中点法生成直线,微分数值法生成直线段等。实验内容:用不同的方法生成斜率不同的直线段,比较各种方法的效果。Bresenham算法的思想Bresenham画法与中点法相似,都是通过每列象素中确定与理想直线最近的像素来进行直线的扫描的转换的。通过各行、各列的象素中心构造一组虚拟网格线的交点,然后确定该列象素中与此交点最近的像素。该算法的巧妙之处在于可以采用增量计算,使得对于每一列,只需要检查一个误差项的符号,就可以确定该列的所有对象。1.1方法一:直线的中点算法算法的主要思想:讨论斜率k∈[1,+∞)上的直线段的中点算法。对直线01pp,左下方的端点为0p(x0,y0),右上方的端点为1p(x1,y1)。直线段的方程为:ymxByyxBxyyxxBx(,)0FxyxyyxxB现在假定已求得像素(,,irixy),则如图得,,11(,]22iirirxxx由于直线的斜率k∈[1,+∞),故m=1/k∈(0,1],则1,,13(,]22iirirxxx在直线1iyy上,区间,,13(,]22irirxx内存在两个像素NE和E。根据取整原则,当11(,)iixy在中点M11(,)2iixy右方时,取像素NE,否则取像素E,即,11,,1()()01()()0iriiririxEFMxxxNEFMxii点当(,y+1)在左方时点当(,y+1)在右方时若取2()idFM,则上式变为,1,,()01(0iriiririxEdxxNEd点当点)当计算id的递推公式如下:3,11,12[(2)()]0122(,2)0122[(2)(1)]2iiriiiiiiirxyyxxBddFxydxyyxxB=202()0iiiidxddxyd算法的初始条件为:00,00,0(,)(0,0)12(,1)22rrxyxydFxyxy相应的程序示例:建立成员函数:voidMidPointLine4(CDC*pDC,intx0,inty0,intx1,inty1,intcolor){/*假定x0x1,直线斜率m1*/intdx,dy,incrE,incrNE,d,x,y;dx=x1-x0;dy=y1-y0;d=2*dx-dy;incrE=2*dx;incrNE=2*(dx-dy);x=x0;y=y0;pDC-SetPixel(x,y,color);while(xx1){if(d=0)d+=incrE;else{d+=incrNE;x++;}y++;p-SetPixel(x,y,color);}}编写OnDraw函数:voidCMy1_1View::OnDraw(CDC*pDC){CMy1_1Doc*pDoc=GetDocument();ASSERT_VALID(pDoc);//TODO:adddrawcodefornativedatahereMidPointLine4(pDC,200,200,300,300,RGB(0,0,0));MidPointLine4(pDC,300,200,400,300,RGB(0,0,0));MidPointLine4(pDC,400,200,500,300,RGB(0,0,0));}编译运行程序得到如下结果:41.2方法二:直线的数值微分法算法的主要思想:由于课本上已经给出了斜率m∈[-1,1]上的算法,故此处给出斜率m∈[1,+∞〕上的算法,m∈(-∞,-1]上的可同理推导。已知待扫描转换的直线为0p(x0,y0),1(1,1)pxy,又10,10xxxyyy,则设k=1/m=/xy(即k∈(0,1])。直线方程为1yxBk,即()xkyB。以一个像素为单位分割区间[y0,y1],由x0x1,故y0y1,得到[y0,y1]上的一个划分:0y,1y,….ny,其中1iy=iy+1,得到点列0(,)niiixy,由公式11()(1)iiiixkyBkyBxk故从ix直接得到1ix。ix可能为浮点数,要对它取整,实际得到像素集,0(,)niirixy。初值为:(00,xy)=(x0,y0)。实验内容:编写自定义的成员函数ddaline()程序:voidCMy1View::ddaline(CDC*pDC,intx0,inty0,intx1,inty1,COLORREFcolor){intlength,i;floatx,y,dx,dy;length=abs(x1-x0);if(abs(y1-y0)length)length=abs(y1-y0);dx=(x1-x0)/length;dy=(y1-y0)/length;5x=x0+0.5;y=y0+0.5;for(i=1;i=length;i++){pDC-SetPixel((int)x,(int)y,color);x=x+dx;y=y+dy;}}编写OnDraw()函数:voidCMy1View::OnDraw(CDC*pDC){CMy1Doc*pDoc=GetDocument();ASSERT_VALID(pDoc);//TODO:adddrawcodefornativedatahereddaline(pDC,100,100,400,100,RGB(255,0,0));ddaline(pDC,400,100,400,400,RGB(0,255,0));ddaline(pDC,400,400,100,400,RGB(0,0,255));ddaline(pDC,100,400,100,100,RGB(255,255,0));ddaline(pDC,100,100,400,400,RGB(255,0,255));ddaline(pDC,100,400,400,100,RGB(0,255,255));}编译运行程序得到如图所示结果:1.3方法三:生成直线段的Bresenham算法与中点算法类似,Bresenham算法也是通过在每列像素中确定与理想直线最近的像素来进行直线扫描转换的。为了讨论方便,此处假定直线的斜率在0,1之间。对直线对直线01pp,左下方的端点为0p(x0,y0),右上方的端点为1p(x1,y1)。如图,由ix到11iixx,则d=d+m,一旦d1时,d=d-1,以保证d始终在0,1之间。610.5()0.51()iiidyEydyNE点点初始条件为:000(,)(0,0)0xyxyd编写成员函数如下:voidCMy1_2View::BresenhamLine(CDC*pDC,intx0,inty0,intx1,inty1,intcolor){intx,y,dx,dy,i;floatm,d;dx=x1-x0;dy=y1-y0;m=dy/dx;d=0;x=x0;y=y0;pDC-SetPixel(x,y,color);for(i=0;i=dx;i++){d+=m;if(d=0.5){y+=1;d-=1;}x++;pDC-SetPixel(x,y,color);}}编写OnDraw函数如下:voidCMy1_2View::OnDraw(CDC*pDC){CMy1_2Doc*pDoc=GetDocument();ASSERT_VALID(pDoc);//TODO:adddrawcodefornativedatahereBresenhamLine(pDC,100,300,500,100,RGB(0,0,0));}编译运行得到以下结果:7实验二:基本曲线曲面的生成实验目的:掌握基本曲线曲面的生成算法,并用C/WIN-TC/VC++实现算法,包括圆,椭圆,抛物线的生成算法,填充图形的生成算法和图形的裁剪算法等。实验内容:自己设计一个图形,比如一个花瓣,整个花瓣可能是一个个椭圆的一部分组成,这就要用到椭圆的生成算法,而花瓣的着色就要用到图形的填充算法。花蕊可能是抛物线,就要用到抛物线的生成算法。总之,大家自己设计一个综合的图形,尽可能地包括以下所列出的四个部分的算法,至少要用到前三个部分中的每一个部份的至少一种算法。第一部分:圆与椭圆抛物线1.圆与抛物线、椭圆的生成算法1.1生成圆弧的函数算法生成圆弧的最简单方法莫过于利用其函数方程,直接离散计算。中心在坐标原点,半径为R的圆的方程为222xyR。考虑第一象限内[0,/2]xR的八分之一圆弧,首先将区间[0,/2R]以1个像素为单位离散得到0()niix,其中11iixx。再根据圆的方程求得0()niiy,其中22iiyRx,则,0(,)niirixy,为所求的像素集。建立成员函数如下:#includemath.hvoidCMy2_6View::sqrtCircle(CDC*pDC,intradius,intcolor){floatx,y;8x=0;y=radius;pDC-SetPixel(x,y,color);while(y=x){x++;y=sqrt(radius*radius-x*x);pDC-SetPixel((int)(x+0.5),(int)(y+0.5),color);}}编写OnDraw函数如下:voidCMy2_6View::OnDraw(CDC*pDC){CMy2_6Doc*pDoc=GetDocument();ASSERT_VALID(pDoc);//TODO:adddrawcodefornativedataheresqrtCircle(pDC,300,RGB(0,0,0));}编译运行程序得到如下结果:1.2生成圆弧参数算法生成圆弧也可以利用其参数方程cosxR,sinyR,[0,2]。考虑第一象限内的八分之一圆弧{(cos,sin)|[0,/4]}RR。首先将区间[0,/4]按一定的步长离散得0{}nii,再求相应的像素集为0{((cos),(sin))}niiiroundRroundR。建立成员函数如下:voidCMy2_7View::funCircle(CDC*pDC,intradius,intcolor){floatx,y,afla,pie;pie=3.1415926;x=radius;y=0;afla=0;9pDC-SetPixel(x,y,color);while(afla=pie/4){afla+=pie/400;x=radius*cos(afla);y=radius*sin(afla);pDC-SetPixel((int)(x+0.5),(int)(y+0.5),color);}编写OnDraw函数如下:voidCMy2_7View::OnDraw(CDC*pDC){CMy2_7Doc*pDoc=GetDocument();ASSERT_VALID(pDoc);//TODO:adddrawcodefornativedataherefunCircle(pDC,300,RGB(0,0,0));}编译运行程序得到如下结果:}1.3圆的中点算法生成圆弧的中点算法和上面讲到的生成直线段的中点算法类似,考虑第一象限内[0,/2]xR的八分之一圆弧段。经过计算,得出判别式的递推公式为:12302()50iiiiiidxdddxyd这两个递推公式的初值条件为:00,0(,)(0,)5/4rxyRdR(,,iirxy)EMSE10编写成员函数如下:voidCMy2_9View::MidPointEllipse(CDC*pDC,doublea,doubleb,intcolor){