C#交互绘图技术_第1页
C#交互绘图技术_第2页
C#交互绘图技术_第3页
C#交互绘图技术_第4页
C#交互绘图技术_第5页
已阅读5页,还剩31页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第5章交互绘图技术5.1窗口系统和事件驱动模式5.2交互式的显示控制技术5.3交互式的图形生成技术5.4交互式的图形编辑技术5.5OpenGL对图形交互的支持5.1窗口系统和事件驱动模式Windows操作系统是一个窗口式的多任务操作系统,在Windows环境下编写应用程序,采用事件驱动机制。传统的MS-DOS程序主要采用顺序的、关联的、过程驱动的程序设计方法。一个程序是一系列预先定义好的操作序列的组合,它具有一定的开头、中间过程和结束。程序直接控制事件和过程的顺序。这样的程序设计方法是面向程序而不是面向用户的,交互性差,用户界面不够友好,因为它强迫用户按照某种不可更改的模式进行工作。它的基本模型如图所示。DOS环境下编程模式

事件驱动程序设计模式对于需要用户交互的应用程序来说,事件驱动的程序设计有着过程驱动方法无法替代的优点。它是一种面向用户的程序设计方法,它在程序设计过程中除了完成所需功能之外,更多的考虑了用户可能的各种输入,并针对性的设计相应的处理程序。它是一种“被动”式程序设计方法,程序开始运行时,处于等待用户输入事件状态,然后取得事件并作出相应反应,处理完毕又返回并处于等待事件状态。它的基本模型如图所示。事件驱动程序设计模式Windows下基于消息的事件驱动编程消息MSG结构是Windows的一种数据结构,包含消息的窗口来源、消息种类、与此消息相关的附加信息、消息发生时鼠标的位置等。接收和处理消息的是窗口,每个窗口都有一个专门负责处理消息的“窗口函数”。MFC中的事件驱动编程

微软基础类库(MFC:MicrosoftFoundationClass)是微软为Windows程序员提供的一个面向对象的Windows编程接口,它大大简化了Windows编程工作。MFC通过定义一个消息与处理函数的对照表,实现了消息处理的分离编程。每当产生一个事件,便可以通过这个对照表找到相应的消息处理函数,执行这个函数便完成了相应的功能;这样,程序员不再需要编写庞大的窗口函数。因此需要一类特殊的对象,每个对象负责在不同状态之下根据自己的任务完成工作,称这些类为功能类,具有以下共同特点:都具有接收键盘,鼠标消息的外部接口都应提供一个初始化工作的外部接口Initalize都应提供一个做扫尾工作的外部接口Suspend都应提供接收自己将被删除的消息的外部接口Kill提供恢复临时的场景的外部接口Draw提供外部接口以完成被重新唤醒之后需要进行的操作WakeUp每个功能类有相同的祖先,设计为虚接口VirtualFunction这种机制可是实现模块分解和分工写作,实现思想:从BaseFunction派生出一个新类,重载其中某些接口就可以完成具体的功能每个从BaseFunction派生出的新类只需负责自己的工作每个不同的功能类可以由不同的的单独开发而不影响系统的集成文档类(MFC体系)中设置功能类对象的队列,包含当前正在运转的功能类对象和之前运转过的对象从一种状态A转换到另一种状态B需要传剑一个新的功能类的对象b(B类对象),然后将b作为参数调用文档的一个外部接口SetCurrentFunction,完成状态转换SetCurrentFunction:调用被挂起对象的Kill外部接口;调用队列中当前功能类对象的Suspend外部接口;最后调用b的外部接口Initalize,将b压进队列,成为当前功能类对象当视图接受到鼠标键盘消息,将此消息分发给文档类中维护的当前功能类对象。5.2交互式的显示控制技术全景显示旋转平移缩放

