CAD应用程序开发详解——Visual C++与OpenGL综合应用(txt+pdf+epub+mobi电子书下载)


发布时间:2020-10-11 20:01:57

点击下载

作者:王清辉,李静蓉

出版社:电子工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

CAD应用程序开发详解——Visual C++与OpenGL综合应用

CAD应用程序开发详解——Visual C++与OpenGL综合应用试读:

版权信息书名:CAD 应用程序开发详解:Visual C++与 OpenGL 综合应用作者:王清辉,李静蓉编著排版:SEYUE出版社:电子工业出版社出版时间:2012-09-01ISBN:9787121179709本书由电子工业出版社授权北京当当科文电子商务有限公司制作与发行。— · 版权所有 侵权必究 · —第1章三维CAD软件的系统框架分析本章要点:• 关于微软基础类库MFC。• MFC应用程序的文档/视图结构概述。• 三维CAD应用程序的模块化结构分析。• 动态链接库的创建、使用、层次关系。1.1 关于微软基础类MFC

在VisualC++2.0以后的版本中,Microsoft公司推出了MFC(Microsoft Foundation Class)类库。MFC随微软Visual C++ 开发平台发布,以一系列C++类集的形式提供给程序设计人员使用,为程序员提供一个面向对象的Windows编程接口。MFC的实质是提供了一种基于Windows系统的应用程序框架(Application Framework),该框架具有高效运行的特性,也是一些资深的程序员认为无所不能的开发工具。使用MFC类库的好处是,可以简化应用程序的开发,从而缩短开发周期,而且代码的可靠性和可重用性也大大提高。首先,MFC提供了一个标准化的应用程序框架,这样开发人员不必从头设计创建和管理一个标准Windows应用程序所需的所有代码,而是“站在巨人肩膀上”,从一个比较高的起点编程,故节省了大量的时间;其次,它提供了大量的代码,指导用户编程时实现某些技术和功能。对用户来说,用MFC开发的最终应用程序具有标准的、熟悉的Windows界面,这样的应用程序易学易用;另外,新的应用程序还能立即支持所有标准Windows特性,而且是用普通的、明确定义的形式。很多读者可能已经有了使用MFC的经验,并对MFC编程有了浓厚的兴趣。这里,我们首先从分析MFC的应用程序框架开始,分析如何采用面向对象的技术来设计CAD软件的程序框架和软件模块结构。

什么是应用程序框架?一种定义是“提供一个一般应用程序所需要的全部面向对象的软件组件的集合”。应用程序框架设计的好坏与否,直接决定了程序功能的实现难易程度和软件开发与维护的代价高低。任何一个应用程序从本质上来说都是对数据的操作,因此,一个好的程序框架结构就意味着对应用数据管理上的友好安全和处理上的简便通用。应用程序框架的实例很多,工程应用的计算机辅助设计/制造/分析(Computer Aided Design/ Manufacturing/ Engineering,CAD/CAM/CAE)软件多采用文档与视图相结合的程序框架。本章将结合MFC提供的应用程序的文档/视图结构这一工程软件的常见框架进行阐述和分析。为了便于阐述,在本书中,作者将一个应用于快速原型制造系统(Rapid Prototyping Manufacturing,RPM)的CAD/CAM软件作了大量简化,去除了主要的专业功能,使之成为一个浅显易懂的三维CAD示例软件贯穿全书,整个软件系统和模块设计均采用了面向对象的编程技术。在本章中,将具体分析这一三维CAD软件的模块化结构设计,使读者对工程CAD软件的应用程序框架设计有一定的理解和认识;同时,本章也在例程中讲解了基于MFC的有关动态链接库的具体创建和使用过程,以期加强读者的理解和实际开发能力。

以下的各章中,通过循序渐进地介绍,读者将可以对以下主要技术有所掌握:(1)面向对象的编程技术。(2)软件的结构及模块化设计。(3)动态链接库的开发与应用。(4)几何计算基础类库的开发。(5)CAD软件的界面设计和交互操作。(6)CAD系统的几何内核设计。(7)基于OpenGL的CAD模型显示。(8)开发面向Windows应用程序的OpenGL C++类库等。1.2 MFC应用程序的文档/视图结构1.2.1 文档/视图结构概述

MFC中的文档/视图结构(Document/View Architecture)是MFC的精髓,它的基本思想是实现模型数据与显示交互的相互分离。文档(Document)负责管理模型,视图(View)负责模型的显示与交互操作。文档/视图结构通过将模型和视图的分开表示,提供了很好的数据层次和表现层次的解耦。在具体实现上,MFC提供了两种典型且实用的基于文档与视图的应用程序框架模板,按照其应用程序生成向导的导引步骤(MFC AppWizard)就可以创建所需的基于文档/视图结构的MFC应用程序框架。在此框架的基础上,设计和插入相关的对象,就可以实现交互式的用户界面、几何模型的管理和操作、图形图像的显示,以及其他各种专业功能。

