计算机图形学课程设计--图形绘制变换
目录
一、引言------------------------------------------------------------------------2
二、设计需求--------------------------------------------------------------------2
2.1 设计目标---------------------------------------------------------------2
2.2 设计环境---------------------------------------------------------------2
2.2.1 VC++6.0 ---------------------------------------------------------2
2.2.2 MFC -------------------------------------------------------------3
2.3 设计题目及要求--------------------------------------------------------3
2.4 总体流程图------------------------------------------------------------3
三、课程设计原理----------------------------------------------------------------4
3.1 实现的算法-------------------------------------------------------------4
3.1.2 Bresenham算法画直线---------------------------------------------4
3.1.3 中心点算法画圆和椭圆---------------------------------------------4
3.2 图形变换的基本原理-----------------------------------------------------6
3.2.1 平移变换---------------------------------------------------------6
3.2.2 旋转变换--------------------------------------------------------7
3.2.3 比例变换--------------------------------------------------------7
四、总体设计与功能实现----------------------------------------------------------7
4.1 主要界面设计-----------------------------------------------------------7
4.2 设置颜色界面-----------------------------------------------------------7
4.2.1 界面设置代码-----------------------------------------------------7
4.2.2 运行结果---------------------------------------------------------8
4.3 二维线画图元实现-------------------------------------------------------8
4.4 画多边形功能的实现---------------------------------------------------12
4.5 画Bezier曲线功能的实现----------------------------------------------13
4.6 二维图形变换的实现---------------------------------------------------15
4.7 三维图形的变换-------------------------------------------------------16
五、实验心得体会
一、引言
计算机图形学(Computer Graphics,简称CG)是一种使用数学算法将二维或三维图形转化为计算机显示器的栅格形式的科学。简单地说,计算机图形学的主要研究内容就是研究如何在计算机中表示图形、以及利用计算机进行图形的计算、处理和显示的相关原理与算法。是计算机科学的一个分支领域,主要关注数字合成与操作视觉的图形内容。计算机图形学研究的是应用计算机产生图像的所有工作,不管图像是静态的还是动态的,可交互的还是固定的,等等。图形API是允许程序员开发包含交互式计算机图形操作的应用而不需要关注图形操作细节或任务系统细节的工具集。计算机图形学有着广泛的应用领域,包括物理、航天、电影、电视、游戏、艺术、广告、通信、天气预报等几乎所有领域都用到了计算机图形学的知识,这些领域通过计算机图形学将几何模型生成图像,将问题可视化从而为各领域更好的服务。
计算机图形学利用计算机产生让人赏心悦目的视觉效果,必须建立描述图形的几何模型还有光照模型,再加上视角、颜色、纹理等属性,再经过模型变换、视图变换、投影操作等,这些步骤从而实现一个完整的OpenGL程序效果。OpenGL是一个开放的三维图形软件包,它独立于窗口系统和操作系统,以它为基础开发的应用程序可以十分方便地在各种平台间移植。计算机图形学通过应用OpenGL的功能,使得生成的图形效果具有高度真实感。学习计算机图形学的重点是掌握OpenGL在图形学程序中的使用方法。事实上,图形学也把可以表示几何场景的曲线曲面造型技术和实体造型技术作为其主要的研究内容。同时,真实感图形计算的结果是以数字图像的方式提供的,计算机图形学也就和图像处理有着密切的关系。
通过21世纪是信息的时代,在日新月异的科技更新中相信计算机会发挥越来越重要的作用,计算机图形学也会在更多的领域所应用,虽然我国在这方面还比较薄弱,但相信会有越来越好的时候的。
二、设计需求
2.1 设计目标
以图形学算法为目标,深入研究。继而策划、设计并实现一个能够表现计算机图形学算法原理的或完整过程的演示系统,并能从某些方面作出评价和改进意见。通过完成一个完整程序,经历策划、设计、开发、测试、总结和验收各阶段,达到:巩固和实践计算机图形学课程中的理论和算法;学习表现计算机图形学算法的技巧;培养认真学习、积极探索的精神。
2.2 设计环境
2.2.1 VC++6.0
VC++6.0是 Microsoft 公司推出的一个基于 Windows 系统平台、可视化的集成开发环境,它的源程序按 C++语言的要求编写,并加入了微软提供的功能强大的 MFC(Microsoft Foundation Class)类库。MFC 中封装了大部分 Windows API 函数和 Windows 控件,它包含的功能涉及到整个 Windows 操作系统。MFC 不仅给用户提供了 Windows 图形环境下应用程序的框架,而且还提供了创建应用程序的组件,这样,开发人员不必从头设计创建和管理一个标准 Windows 应用程序所需的程序,而是从一个比较高的起点编程,故节省了大量的时间。另外,它提供了大量的代码,指导用户编程时实现某些技术和功能。因此,使用VC++提供的
高度可视化的应用程序开发工具和 MFC 类库,可使应用程序开发变得简单。
2.2.2 MFC
MFC(Microsoft Foundation Classes) ,是一个微软公司提供的类库( class libraries)以 C++类的形式封装了 Windows 的 API,,它包含了窗口等许多类的定义。各种类的集合构成了一个应运程序的框架结构,以减少应用程序开发人员的工作量。其中包含的类包含大量 Windows 句柄封装类和很多 Windows 的内建控件和组件的封装类。MFC 6.0 版本封装了大约 200 个类,其中的一些可以被用户直接使用。例如CWnd 类封装了窗口的功能,包括打印文本、绘制图形及跟踪鼠标指针的移动等;CsplitterWnd 类是从 CWnd 类派生出来的,继承了基类或称父类 CWnd 类的所有特性,但增加了自己的功能,实现拆分窗口,使窗口至少可被拆分成两个窗口,用户可以移动两个窗口之间的边框来改变窗口的大小;CtoolBar 类可以定义工具栏等。MFC 命名的惯例是类的名字通常是由“C”打头;成员变量使用前缀“m_”,接着使用一个字母来指明数据类型,然后是变量的名称;所有的单词用大写字母开头。
2.3 设计题目及要求
(1)题目:实现多边形和曲线的绘制和变换
(2)要求:学会使用VC++编写实现图形的绘制变换,需包括直线、曲线、多边形的绘制和变换,及三维立体图形的相应变换.
2.4 总体流程图
三、课程设计原理
3.1 实现的算法
3.1.1 DDA算法画直线
DDA是数字微分分析式(Digital Differential Analyzer)的缩写。
已知直线两端点(x1,y1)、(x2,y2)则斜率m为:m = (y2-y1)/(x2-x1)= Dx/Dy;直线中的
每一点坐标都可以由前一点坐标变化一个增量(Dx, Dy)而得到,即表示为递归式: xi+1=xi+Dx yi+1=yi+Dy 。
递归式的初值为直线的起点(x1, y1),这样,就可以用加法来生成一条直线。具体算法是:
该算法适合所有象限,其中用了用了两个函数如:Integer(-8.5)= -9; Integer(8.5)
=8;Sign(i),根据i的正负,分别得到-1,0,+1;
相应代码:
//DDA DrawLine
{if(abs(x2-x1) > abs(y2-y1))
length = abs(x2-x1);
else
length = abs(y2-y1);
Dx = (x2-x1)/length;
Dy = (y2-y1)/length;
x = x1+0.5*Sign(Dx);
y = x2 + 0.5*Sign(Dy);
i = 1;
while(i <= lenght)
{ setpixel(Integer(x),Integer(y),color);
x= x + Dx;
y= y + Dy;
i+=1;} }
3.1.2 Bresenham算法画直线
思路如下:
// 假设该线段位于第一象限内且斜率大于0小于1,设起点为(x1,y1),终点为(x2,y2).
// 根据对称性,可推导至全象限内的线段.
1.画起点(x1,y1).
2.准备画下个点。x坐标增1,判断如果达到终点,则完成。否则,由图中
可知,下个要画的点要么为当前点的右邻接点,要么是当前点的右上邻接点.如果线段
ax+by+c=0与x=x1+1的交点的y坐标大于M点的y坐标的话,下个点为U(x1+1,y1+1),否则,
下个点为B(x1+1,y1),3.画点(U或者B).4.跳回第2步.5.结束.
3.1.3中心点算法画圆和椭圆
(1)中心点算法画圆
在一个方向上取单位间隔,在另一个方向的取值由两种可能取值的中点离圆的远近而定。
实际处理中,用决策变量的符号来确定象素点的选择,因此算法效率较高。生成圆弧的中点算
法和上面讲到的生成直线段的中点算法类似。
考虑第一象限内[0,/x R ∈的八分之一圆弧段。经过计算,得出判别式的递推公式为: 1
2302()5
i i i i i i d x d d d x y d +++≤?=?
+-+>?
这两个递推公式的初值条件为: 00,0(,)(0,)5/4r x y R d R
=??
=-?
编写成员函数如下:
void CMy2_9View::MidPointEllipse(CDC *pDC, double a, double b, int color) {
double x,y,d,xP,yP,squarea,squareb; squarea=a*a; squareb=b*b;
xP=(int)(0.5+(double)squarea/sqrt((double)(squarea+squareb))); yP=(int)(0.5+(double)squareb/sqrt((double)(squarea+squareb))); x=0; y=b;
d=4*(squareb-squarea*b)+squarea; pDC->SetPixel(x,y,color); while(x<=xP)
{if(d<=0) d+=4*squareb*(2*x+3); else
{d+=4*squareb*(2*x+3)-8*squarea*(y-1); y--;} x++;
pDC->SetPixel(x,y,color);} x=a; y=0;
d=4*(squarea-a*squareb)+squareb; pDC->SetPixel(x,y,color) ; while(y { if(d<=0) d+=4*squarea*(2*y+3); else {d+=4*squarea*(2*y+3)-8*squareb*(x-1); x--; } y++; pDC->SetPixel(x,y,color);}} 编写OnDraw 函数如下: void CMy2_9View::OnDraw(CDC* pDC) {CMy2_9Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); MidPointEllipse(pDC,500,300,RGB(0,0,0));} (2)中心点算法画椭圆 我们先考虑圆心在原点的椭圆的生成,对于中心不是原点的椭圆,可以通过坐标的平移变换获得相应位置的椭圆。中心在原点。焦点在坐标轴上的标准椭圆具有X轴对称、Y轴对称和原点对称特性,已知椭圆上第一象限的P点坐标是(x, y),则椭圆在另外三个象限的对称点分别是(x, -y)、(-x, y)和(-x, -y)。因此,只要画出第一象限的四分之一椭圆,就可以利用这三个对称性得到整个椭圆。 相应代码: void MP_Ellipse(int xc , int yc , int a, int b) { double sqa = a * a; double sqb = b * b; double d = sqb + sqa * (-b + 0.25); int x = 0; int y = b; EllipsePlot(xc, yc, x, y); while( sqb * (x + 1) < sqa * (y - 0.5)) {if (d < 0) {d += sqb * (2 * x + 3);} else { d += (sqb * (2 * x + 3) + sqa * (-2 * y + 2)); y--; } x++; EllipsePlot(xc, yc, x, y);} d = (b * (x + 0.5)) * 2 + (a * (y - 1)) * 2 - (a * b) * 2; while(y > 0) {if (d < 0) { d += sqb * (2 * x + 2) + sqa * (-2 * y + 3); x++; } else {d += sqa * (-2 * y + 3); } y--; EllipsePlot(xc, yc, x, y);}} 3.2 图形变换的基本原理 3.2.1 平移变换 平移变换函数如下: void glTranslate{fd}(TYPE x, TYPE y, TYPE z); 三个函数参数就是目标分别沿三个轴向平移的偏移量。这个函数表示用于这三个偏移量生成的矩阵乘以当前矩阵。当参数是(0.0,0.0,0.0)时,表示对函数glTranslate*()的操作是单位矩阵,也就是对物体没有影响。 3.2.2 旋转变换 旋转变换函数如下: Void glRota{fd}TYPE angle, TYPE x, TYPE y, TYPE z); 函数中第一个参数是表示目标沿从点(x,y,z)到原点方向逆时针旋转的角度,后三个参数是旋转的方向点坐标。这个函数表示用这四个参数生成的矩阵乘以当前矩阵。当角度参数是0.0时,表示对物体没有影响。 3.2.3 比例变换 比例变换函数如下: Void glScale{fd}(TYPE x, TYPE y, TYPE z); 单个函数参数值就是目标分别沿三个轴方向缩放的比例因子。这个函数表示用这三个比例因子生成的矩阵乘以当前矩阵。这个函数能完成沿相应的轴对目标进行拉伸、压缩和反射三项功能。以参数x为例,若当x大于1.0时,表示沿x方向拉伸目标;若x小于1.0,表示沿x 轴方向收缩目标;若x=-1.0表示沿x轴反射目标。其中参数为负值时表示对目标进行相应轴的反射变换。 四、总体设计与功能实现 4.1 主要界面设计 4.2 设置颜色界面 4.2.1 界面设置代码: void CGraphicsView::OnClock() { WHAT_TO_DO=ID_CLOCK; clean(); int xx = 450, yy = 300, r = 150,d = 5; int i, white = RGB (255,255,255); mile (xx, yy, r, COLOR); Matrix m (xx, 240), s (xx, 200); Matrix t1 (xx, yy, true), t2 (-xx, -yy, true), mr ( PI/1800 ), sr ( PI/30 ); mile (m.getx (), m.gety (), d+1, COLOR); mile (s.getx (), s.gety (), d, COLOR); dne ( m.getx (), m.gety (), xx, yy, COLOR ); dne ( s.getx (), s.gety (), xx, yy, COLOR ); for (i=0;i<120;i++){ ::Sleep (80); mile (m.getx (), m.gety (), d+1, white); mile (s.getx (), s.gety (), d, white); dne ( m.getx (), m.gety (), xx, yy, white ); dne ( s.getx (), s.gety (), xx, yy, white ); m = t1*mr*t2*m; s = t1*sr*t2*s; mile (m.getx (), m.gety (), d+1, COLOR); mile (s.getx (), s.gety (),d, COLOR); dne ( m.getx (), m.gety (), xx, yy, COLOR ); dne ( s.getx (), s.gety (), xx, yy, COLOR );}} 4.2.2 点击“设置--颜色”后,运行结果如下: 4.3 二维线画图元实现 4.3.1 实现代码: void CGraphicsView::MidCir(CDC *pdc, int x0, int y0, int x1, int y1, int color) { int r,x,y,deltax,deltay,d; r=sqrt(((double)x1-(double)x0)*((double)x1-(double)x0)+((double)y1-(double)y0 )*((double)y1-(double)y0)); x=0; y=r; deltax=3; deltay=2-r-r; d=1-r; while(x<=y) { ::Sleep(time); pdc->SetPixel(x+x0,y+y0,color); ::Sleep(time); pdc->SetPixel(-x+x0,y+y0,color); ::Sleep(time); pdc->SetPixel(x+x0,-y+y0,color); ::Sleep(time); pdc->SetPixel(-x+x0,-y+y0,color); ::Sleep(time); pdc->SetPixel(y+x0,x+y0,color); ::Sleep(time); pdc->SetPixel(-y+x0,x+y0,color); ::Sleep(time); pdc->SetPixel(y+x0,-x+y0,color); ::Sleep(time); pdc->SetPixel(-y+x0,-x+y0,color); if(d<0) { d+=deltax; deltax+=2; x++;} else { d+=deltax+deltay; deltax+=2; deltay+=2; x++; y--; }}} void CGraphicsView::midellispse(int xx, int yy, int r1, int r2, int color) { } void CGraphicsView::Ellipse(CDC *pdc, int x1, int y1, int x2, int y2, int color) { xx0=(x2+x1)/2; yy0=(y2+y1)/2; rra=abs(x2-x1)/2; rrb=abs(y2-y1)/2; if(rra==0 && rrb==0) return; Ellipse0(pdc,xx0,yy0,rra,rrb,color);} void CGraphicsView::Ellipse0(CDC *pdc, int x0, int y0, int a, int b, int color) { int i,yy; int x,y,deltax,deltay; int aa,aa2,aa3,bb,bb2,bb3; double d1,d2; aa=a*a; aa2=aa*2; aa3=aa*3; bb=b*b; bb2=bb*2; bb3=bb*3; x=0; y=b; d1=bb+aa*(-b+0.25); deltax=bb3; deltay=-aa2*b+aa2; pdc->SetPixelV(x+x0,y+y0,color); pdc->SetPixelV(x+x0,-y+y0,color); while(bb*(x+1) { yy=y; if(d1<0) { d1+=deltax; deltax+=bb2; x++;} else { d1+=deltax+deltay; deltax+=bb2; deltay+=aa2; x++; y--;} ::Sleep(time); pdc->SetPixelV(x+x0,y+y0,color); ::Sleep(time); pdc->SetPixelV(-x+x0,y+y0,color); ::Sleep(time); pdc->SetPixelV(x+x0,-y+y0,color); ::Sleep(time); pdc->SetPixelV(-x+x0,-y+y0,color);} d2=bb*(x+0.5)*(x+0.5)+aa*(y-1)*(y-1)-aa*bb; deltax-=bb; deltay+=aa; while(y>0) { if(d2<0) { d2+=deltax+deltay; deltax+=bb2; deltay+=aa2; x++; y--; } else { d2+=deltay; deltay+=aa2; y--; } ::Sleep(time); pdc->SetPixelV(x+x0,y+y0,color); ::Sleep(time); pdc->SetPixelV(-x+x0,y+y0,color); ::Sleep(time); pdc->SetPixelV(x+x0,-y+y0,color); ::Sleep(time); pdc->SetPixelV(-x+x0,-y+y0,color); }} void CGraphicsView::DDALine(CDC *pdc, int x0, int y0, int x1, int y1, int color) { int xx,yy,s,s1,s2,di; float dx,dy,k,x,y; dx=x1-x0; if(dx>=0) s1=1; else s1=-1; dy=y1-y0; if(dy>=0) s2=1; else s2=-1; dx=abs(dx); dy=abs(dy); if(dx>=dy) { s=0; di=(int)dx; k=dy/dx*s2;} else { s=1; di=(int)dy; k=dx/dy*s1;} x=x0; y=y0; for(int i=0;i<=di;i++) {if(s==0) { xx=(int)x; yy=(int)(y+0.5); ::Sleep(time); pdc->SetPixel(xx,yy,color); x+=s1; y+=k;} else{ xx=(int)(x+0.5); yy=(int)y; ::Sleep(time); pdc->SetPixel(xx,yy,color); y+=s2; x+=k;}}} 4.3.2 点击二维线画图元,课相应画出直线、圆和椭圆,结果如下: 4.4 画多边形功能的实现 4.4.1 部分实现代码: void CGraphicsView::OnDrawDuoBX() { Vertex_Count dlg; if(dlg.DoModal()==IDOK) { if(dlg.m_vertex_count>MAX) { MessageBox("输入顶点数过大"); return; } VertexTotal=dlg.m_vertex_count; CDC *pDC=GetDC(); CPen pen(PS_SOLID,2,RGB(255,255,255)); CPen *pOldpen=pDC->SelectObject(&pen); pDC->MoveTo((int)(inVertexArray[0].x+0.5),(int)(inVertexArray[0].y+0.5)); int i; for(i=1;i pDC->LineTo((int)(inVertexArray[i].x+0.5),(int)(inVertexArray[i].y+0.5)); pDC->LineTo((int)(inVertexArray[0].x+0.5),(int)(inVertexArray[0].y+0.5)); pDC->SelectObject(pOldpen); ReleaseDC(pDC); inLength=0; outLength=0; WHAT_TO_DO=ID_DrawDuoBX;}} 4.4.2 点击多边形,输入定点个数,可绘制出相应的多边形,结果如下: 4.5 画Bezier曲线功能的实现 4.5.1 部分实现代码: void CGraphicsView::OnBezier() { // TODO: Add your command handler code here WHAT_TO_DO=ID_BEZIER; CDC *p=GetDC (); p->TextOut (10, 20, "PS:鼠标左键添加曲线,鼠标右键修改曲线."); ReleaseDC (p);} void CGraphicsView::OnBezierClear() { n = -1; RedrawWindow();} void CGraphicsView::DrawBezier(DPOINT *p) { if (n <= 0) return; if((p[n].x < p[0].x+1) && (p[n].x > p[0].x-1) && (p[n].y < p[0].y+1) && (p[n].y > p[0].y-1)) { pDC->SetPixel(p[0].x, p[0].y, COLOR); return; } DPOINT *p1; p1 = new DPOINT[n+1]; int i, j; p1[0] = p[0]; for(i=1; i<=n; i++) { for(j=0; j<=n-i;j++) { p[j].x = (p[j].x + p[j+1].x)/2; p[j].y = (p[j].y + p[j+1].y)/2; } p1[i] = p[0];} DrawBezier(p); DrawBezier(p1); delete p1; } void CGraphicsView::OnBezierAdd() { AddorMove = 1; } void CGraphicsView::OnBezierMove() { AddorMove = -1;} void CGraphicsView::OnMouseMove(UINT nFlags, CPoint point) { switch(WHAT_TO_DO) { case ID_BEZIER: { if(current >= 0 ) { points[current].x = point.x; points[current].y = point.y; RedrawWindow();} if(current2 >= 0 ) { points[current2].x = point.x; points[current2].y = point.y; RedrawWindow();} break; } default:break;} CView::OnMouseMove(nFlags, point);} 4.5.2 点击曲线--Beizer曲线,可实现Beizer曲线的绘制功能,绘制结果如下图: 图 1 图 2 4.5.3 点击曲线--Beizer曲线,可实现Beizer曲线的移动,鼠标点击其中的任一点,可实现曲线的移动,绘制结果如下图: 上图1移动后的曲线 上图2移动后的曲线 4.6 二维图形变换的实现 可以实现一椭圆在界面上的随机移动,一圆在界面上饶某一点的旋转和一正方形由大变小在变大的变化,部分实现代码如下: void CGraphicsView::OnXuanzhuan() { WHAT_TO_DO=ID_XUANZHUAN; time=0; OnClear(); CClientDC dc(this); CDC* pDC=&dc; int i, white=RGB(255,255,255), point [2][2]={{300,200},{300,250}}; Matrix a (point[0][0],point[0][1]), b (point[1][0],point[1][1]); int midx=(point[0][0]+point[1][0])/2,midy=(point[0][1]+point[1][1])/2; Matrix t1 (midx, midy,true), t2 (-midx, -midy,true); Matrix r (PI/50); Matrix temp (midx, midy,true); temp = t1*r*t2; for(i=0;i<200;i++){ ::Sleep(50); MidCir(pDC, a.getx(), a.gety(), b.getx(), b.gety(), white); a = temp*a; b = temp*b; MidCir(pDC, a.getx(), a.gety(), b.getx(), b.gety(), COLOR); } for(i=0;i<200;i++){ ::Sleep(50); MidCir ( pDC,a.getx(), a.gety(), b.getx(), b.gety(), white); a = temp*a; b = temp*b; MidCir (pDC, a.getx(), a.gety(), b.getx(), b.gety(), COLOR); } time=5;} void CGraphicsView::OnUpdateXuanzhuan(CCmdUI* pCmdUI) { pCmdUI->SetCheck(WHAT_TO_DO==ID_XUANZHUAN);} void CGraphicsView::OnScale() { WHAT_TO_DO=ID_SCALE; OnClear(); CClientDC dc(this); CDC* pDC=&dc; time=0; int i,white=RGB(255,255,255), point[4][2]={{300,250},{400,250},{300,300},{400,300}}; float sx=0.9,sy=0.85; int midx=(point[0][0]+point[3][0])/2,midy=(point[0][1]+point[3][1])/2; Matrix s1 (sx,sy),s2 (1/sx,1/sy); Matrix t1 (midx, midy,true), t2 (-midx, -midy,true); Matrix a (point[0][0],point[0][1]), b (point[1][0],point[1][1]); Matrix c (point[2][0],point[2][1]), d (point[3][0],point[3][1]); Matrix temp (midx, midy,true); temp = t1*s1*t2; DDALine (pDC,a.getx(),a.gety(),b.getx(),b.gety(),COLOR); DDALine (pDC,a.getx(),a.gety(),c.getx(),c.gety(),COLOR); DDALine (pDC,c.getx(),c.gety(),d.getx(),d.gety(),COLOR); DDALine (pDC,d.getx(),d.gety(),b.getx(),b.gety(),COLOR); for(i=0;i<20;i++){ ::Sleep (30); DDALine (pDC,a.getx(),a.gety(),b.getx(),b.gety(),white); DDALine (pDC,a.getx(),a.gety(),c.getx(),c.gety(),white); DDALine (pDC,c.getx(),c.gety(),d.getx(),d.gety(),white); DDALine (pDC,d.getx(),d.gety(),b.getx(),b.gety(),white); a=temp*a; b=temp*b; c=temp*c; d=temp*d; DDALine (pDC,a.getx(),a.gety(),b.getx(),b.gety(),COLOR); DDALine (pDC,a.getx(),a.gety(),c.getx(),c.gety(),COLOR); DDALine (pDC,c.getx(),c.gety(),d.getx(),d.gety(),COLOR); DDALine (pDC,d.getx(),d.gety(),b.getx(),b.gety(),COLOR);} temp = t1*s2*t2; for(i=0;i<20;i++){ ::Sleep (30); DDALine (pDC,a.getx(),a.gety(),b.getx(),b.gety(),white); DDALine (pDC,a.getx(),a.gety(),c.getx(),c.gety(),white); DDALine (pDC,c.getx(),c.gety(),d.getx(),d.gety(),white); DDALine (pDC,d.getx(),d.gety(),b.getx(),b.gety(),white); a=temp*a; b=temp*b; c=temp*c; d=temp*d; DDALine (pDC,a.getx(),a.gety(),b.getx(),b.gety(),COLOR); DDALine (pDC,a.getx(),a.gety(),c.getx(),c.gety(),COLOR); DDALine (pDC,c.getx(),c.gety(),d.getx(),d.gety(),COLOR); DDALine (pDC,d.getx(),d.gety(),b.getx(),b.gety(),COLOR); } time=5;} void CGraphicsView::OnUpdateScale(CCmdUI* pCmdUI) { pCmdUI->SetCheck(WHAT_TO_DO==ID_SCALE);} 4.7 三维图形的变换 主要实现三维图形的上下左右平移,分别绕X轴Y轴Z轴的旋转,放大和缩小,以及正方体 六个面的颜色变换,除此之外,还可以选择背景颜色的改变 4.7.1 部分代码如下: void CGraphicsView::OnAoduomianti() { WHAT_TO_DO=ID_AODUOMIANTI; CDrawDLG dlg1; dlg1.DoModal();} void CGraphicsView::OnUpdateAoduomianti(CCmdUI* pCmdUI) { pCmdUI->SetCheck(WHAT_TO_DO==ID_AODUOMIANTI);} void CDrawDLG::OnPaint() { CPaintDC dc(this); // device context for painting CWnd *pWnd=GetDlgItem(IDC_DRAW); pWnd->UpdateWindow(); // CDC *PDC=pWnd->GetDC(); Draw();} void CDrawDLG::Draw() { CWnd *pWnd=GetDlgItem(IDC_DRAW); pWnd->UpdateWindow(); CDC *pDC=pWnd->GetDC(); CRect rect; pWnd->GetClientRect(rect); D v[8]={ {-fs,-fs,fs},{-fs,fs,fs},{fs,fs,fs},{fs,-fs,fs},{-fs,-fs,-fs},{-fs,fs,-fs},{f s,fs,-fs},{fs,-fs,-fs} },d[8]; POINT p0[4],p1[4],p2[4],p3[4],p4[4],p5[4],w[8]; int z[8]; for (int i=0; i<8; i++) { d[i].x=v[i].x; d[i].y=(int)(v[i].y*cos(a*DU)-v[i].z*sin(a*DU)); d[i].z=(int)(v[i].y*sin(a*DU)+v[i].z*cos(a*DU)); v[i].x=(int)(d[i].x*cos(b*DU)+d[i].z*sin(b*DU)); v[i].y=d[i].y; v[i].z=(int)(d[i].z*cos(b*DU)-d[i].x*sin(b*DU)); d[i].x=(int)(v[i].x*cos(c*DU)-v[i].y*sin(c*DU)); d[i].y=(int)(v[i].x*sin(c*DU)+v[i].y*cos(c*DU)); d[i].z=v[i].z; w[i].x=d[i].x+cx; w[i].y=d[i].y+cy; z[i]=d[i].z;} p0[0]=w[0];p0[1]=w[1];p0[2]=w[2];p0[3]=w[3]; p1[0]=w[4];p1[1]=w[5];p1[2]=w[6];p1[3]=w[7]; p2[0]=w[0];p2[1]=w[1];p2[2]=w[5];p2[3]=w[4]; p3[0]=w[1];p3[1]=w[2];p3[2]=w[6];p3[3]=w[5]; p4[0]=w[2];p4[1]=w[3];p4[2]=w[7];p4[3]=w[6]; p5[0]=w[0];p5[1]=w[3];p5[2]=w[7];p5[3]=w[4]; switch (Maxnum(z,7)) { case 0:fill(p0,p2,p5,0,2,5);break; case 1:fill(p0,p2,p3,0,2,3);break; case 2:fill(p0,p3,p4,0,3,4);break; case 3:fill(p0,p4,p5,0,4,5);break; case 4:fill(p1,p2,p5,1,2,5);break; case 5:fill(p1,p2,p3,1,2,3);break; case 6:fill(p1,p3,p4,1,3,4);break; case 7:fill(p1,p4,p5,1,4,5);break;}} BOOL CDrawDLG::OnInitDialog() { CDialog::OnInitDialog(); m_scroll1.SetScrollRange(-180,180); m_scroll1.SetScrollPos(0); m_scroll2.SetScrollRange(-180,180); m_scroll2.SetScrollPos(0); m_scroll3.SetScrollRange(-180,180); m_scroll3.SetScrollPos(0); m_scroll4.SetScrollRange(0,350); m_scroll4.SetScrollPos(200); m_scroll5.SetScrollRange(0,300); m_scroll5.SetScrollPos(115); m_scroll6.SetScrollRange(0.00,300.00); m_scroll6.SetScrollPos(50.00); a=b=c=0; fs=50.00; SetTimer(1,100,NULL); Ctrl=0; cx=200; cy=115; COLOR1=RGB(123,234,43); COLOR2=RGB(123,123,0); COLOR3=RGB(123,24,235); COLOR4=RGB(0,123,95); COLOR5=RGB(23,234,34); COLOR6=RGB(234,124,0); COLOR7=RGB(0,43,98); return TRUE; // return TRUE unless you set the focus to a control} void CDrawDLG::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { int nID=pScrollBar->GetDlgCtrlID(); switch(nID) { case IDC_SCROLLBAR1: a=pScrollBar->GetScrollPos(); switch (nSBCode) { case SB_LINELEFT: a--;break; case SB_PAGELEFT: a-=10;break; case SB_PAGERIGHT: a+=10;break; case SB_THUMBTRACK: a=nPos;break; } if (a<-180)a=180; if (a>180)a=-180; pScrollBar->SetScrollPos(a); break; case IDC_SCROLLBAR2: b=pScrollBar->GetScrollPos(); switch (nSBCode) { case SB_LINELEFT: b--;break; case SB_LINERIGHT: b++;break; case SB_PAGELEFT: b-=10;break; case SB_PAGERIGHT: b+=10;break; case SB_THUMBTRACK: b=nPos;break; } if (b<-180)b=180; if (b>180)b=-180; pScrollBar->SetScrollPos(b); break; case IDC_SCROLLBAR3: c=pScrollBar->GetScrollPos(); switch (nSBCode) { case SB_LINELEFT: c--;break; case SB_LINERIGHT: c++;break; case SB_PAGELEFT: c-=10;break; case SB_PAGERIGHT: c+=10;break; case SB_THUMBTRACK: c=nPos;break; } if (c<-180)c=180; if (c>180)c=-180; pScrollBar->SetScrollPos(c); break; case IDC_SCROLLBAR4: cx=pScrollBar->GetScrollPos(); switch (nSBCode) { case SB_LINELEFT: cx--;break; case SB_LINERIGHT: cx++;break; case SB_PAGELEFT: cx-=10;break; case SB_PAGERIGHT: cx+=10;break; case SB_THUMBTRACK: cx=nPos;break;} if (cx<0)cx=200; if (cx>350)cx=200; pScrollBar->SetScrollPos(cx); break; case IDC_SCROLLBAR5: cy=pScrollBar->GetScrollPos(); switch (nSBCode) { case SB_LINELEFT: cy--;break; case SB_PAGELEFT: cy-=10;break; case SB_PAGERIGHT: cy+=10;break; case SB_THUMBTRACK: cy=nPos;break; } if (cy<0)cy=300; if (cy>300)cy=0; pScrollBar->SetScrollPos(cy); break; case IDC_SCROLLBAR6: fs=pScrollBar->GetScrollPos(); switch (nSBCode) { case SB_LINELEFT: fs--;break; case SB_LINERIGHT: fs++;break; case SB_PAGELEFT: fs-=0.55;break; case SB_PAGERIGHT: fs+=0.55;break; case SB_THUMBTRACK: fs=nPos;break; } if (fs<0)fs=50; if (fs>300)fs=50; pScrollBar->SetScrollPos(fs); break; // UpdateData(FALSE);} // Invalidate(); Draw(); CDialog::OnHScroll(nSBCode, nPos, pScrollBar);} void CDrawDLG::OnOK() { KillTimer(1); CDialog::OnOK();} int CDrawDLG::Maxnum(int *p, int n) { int max=p[0]; int x; for (int i=0; i<=n;i++) { if (max<=p[i]) { max=p[i]; x=i; } } return x;} void CDrawDLG::fill(POINT *x, POINT *y, POINT *z, int i,int j,int q) { CWnd *pWnd=GetDlgItem(IDC_DRAW); pWnd->UpdateWindow(); CDC *pDC=pWnd->GetDC(); CRect rect; pWnd->GetClientRect(rect); CDC dcmem; dcmem.CreateCompatibleDC(pDC); CBitmap bmp,*oldbmp; bmp.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());