本节内容为交互绘图平台与显示相关的控制技术,以上机实现为主。场景充满窗口的控制方法//得到场景分布区域的宽度ExtendPoint3DMax,Min;PSceneData->GetBox(Max,Min);//设置视距viewDisatance=Max.Distance(&Min)*15;//求出场景中心点middlePoint,作为显示中心点,保证场景能够显示在屏幕中心middlePoint=(Max+Min)/2;//求出场景分布区域x方向的长度dX_Extend和y方向的长度dY_ExtendPSceneData->GetBox(Max,Min);doubleExtend=Max.Distance(&Min);doubledX_Extend=Extend;doubledY_Extend=Extend;//再根据窗口的宽高比及Y方向的长度,得到X方向的适合窗口宽高比的长度dTmpX_ExtendDoubledTmpX_Extend=dY_Extend*m_dAspectRatio;//设置near平面和far平面nearestPlaneDistance=viewDistance-Extend/2;farestPlaneDistance=viewDistance+Extend/2;//设置视宽为X方向长度及Y方向的适合窗口宽高比的长度中小者//保证场景在X方向及Y方向都不会超出视景体viewWidth=max(dX_Extend,dTmpX_Extend)/1.1;//刷新窗口Invalidate();OnLButtonDown(msg){ m_LeftButtonDown=TRUE; m_LeftDownPos=GetMouseLocation(); m_CenterPoint=GetCenterPont(); m_ViewPoint=GetViewPoint();}OnLButtonUp(msg){ m_LeftButtonDown=FALSE;}OnMouseMove(msg){ intdx,dy; dx=m_LeftDownPos.x-GetMouseLocation().x; dy=m_LeftDownPos.y-GetMouseLocation().y; m_LeftDownPos=GetMouseLocation(); VP=m_ViewPoint-m_CenterPoint; doublealfa=3.14*dx/GetClientRect().right; SetViewDirection()VP; m_ViewPoint=GetViewPoint();