在MFC的文档/视图结构的应用程序框架中,文档类和视图类是成对出现的。文档用于管理应用程序的模型,而模型则封装了数据并提供对数据的操作接口;视图用于显示文档中的模型,并接收用户请求处理与用户的交互信息。模型是独立的;而视图依赖于模型,它从模型获取数据进行显示,并向模型发送用户请求,根据返回结果刷新视图显示。MFC通过文档类和视图类的划分,使数据的存储和显示既相对独立,又相互关联。

在MFC所提供的框架结构中,文档与视图的关系可以由图1-1简要表示。如图1-1所示,MFC中的视图和文档是由视图类(CView class)和文档类(CDocument class)分别表示的。视图类可以调用其本身的成员函数GetDocument(),获得一个指向文档类的指针,从而能够访问文档类中的数据。例如,在视图类的OnDraw() 函数中,视图类通过调用GetDocument() 函数获得一个指向文档类的指针。然后,通过这个指针获取文档类中的数据,并使用CDC类(负责处理应用程序显示设备接口的MFC类)中的函数将这些数据绘制在视图窗口中。视图可以通过图形、图像、文字、表格等多种方式以视图对象(CView object)来显示实际文档(文档对象CDocument object)中的数据。同时,视图对象也负责接收鼠标、键盘等用户输入信息,并通过这些与用户之间的交互信息来操作和修改文档中的数据。图1-1 文档与视图的关系1.2.2 文档与多个视图的关联

使用MFC AppWizard自动创建的MFC应用程序中,为每个文档类的对象创建并关联了一个视图类的对象。实际上,文档和视图的关系可以是一对一的,也可以是一对多的,即一个文档可以关联一个或一个以上的视图,也即可以用多个视图来显示和操作文档中的模型数据。通常,设计不同的视图是为了以不同的方式来显示文档内容,如图形、图表、结构、文字等。然而,当需要用多个视图显示同一个模型时,情况发生了变化:当一个视图修改了模型数据以后,不但本身要刷新显示,其他所有视图也要刷新显示。如果由该视图通知其他视图,它就需要能够找到其他所有视图。每个视图都可能发生修改,这样每个视图都要找到其他所有视图,这种关联过于复杂,不但难以维护,而且不便于增加新的视图。用MFC提供的文档与视图的关联模式,则可以很好地解决上述问题,从而实现由模型通知视图更新,而模型不依赖于具体的视图,而且不同视图之间保持相互独立。

如图1-1所示,一个文档对象就同时关联了多个视图对象。当在一个视图对象中对文档数据作了修改后,可以调用文档类的UpdateAllViews() 函数来更新所有与文档相关联的视图类对象的显示,以此来保持所有视图相对于同一文档数据变化的同步显示。一个文档关联多个视图为应用程序提供了很多的方便。例如,程序中可以使用两个视图,分别以表格和图形的方式来显示文档中的数据,图形显示用户直观的感觉,而用户可以通过表格来访问和操作文档中的具体数据,这种方式在CAD应用程序中较为常用。在CAD程序中,使用一个大的三维图形窗口显示几何模型的同时,通常还会使用一些其他的视图以不同的方式来显示文档数据,例如使用一个树型结构来显示模型的组成结构、属性信息、创建过程等。这样的多视图显示的例子可以参见图1-2,该图显示的是本书中使用的CAD示例软件——STLViewer的主界面。在图形用户界面(Graphic User Interface,GUI)中,左侧浮动窗口是一个树型结构的视图(CTreeView)类的对象,用于显示几何模型的结构与属性;右侧的视图窗口用于模型的OpenGL三维图形绘制和交互操作。这两个视图对象都与同一文档对象(存储几何模型的信息)相关联。在本书第9章还将进一步介绍单文档多视图关系的实现及有关内容。图1-2 STLViewer的主界面(单文档多视图结构)1.2.3 文档模板及主要组成类

MFC中,文档/视图的结构关系是由文档模板(Document Template)定义的。文档模板用于存放与应用程序文档、视图和框架窗口有关的信息。MFC类库提供两种文档模板类,即用于单文档(Single Document Interface,SDI)应用程序的CSingleDocTemplate和用于多文档(Multiple Document Interface,MDI)应用程序的CMultiDocTemplate。CSingleDocTemplate每次只能创建并管理一个文档,而CMultiDocTemplate可以创建并管理多个文档。图1-3和图1-4分别显示了基于MFC单文档和多文档的模板结构。

文档模板的创建和维护是在MFC的应用程序类CWinApp的对象中实现的。在类CWinApp调用成员函数InitInstance() 进行初始化时,必须为应用程序创建一个文档模板对象,并使用函数AddDocTemplate() 向新创建的应用程序加载这个模板。在应用程序对象中,也可以创建并加载多个文档模板。下面列出的代码是在应用程序类CSTLViewerApp(CWinApp的派生类)的成员函数InitInstance()中创建并加载一个单文档模板的例子。图1-3 MFC的单文档的模板序结构图1-4 MFC的多文档的模板结构

由文档模板定义的MFC文档和视图程序框架包括四个主要的类:

• 文档类 CSTLViewerDoc。

• 视图类 CSTLViewerView。

• 主框架类CMainFrame。

• 应用程序类 CSTLViewerApp。

应用程序的主要功能的实现代码分配在这四个主要的类中。MFC AppWizard为每个类自动生成了源文件。以此为基础,开发人员进一步在这些类中插入需要的代码和对象,就可以实现软件的具体功能。下面将对这四个类的主要功能分别加以介绍。1.应用程序类

应用程序类由MFC提供的用程序基类CWinApp所派生,负责从总体上实现对程序的管理,管理从程序开始到结束的全过程,例如程序的初始化、运行,以及进行最后的程序清除工作。MFC的文档/视图结构、程序的主窗口都在应用程序类中定义和创建。基于MFC框架生成的Windows应用程序必须有且仅有一个从 CWinApp 派生的类的对象,在创建窗口之前先构造该对象。2.文档类

文档类是由MFC提供的文档基类CDocument所派生,负责存放应用程序的数据,并管理程序和磁盘文档文件之间的存储与读取。在建立一个CAD系统时,几何模型的数据通常是文档中最主要的数据,应该存放在文档类中。文档类把数据处理从界面中分离出来,同时提供一个与其他对象交互的接口。3.视图类

视图类是由MFC基类CView所派生的,负责显示文档类中的数据,显示的设备可以是计算机屏幕,也可以是打印机或其他设备。视图类还负责处理用户的交互输入,它可以处理多种类型的输入命令,如键盘输入、鼠标输入、菜单及工具栏命令等。在设计一个CAD系统时,屏幕上的图形绘制、打印机的绘图等功能都需要在视图类中开发完成。

不仅如此,视图类还可通过GetDocument()函数来获取文档指针,用之读取和操作文档中的数据,从而实现对文档数据的修改。如前提及,当文档中数据发生变化时,可通过调用CDocument::UpdateAllViews()函数来更新视图的显示内容。

特别值得说明的是,CView是个虚拟类,虚拟类中由于包含了纯虚函数(例如CView::OnDraw()就是一个纯虚函数),它本身不能直接用于声明对象,但在CView中封装了许多对视图进行操作的成员函数,可以被其派生类使用。4.主框架类

主框架窗口也就是应用程序的主窗口,是由主框架类管理。如图1-2、图1-3所示,单文档应用程序和多文档应用程序的主框架类的MFC基类是不同的。对单文档应用程序(SDI),主框架窗口的基类为CFrameWnd类;而在多文档应用程序(MDI)的情况下,其框架窗口所继承的类为CMDIFrameWnd类,文档框架窗口所继承的类则为CMDIChildWnd类,每个文档都有一个文档框架窗口。在用户界面上,一个文档框架窗口至少含有一个视图以显示该文档数据。

主框架窗口还负责管理用户界面对象,如菜单、工具条、状态栏等。每个框架窗口对应管理一个可选的加速键表,改变加速键表的内容就可以自动转换键盘的加速键,这样可以方便地定义调用菜单命令的加速键。

主框架窗口同时管理所有的视图窗口,并跟踪当前活动的视图。当框架窗口含有多个视图窗口时,当前视图就是最近使用的视图。当视图活动改变时,边框窗口通过调用CView的成员函数OnActiveView()来通知当前视图。例如,在如图1-2所示的应用程序界面中,主框架窗口就同时管理了三个视图,分别是左边的树型视图、右边的OpenGL图形显示视图和下边的信息输出视图。1.3 实例分析:三维CAD模型浏览软件STLViewer

本书将结合一个三维CAD软件STLViewer的设计与开发,讲述在MFC环境下使用面向对象的方法设计三维CAD软件的一些技术。包括总体程序框架的分析与设计、功能模块的划分及相关DLL库的开发、如何在MFC环境下使用OpenGL进行图形绘制、为CAD应用程序开发OpenGL的通用绘图类、使用面向对象技术设计CAD软件的几何内核、CAD软件的图形交互、软件的界面设计等。

这里,首先介绍STLViewer的主要功能。图1-2是STLViewer的主界面。作为一个简化了的三维CAD软件,STLViewer可以接收输入的STL几何模型,并将STL 文件转化为系统自定义的几何模型,修改并增加属性,还可以采用串行化(Serialize)方法存储和装载系统自定义的几何模型(*.mdl文件)。在STLViewer中,使用OpenGL对几何模型进行了三维真实感渲染,并对模型进行视角变换、显示缩放、光照设置及鼠标捡取等。在界面中,设计了具有Visual Studio界面风格的浮动窗口和信息输出框。浮动窗口采用树形控件,用于显示几何模型结构、修改模型的附加信息(颜色、名称等)和操作选取几何模型。信息输出框用于输出系统提示信息,类似于Visual Studio开发环境中的Output窗口。

STL文件,即立体光造型文件(Stereo Lithographic File,STL File),是描述三维几何形状的标准文件格式之一,它采用一系列离散的三角片来描述三维曲面形状。目前,大多数CAD软件都具有STL文件输出接口,可以将三维几何模型输出成STL文件。本书所附带的STL文件(ASCII格式)均是从AutoCAD 软件输出的。STL文件在工业领域有较多的应用,如快速原型制造(Rapid Prototyping Manufacturing,RPM)就使用STL文件作为加工模型的几何输入接口。贯穿本书的示例程序STLViewer就是作者对参与开发的一个快速原型制造软件作了大量简化后的结果。1.4 STLViewer的程序框架