Invalidate();}m_LeftButtonDown用来标志鼠标左键是否已被按下。m_LeftDownPos记录上次鼠标移动事件中鼠标的位置,用来计算两次鼠标移动的距离。m_CenterPoint,Point3D类型,显示中心点的坐标m_ViewPoint,Point3D类型,视点的位置当按下鼠标左键,旋转操作开始:设标志m_LeftButtonDown为真,表示已经处于旋转状态;记下此时鼠标指针的位置,放在m_LeftDownPos中,用来在鼠标移动事件中计算两次鼠标位置的移动距离,从而计算出场景旋转的尺度;将此时场景的显示中心点记入m_CenterPoint中,将视点位置记入m_ViewPoint中。当鼠标移动时,旋转功能类首先判断鼠标左键是否已按下,这可以根据m_LeftButtonDown的值来确定。若鼠标左键未按下,则不做任何处理,否则,做如下工作:分别计算上次鼠标位置与现在鼠标位置在x,y方向的距离,根据这两个距离计算场景应旋转的尺度,然后按照这个尺度将视图原来的实现方向(视点减去参考点所得向量)进行旋转,得到新的视线方向VP,并将视图的视线方向修改为新的值。然后刷新视图。当视图刷新时,会根据视点、显示中心点、视线方向等参数自动调整场景的外观。当鼠标左键抬起时,表示旋转动作结束。旋转功能类将标志m_LeftButtonDown的值设置FALSE平移操作:OnLButtonDown(msg){ m_LeftButtonDown=TRUE; //确认鼠标左键是否已被按下。

oldCenterPoint=GetCenterPont();//中心点的位置

m_LeftDownPos=GetMouseLocation();//上次鼠标移动事件中鼠标的位置}OnLButtonUp(msg){ m_LeftButtonDown=FALSE;}OnMouseMove(msg){ if(m_LeftButtonDown) {MouseLocation=GetMouseLocation(); oldPoint=GetWorldCrdByScreenCrd(m_LeftDownPos); newPoint=oldCenterPoint+(GetWorldCrdByScreenCrd(MouseLocation))-oldPoint; Invalidate(); }}设标志m_LeftButtonDown为真,表示已经处于旋转状态;记下此时鼠标指针的位置,放在m_LeftDownPos中,用来在鼠标移动事件中计算两次鼠标位置的移动距离,从而计算出视图平移的尺度;将此时场景的显示中心点记入oldCenterPoint中当鼠标移动时,视图平移功能类首先判断鼠标左键是否已按下,这可以根据m_LeftButtonDown的值来确定。若鼠标左键按下,计算上次鼠标位置对应的世界坐标,计算本次鼠标位置对应的世界坐标,求得两次鼠标位置在世界坐标系中的距离向量,将此向量加到场景的显示中心点上,得到场景新的显示中心点。最后刷新场景。缩放操作OnLButtonDown(msg){ m_LeftButtonDown=TRUE; //确认鼠标左键是否已被按下。

m_LeftDownPos=GetMouseLocation();//上次鼠标移动事件中鼠标的位置

oldWidth=GetCenterWidth();//缩放之前视口的宽度}OnLButtonUp(msg){ m_LeftButtonDown=FALSE;}OnMouseMove(msg){ if(m_LeftButtonDown) { dy=m_LeftDownPos.y-GetMouseLocation().y; ScalingFactor=dy/msg.GetView()->GetClientRect().bottom; newWidth=oldWidth*(1+ScalingFactor); SetViewWidth(newwidth); InvalidateRect(NULL,FALSE); }}5.3交互式的图形生成技术

坐标的输入技术将二维计算机屏幕的鼠标位置转换为三维世界坐标。

橡皮筋技术实现橡皮筋技术主要有两种方法:基于异或操作的橡皮筋技术;基于缓冲区的橡皮筋技术;5.4交互式的图形编辑技术利用鼠标动作来改变图形选中图形的方法5.4交互式的图形编辑技术5.4交互式的图形编辑技术图形元素拾取办法:静态选择功能类动态选择功能类5.4交互式的图形编辑技术静态选择功能类伪代码实现:(1)构造函数m_pElementSet=pElementSet;//接收外部提供的待选择图元集合m_pElement=pElement;//接受外部提供的预选取对象If(m_pElement!=NULL)SetSelectedElement(m_pElement)//将用户指定的默认选中元素赋给成员变量,并高亮显示默认被选中元素5.4交互式的图形编辑技术(2)数据成员ElementSet*m_pElementSet;//图形元素集合,将从这些图元中挑出被选中者,放到m_pElement中Element*m_pElement;//将被选中的图元放在这个成员变量中(3)鼠标左键处理//利用某种机制从待选择元素集合中选择出鼠标指向的图形元素Element*pEI=GetElementFromSelection(m_pElementSet,GetMouseLocation());If(pEI==m_pSelectedElement)return;//恢复屏幕背景,然后高亮显示被选中的元素。If(pEI!=NULL)SetSelectedElement(pEI);5.4交互式的图形编辑技术动态选择功能类(1)数据成员ElementSet*m_pElementSet;//图形元素集合,将从这些图元中挑出被选中者,放到m_pElement中Element*m_pElement;//将被选中的图元放在这个成员变量中(2)鼠标移动处理//利用某种机制从待选择元素集合中选择出鼠标指向的图形元素Element*pEI=GetElementFromSelection(m_pElementSet,GetMouseLocation());If(pEI==m_pSelectedElement)return;If(pEI!=NULL)SetSelectedElement(pEI);5.4交互式的图形编辑技术5.5OpenGL对图形交互的支持三维坐标输入--OpenGL提供反向坐标变换(gluUnProject)实现橡皮筋技术--OpenGL的双缓存机制三维图形的编辑及三维目标实体的拾取--OpenGL提供了一种简单直观的选择机制,能够很容易的实现三维场景中任一图形元素的选取。

5.5OpenGL对图形交互的支持

用OpenGL的反向坐标变换实现三维坐标输入

函数gluUnProject能够将Windows屏幕坐标转换为场景中的三维世界坐标。该函数需要指定如下参数:视口的原点(X,Y坐标)及视口宽度(width)与高度(height)当前显示三维场景所使用的模型视图变换矩阵(TheModelviewMatrix)当前显示三维场景所使用的投影变换矩阵(TheProjectionMatrix)Windows窗口坐标存储三维坐标的变量(posX,posY,posZ)5.5OpenGL对图形交互的支持视口信息:获得视口左上角坐标(x,y)和视口宽度

width及高度height Glintviewport[4];//存储视口相关信息glGetIntegerv(GL_VIEWPORT,viewport);//检索(x,y,width,height)调用成功后viewport数组四个元素将分别为x,y,width,height模型视图变换矩阵:OpenGL图元顶点的世界坐标如何变换到视坐标。

GLdoublemodelview[16];//存储模型视图变换矩阵的16个值

glGetDouble(GL_MODELVIEW_MATRIX,modelview) //检索模型视图矩阵5.5OpenGL对图形交互的支持投影矩阵:将顶点的视坐标变换为剪裁坐标

GLdoubleprojection[16];//存储投影矩阵的16个值

glGetDouble(GL_PROJECTION_MATRIX,projection) //检索模型视图矩阵

5.5OpenGL对图形交互的支持Windows屏幕坐标:为要变换撑三维坐标的数据来源,了解当前鼠标的位置CPointmouse;::GetCursorPos(&mouse);ScreenToClient(hWnd,&mouse);GLfloatwinX,winY,winZ;winX=(float)mouse.x;winY=(float)mouse.y;因为Windows窗口(0,0)从左上角开始,而OpenGL从左下角开始,所以winY=(float)viewport[3]-winY;winZ:通过glReadPixel(winX,winY,1,1,GL_DEPTH_COMPONENT,GL_GLOAT,&winZ)得到5.5OpenGL对图形交互的支持存储三维坐标的变量进行方向坐标变换实现三维坐标输入的完整子程序:Point3DGetOGLPos(intx

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论