图1-5显示了STLViewer的MFC文档/视图结构框架。STLViewer采用MFC提供的单文档模板,其中包含四个主要的应用程序类:

• 文档类 CSTLViewerDoc。

• 视图类 CSTLViewerView。

• 主框架类 CMainFrame。

• 应用程序类 CSTLViewerApp。

它们所对应的源文件分别是:STLViewerDoc.h,STLViewerDoc.cpp,STLViewerView.h,STLViewerView.cpp,MainFrm.h,MainFrm.cpp,STLViewerApp.h,STLViewerApp.cpp。所有本书提及的源程序VC++代码都在随书附带的光盘内。图1-5 STLViewer的文档/视图结构

下面将对这四个应用程序类的分别加以分析。1.文档类 CSTLViewerDoc

文档类负责管理应用程序的数据。在STLViewer中,CSTLViewerDoc由MFC的文档基类CDocument派生,并插入了存放几何模型的对象m_Part。m_Part由一个自定义的几何模型类CPart定义,用于存储和管理STLViewer应用程序中全部的几何模型。

CSTLViewerDoc的定义如下(详见本书附带光盘内的STLViewerDoc.h文件):

对m_Part进行串行化存储和读取操作由CSTLViewerDoc的串行化函数Serialize_()实现。用m_Part代表的几何模型可以以二进制文件的形式存储在磁盘上,或从一个磁盘文件中读取出来并创建该对象。而执行函数OnStlFilein()则可通过读取STL格式文件,创建m_Part几何模型的内容。

CPart由一个自行开发的动态链接库GeomKernel.dll输出。关于CPart类的描述,将在本书第6章开发几何内核库时详细介绍。2.视图类 CSTLViewerView

视图类负责文档类中数据的显示,以及负责处理用户与图形窗口之间的交互操作。CSTLViewerView是在CGLView基础上派生的,用于在OpenGL的三维环境下绘制和操作几何模型对象m_Part。通常,应用程序的视图类都是由MFC提供的基类CView派生得来的。

但由于CView作为一个视图窗口的基础类,没有直接调用OpenGL绘制三维几何图形的功能,因此在本书开发的CAD图形显示动态链接库glContext.dll中,专门开发了支持OpenGL的视图类CGLView,它由CView类派生,并采用面向对象技术封装了OpenGL的图形绘制功能。CGLView的设计将在以后的章节中详细论述。由于在类CGLView中已经实现了主要的模型显示和操作功能,类CSTLViewerView所承担的任务更多的是接收用户输入信息,并调用CGLView中的相关函数处理用户输入。

CSTLViewerView的定义如下(详见本书附带光盘内的STLViewerView.h文件):

如图1-6所示,视图类中的虚拟函数CSTLViewerView::RenderScene() 在基类CGLView的绘图响应函数CGLView::OnDraw() 中被调用,用于执行基于OpenGL的场景绘制,即绘制CSTLViewerDoc::m_Part模型所包含的几何内容。用户可直接在RenderScene()函数中直接或间接调用OpenGL的图形绘制命令,以实现CAD模型的三维空间绘制。图1-6 在应用程序中重载RenderScene()函数实现OpenGL图形绘制3.主框架类 CMainFrame

主框架类提供了文档界面的主窗口,并创建和管理系统菜单、浮动工具条和状态条等界面对象。在程序STLViewer中,在MFC AppWizard生成的界面基础上进一步增强了用户界面的功能,即在主框架类CMainFrame中插入了一个具有Visual Studio界面风格的浮动窗口

对象(图1-7所示界面中左边的包含树型视图的窗口)和一个信息输出框对象(图1-7所示界面中底部的信息输出窗口),分别用于几何模型的浏览操作和提示信息的输出。浮动窗口和信息输出框对象是由对象m_ LeftDockBar和m_OututDockBarp对应表示的。在本书第9章将介绍一个用于界面增强的动态库DockTool.dll的开发,该动态库中开发并输出了几个专门用于界面增强的类。对象m_LeftDockBar、m_OutputDockBar分别由DockTool.dll的输出类或输出类的派生类所定义。对象m_LeftDockBar是一个具有浮动特性的窗口,它的功能类似_于Visual C++开发环境中的Workspace窗口,可以在主框架内任意浮动,并可以在其中嵌套多个视图,这些视图又可以与文档相关联,即实现文档多视图。m_ OutputDockBar也是一个具有浮动特性的窗口,但只可以停靠在主窗口内的上下侧,在其中还嵌套了一个用于文本输出的滚动视图用于系统信息的输出显示。

CMainFrame的主要任务集中在创建并管理上述界面对象。

类CMainFrame的定义如下(详见本书附带光盘内的 Mainfrm.h文件):图1-7 框架类CMainFrame设计与STLViewer的主界面中的窗口对象4.应用程序类 CSTLViewerApp

类CSTLViewerApp负责管理应用程序的主线程,从程序的初始化、运行,直到最后的清除任务。程序STLViewer中,类CSTLViewerApp由CWinApp直接派生:

这里需要介绍的是对CWinApp:: InitInstance()函数的重载。InitInstance是CWinApp的基类CWinThread中的一个虚函数,就是“初始化实例”的意思。它在实例创建时首先被调用,应用程序总要重载这个虚函数,进行系统设置、创建运行环境。而且,主窗口、视图窗口、文档对象等一定要在InitInstance()中创建,因为该函数退出后就进入了应用程序主线程的消息循环。

为了形成一个文档/视图结构的应用程序,在应用程序类的CSTLViewerApp::InitInstance()函数重载中,MFC帮助创建了一个单文档模板类对象,并且在文档模板的构造函数中,用系统定义的宏RUNTIME _CLASS创建了文档类CSTLViewerDoc、框架窗口类CMainFrame_和视图类CSTLViewerView的对象。在一个应用程序中,可以使用多个模板,这些模板由系统创建的一个链表进行管理。因此,在创建模板之后,还要使用AddDocTemplate()函数把该模板添加到模板链表中。

InitInstance()函数内容通常由MFC的程序向导(AppWizard)自动生成。在客户程序中,可以对该函数作进一步修改,例如给程序增加一个封面、设置主窗口的初始状态等。1.5 STLViewer中类的层次设计及软件模块结构划分

学习过C++的读者对于面向对象的编程技术( Object - Oriented Programming ,OOP )都不会陌生,OOP技术是当前程序设计的主流方法学。详细讲述OOP技术的著作和文章很多,由于本书的重点不在于此,所以不再花篇幅详细介绍OOP技术。概括地说,OOP技术的主要特征在于三个方面:即函数的重载、数据的封装和类的继承。能否在程序设计中较好地运用OOP技术的关键,就在于对这三个主要特征的理解和体会。对一个较复杂的功能软件而言,在初期最重要的一部分工作是设计软件的整体结构,主要的考虑包括:要设计哪些主要的类?这些主要类之间的关系怎样?例如类之间的继承和派生关系,类之间的消息传递和数据交换等。如果类的数量较多、系统较复杂的话,还应该考虑软件功能模块的划分问题。读者或许已注意到,很多软件都是由一个执行程序(*.exe 文件)附加多个动态链接库(Dynamic Link Libaray,DLL)组成的。可以这样说,类是软件设计时的模块,而DLL库是软件运行时的模块,一个DLL库可以输出一组类、函数及资源。通常的做法是把一些功能相对集中、可重复利用率高的类和函数集中于一个动态链接库中,执行程序在运行时根据需要动态地链接并调用这些DLL库所输出的类和函数,并在使用完成后予以释放。这种动态地链接和调用关系也可以存在于动态链接库之间。

以STLViewer为例,整个应用程序由可执行程序STLViewer.exe和四个动态链接库组成,即Geom Calc.dll、gl Context.dll、Geom Kernel.dll和DockTool.dll。图1-8显示了这些软件模块相互之间以及它们与MFC基本类库之间的层次关系。图1-8 STLViewer的层次结构

STLViewer.exe在运行时调用所需要的动态库,四个动态链接库均是MFC扩展方式构造的DLL库,这是因为只有采用扩展方式的DLL库才能输出C++的类。具体地创建和使用DLL将在下节介绍。四个模块或动态链接库的功能介绍如下:(1)几何基本工具模块GeomCalc.dll。该模块输出基本几何对象类与几何计算函数,如描述点、矢量、矩阵的类及相关的计算函数。它是CAD系统中必不可少的模块,CAD系统中与几何造型、操作及显示等相关的功能都需要这些基本的几何对象和计算功能。系统中另外两个模块,即几何内核模块和图形显示模块就建立在GeomCalc.dll基础之上。(2)CAD图形工具模块glContext.dll。该模块输出了一系列用于OpenGL三维图形绘制的C++类,在这些类中,基于MFC的机制对OpenGL的有关功能进行了封装。在MFC下可方便地调用这些类,完成OpenGL的初始化设置、三维几何体的光照显示,以及对显示的操作,如视角变换、显示缩放、光照或颜色的设置等。glContext.dll建立在MFC及GeomCalc.dll的输出类基础之上。(3)CAD几何内核模块GeomKernel.dll。该模块输出了一系列用于描述三维几何对象的类。几何对象是CAD软件操作和显示的主体,这些对象之间又存在各种关系,如层次关系、拓扑关系。在本书中,将描述和管理这些几何对象及它们之间关系的类集称为几何内核模块。对这些几何体的描述是建立在GeomCalc.dll输出类的基础之上。GeomKernel.dll调用glContext.dll用于几何体的OpenGL绘制。建立一个真正的三维几何内核是一项复杂而专业的工作,将涉及大量CAD领域的专业知识。在本书中,笔者以构造GeomKernel.dll这样一个较简单的几何内核库为例,主要目的在于讲述如何使用面向对象的编程技术设计和实现CAD几何内核。经过简化的几何内核库GeomKernel虽然只包括了为数不多的几何类,但构造一个面向对象的几何模型结构。在它的基础上,可方便地对这个库进行扩充,增加更多功能的几何对象类。(4)浮动界面工具模块DockTool.dll。该模块输出了一些增强界面效果的浮动窗口类。如图1-2左侧所示的类似于Visual C++集成开发环境中的Workspace浮动窗口,以及底部的用于提示信息输出的Output浮动窗口,都由DockTool.dll输出。1.6 建立和使用动态链接库

以上我们分析了应用程序实例STLViewer的模块化层次结构。这是一个由多个动态链接库组成的、模块化的CAD软件。本节将介绍动态链接库的一些基本概念、使用方法,以及利用Visual C++开发动态链接库的有关知识。在第2章中将尝试创建第一个DLL——几何工具类库GeomCalc.dll。GeomCalc.dll将输出开发CAD系统需要的基础几何表示类,如点、矢量和矩阵,以及一些常用的计算函数。通过对GeomCalc.dll的开发,相信读者能够掌握开发DLL的有关技术。同时,通过几何基础类的设计和开发,读者也会对使用Visual C++设计与开发中的一些技术细节有更深刻的认识。1.6.1 动态链接库的基本概念

在软件结构中,库(library)是指一个或多个目标文件(.obj文件)经过组合而形成的一个代码群,这些目标文件经过链接后生成一个可执行文件。它可以简单地被看成是一种仓库,提供一些可以直接拿来用的变量、函数或类。例如在本项目中,将功能相对集中、易于重复使用的代码根据其功能分别设计了基础几何计算库(GeomCalc.dll)、CAD几何模型(GeomKernel.dll)、OpenGL图形绘制功能(glContext.dll)、界面工具函数(DockTool.dll)四个库。

与库的链接方式有两种:静态链接与动态链接。静态链接库与动态链接库都是共享代码的方式。在静态链接中,无论你愿不愿意,链接程序将所需求的目标代码从库文件中复制到可执行文件EXE中。之所以被称为“静态”,是因为对库中的所有函数调用在链接生成可执行文件时已经完成,运行可执行文件时,不需要再从库中调用目标代码。这样链接生成的执行文件的尺寸会比较大。而动态链接时,链接程序并没有把所需要的目标代码从库文件中复制到可执行文件中,而是可执行文件在运行的开始或运行的过程中,根据需要从库文件中装载并使用相应目标代码,在使用完后可以根据需要及时卸载,从而释放不必要的系统资源。之所以被称为动态链接,是因为对目标代码的调用不是在链接时完成的,而是在执行过程中从库文件中动态装载使用的。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态链接库,而在动态链接库中还可以再包含其他的动态或静态链接库。

动态链接库(DLL)即是这样一种动态链接模块,是包含输出类和共享函数库的二进制文件,可以被多个程序同时使用。建立应用程序的可执行文件时,不必将DLL链接到程序中,而是在运行时动态装载DLL,装载时DLL被映射到调用进程的地址空间中。因而,DLL是“运行时”的模块。

利用动态链接库技术,有利于应用程序的模块化,可将一个大的应用程序分成多个单独的功能模块,这样也有利于开发队伍之间的分工协作。对大型的CAD软件,如果不采用静态链接技术,将所有的执行代码都加入到执行文件中,会导致程序的主执行文件异常庞大,执行时占用大量的内存而严重影响程序的运行效率。DLL对于Windows系统的使用者来说其实并不陌生。事实上,如果不使用动态链接技术,微机的内存恐怕连Window操作系统本身都启动不了。如果我们浏览Windows目录下的system32文件夹,就会看到诸如kernel32.dll、user32.dll、gdi32.dll等大量的DLL库文件,Windows的大多数API都包含在这些DLL中。例如,kernel32.dll中的函数主要处理内存管理和进程调度,user32.dll中的函数主要控制用户界面,gdi32.dll中的函数则负责图形方面的操作。很多程序员都用过类似MessageBox的函数,其实它就包含在user32.dll这个动态链接库中。

除了节省程序运行时的资源消耗,DLL的另一个主要特点是一个DLL可以同时被多个应用程序共享。在开发软件时,如果能够将一些功能集中、可重复利用率高的类和函数组合成一个独立的模块,则不仅一个系统的其他模块可以调用这些类和函数,它们也可以供别的应用程序共享。也就是说,在STLViewer中开发的四个DLL库,还可用于其他的应用程序。CAD领域著名的几何内核软件ACIS就是应用DLL技术的典型例子,它所提供给用户的就是一系列功能相对集中的DLL库,由用户在这些库的基础上开发自己的CAD应用程序。

另外,如果不改变DLL的接口,即使DLL库发生改变,也不需要重新编译所有调用它的应用程序。这也在一定程度上减轻了软件开发和维护的工作量。

另外,需要强调的是,DLL的设计制作与具体的编程语言和编译器无关。只要遵循约定的DLL接口规范和调用方式,用各种语言编写的DLL都可以相互调用。譬如Windows提供的系统DLL(其中包括了Windows的API),在任何开发环境中都能被调用,无论是Visual Basic、Visual C++还是Delphi。1.6.2 基于MFC的动态链接库

使用Visual C++能够建立一个没有MFC库的纯Win32 DLL,正如可以建立一个没有MFC支持的Windows程序一样。然而,本书的所有案例都是基于MFC的,因此这儿只着重介绍基于MFC的DLL库。

MFC提供了三种不同的方式支持DLL的开发:

• 建立静态链接MFC的常规DLL(Regular DLL)。

• 建立动态链接MFC的常规DLL。

• 建立动态链接MFC的扩展DLL(Extension DLL)。

扩展DLL和常规DLL的区别在于:(1)MFC的扩展DLL支持C++接口,即扩展DLL能够导出整个C++类。这就是说,可以从已有的MFC类派生新的可再用类。扩展DLL在建立时使用的是MFC的动态链接,因而扩展DLL要求客户程序动态地链接到MFC动态库。另外,需要保证客户程序与DLL所链接的DLL库版本保持一致。如果客户程序是基于Visual C++ 2005创建的MFC程序,其本身所链接的MFC库的版本是mfc80.dll;而在Visual C++ 6.0创建的扩展DLL,其被客户程序加载时会动态链接到mfc42.dll,会造成程序运行时的冲突。此外,扩展DLL的一个特点是尺寸很小,可以建立一个大小仅为10KB的简单的扩展DLL,能够很快被系统加载。例如,本书所创建的DLL库均为扩展DLL库,其每个库的尺寸分别为:几何模块(GeomCalc.dll)30KB、图形模块(glContext.dll)60KB、内核模块(GeomKernel.dll)36KB,界面模块(DockTool.dll)34KB。(2)常规DLL可被任意Win32编程环境(例如Visual Basic)加载。它的局限性在于常规DLL只能导出标准C接口,不能导出C++类、成员函数或重载函数。这是因为每个编程环境编译器有其自己的修饰名方法。但在常规DLL内部,仍然可以使用C++类及MFC类。(3)常规DLL能够采用显式链接或隐式链接,而扩展DLL只能采用显式链接。

静态链接MFC的DLL与动态链接MFC的DLL的区别在于:(1)静态链接MFC的DLL将复制所有需要的MFC的代码,成为自我包含的模块,可以独立于MFC的DLL库而运行,但DLL的代码尺寸会较大。(2)动态链接MFC的DLL在运行时动态链接MFC类库,因而DLL的代码尺寸会大大减小,但必须确保在运行的系统上有合适版本的MFC DLL库。

由以上分析可知,因为需要导出一系列C++类,且很多类还需要从MFC类派生,因而,在本书的实例中要创建的是MFC的扩展DLL。1.6.3 查看执行程序EXE与DLL库的层次关系

为了便于理解可执行文件EXE与DLL之间的层次关系及调用关系,可以借助Visual Studio提供的辅助工具Dependency Walker(Depends.exe)查看并分析一个程序与其他动态链接模块之间存在的依赖关系与函数调用接口。运行Depends.exe后,选择“File|Open”命令,选择要查看的EXE或DLL文件,则界面中会显示DLL调用的DLL及其提供的接口。如图1-9所示,打开位于本书附带光盘“CH1\”子目录下的主执行文件STLViewer.exe,在左边的树形视图显示了程序所调用的DLL资源列表。可以看到STLViewer.exe的运行直接依赖于八个DLL库。其中,上面四个库(GEOMCALC.DLL、GEOMKERNEL.DLL、Glcontext.DLL、DOCKTOOL.DLL)是由本项目生成并链接的DLL库,而下面四个库(MFC80U.DLL、MSVCR80.DLL、KERNEL32.DLL、USER32.DLL)则是为基于MFC开发的Windows程序而自动链接的系统库。在左边树形视图中,选择相应的DLL,在右边的列表部分则会显示对应的接口函数。其中,Ordinal列表示函数在DLL中的序号或名称,Hint列表示接口函数在DLL内部的序号值,Function列表示函数名称。底部的列表视图显示了调用的DLL模块的信息。从图1-9中可以看到,GEOMCALC.DLL中提供了CBox3D、CPoint3D等输出类供主程序STLViewer.exe使用。

如图1-9所示,DLL库之间也存在层次依赖关系。利用Dependency Walker工具有助于我们了解一个DLL库与其他DLL模块之间存在的层次结构。例如,在图1-9所示的界面左侧的树形视图中打开GEOMKERNEL.DLL(本项目的CAD模型库),则可以看到GEOMKERNEL.DLL与本项目的其他两个模块GEOMCALC.DLL(基础几何计算库)、Glcontext.DLL(OpenGL图形绘制功能库)之间存在依赖关系。图1-9 用Dependency Walker工具查看程序与DLL之间的函数调用关系附:本章相关程序使用说明

在本书附带光盘中的“ch1”子目录下,给出了运行STLViewer的执行程序和DLL库,它们是:

• ch1\STLViewer.exe,执行程序。

• ch1\GeomCalc.dll,几何基本工具库。

• ch1\glContext.dll,CAD图形工具库。

• ch1\GeomKernel.dll,CAD几何内核库。

• ch1\DockTool.dll,浮动界面工具库。

运行STLViewer.exe,程序出现如图1-2所示界面,但开始时窗口中还没有几何模型。

在目录“ch1\Models\”下,给出了一些STL模型文件和STLViewer自己的模型文件(*.mdl)。可以分别通过读入一个或多个STL文件来构造几何模型。在ToolBar中,使用“STL File In”按钮来输入STL模型,每读入一个文件,STL模型将显示在窗口上。然后,可以使用ToolBar上提供的放大、缩小、平移、视角变化等功能来观察几何模型。

STL作为一个标准的三维几何形状文件接口,很多CAD软件都可以输出STL模型。本例中的几个STL模型由AutoCAD软件输出(ASCII格式)。读者自己也可以创建一些STL模型,用STLViewer.exe来读入并观察模型。图1-2显示的就是读入了“ch1\Models”子目录下的几个STL文件后构造的模型。

mdl文件是STLViewer自己定义的二进制格式文件。使用[File]菜单下的[Save] 命令,可将当前模型存储成系统自己的.mdl类型文件。也可使用[Open]命令直接读入.mdl文件。在目录“ch1\Models\”中提供了几个已经生成的.mdl文件。第2章矢量计算工具与几何计算类库设计本章技术要点:• 介绍几何计算中的基本对象:点、矢量和齐次变换矩阵。• 设计实现点、矢量和齐次变换矩阵的C++类。• 齐次变换矩阵与三维图形变换。• 开发几何基本工具库GeomCalc.dll。点、矢量和齐次变换矩阵是CAD中构造几何元素及几何变换运算时最常用的基本对象。本章将分析点、矢量和齐次变换矩阵之间的几何运算,并为它们的数据结构设计实现相应的C++类。最后,以这些类及相关的计算函数为主要内容开发一个DLL库——GeomCalc.dll,即一个几何基本工具类库。这些基本的几何对象及其相关计算在CAD中有着非常广泛的应用,是进一步开发其他高级功能的基础。本章所开发的DLL库,作为一个基本模块可供系统中其他模块开发时调用。2.1 矢量运算概述2.1.1 点

点是构成所有几何对象的最基本的元素。在三维几何系统中,点用于表示空间的一个位置。几乎所有对几何对象的操作都可以归结为对点的操作,如几何体的平移、旋转、缩放,实际上都是对构成几何对象的点进行平移、旋转、缩放。对点的操作是通过点与矢量、矩阵之间的运算来实现的。

在三维CAD系统中,点的空间位置由三个标量所表示的坐标值(x,y,z)定义,它是点的唯一属性。二维平面上的点是三维点的特殊情况。一个描述点的数据结构定义如下:

C语言中提供的数据结构是一种复合数据类型,用于将一些相关的数据类型组织成一个新的数据类型。数据结构的声明以关键字struct开始。注意,在结构struct之前使用了typedef,typedef用于将某个标识符定义成数据类型,然后将这个标识符当作数据类型使用。例如,用typedef将标识符POINT3D定义为点的数据结构struct tagPoint3D;将标识符PPOINT3D定义为指向点的数据结构struct tagPoint3D的指针。用typedef来重定义数据类型的目的在于提高程序的可移植性。

例如,以下两行代码的作用是完全相同的,都声明了一个struct tagPoint3D的变量:

以下两行代码都声明了一个指向struct tagPoint3D的指针pPt:2.1.2 矢量

矢量是带方向的长度单位,是几何计算中最重要的工具之一,几乎所有的几何计算都会涉及矢量的运算。如物体的移动、旋转、坐标系的变换等。空间中的一个矢量,由dx、dy、dz三个分别沿坐标轴方向的标量组成,二维平面上的矢量是三维矢量的特殊情况。矢量没有一个固定的空间位置。两个矢量,只要它们的长度和方向都一致,就认为这两个矢量是相等的。

定义空间矢量的数据结构如下:

矢量与矢量、矢量与标量、矢量与点之间的常用运算关系有如下几项。

1. 矢量表示两空间点之间的位置关系

如图2-1所示,在一个三维坐标系中有点P(x,y,z)与点1111P(x,y,z),从P点到P点的位移用矢量222212V=P−P=(x−x,y−y,z−z)表示。因而,可以用矢量V表示两点之21212121间的位置关系,它有方向和长度但没有固定位置。

2.矢量的模长

求矢量V(dx,dy,dz)的长度(模长)M的计算公式如下:

3.矢量与点的和与差

换个角度,也可以说点P是点P沿矢量V平移得到的。在数学上,21P可以表示为:2图2-1 表示位移的矢量

即一个点与一个矢量的和还是一个点。另外,点P也可以看作1是点P沿矢量V的相反方向平移得到的,即表示为:2

P= P− V12

在CAD图形计算中,几何实体的位移常通过点与矢量的加减计算实现。点P(x,y,z)与矢量V(dx,dy,dz)相加或相减,生成一个新的点P*,即沿矢量方向(相加)或反方向(相减)平移该点:

4.矢量的和与差

矢量允许两个基本操作:两个矢量相加或相减,以及一个矢量与一个标量(实数)的数乘。对于矢量V、V及标量s,V+V、V−V、121212和s*V都是有意义的。1

两个矢量V(dx,dy,dz)、V(dx,dy,dz)相加或相减,生成一个11112222新的矢量V*。图2-2直观地表示了矢量求和是两个位移的简单相加。图2-2 两个矢量的和与差

5.矢量与标量相乘

矢量V(dx,dy,dz)与标量s相乘,可以放大或缩小该矢量的长度。

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载