VBA二次开发AutoCAD技术在桥梁工程中的应用
2018-11-14张海涛
□文 /张海涛
VBA(Visual Basic for Application)是一种面向对象的编程语言,它的基本语法完全继承于VB,所以具有语法简单易懂、编程逻辑清晰的特点,非常适合程序的快速开发。VBA的强大优势在于将VB的编程环境与被开发程序同时运行,利用面向对象编程方法(OOP),在接口的库中将软件中的重要部分对象化、参数化,在VBA中直接调用软件中丰富的对象进行操作以实现编程目的。因此,VBA作为一种通用型语言,能广泛应用于Windows下的Office系列软件、AutoCAD等专业商业软件的二次开发、Windows脚本编程(VBS)等。
AutoCAD是目前应用最为广泛的交互式计算机辅助绘图与设计软件,其优势在于通用性、多工业标准和开放的体系结构,广泛应用于土木建筑、装饰设计、机械工程等领域。虽然AutoCAD功能强大,但在解决一些专业问题,尤其在需要结合设计计算、数据处理、复杂图形绘制时就会显得力不从心,这时候在程序基础上对AutoCAD进行二次开发成为解决上述问题的有效补充手段[1]。AutoCAD常见的二次开发工具包括Auto LISP/Visual LISP、基于ActiveX Automation技术的VB/VBA、采用C++语言的Object ARX技术、基于微软.Net技术的VB.Net和C#语言开发。这几种语言各有优劣,具体特点及使用方法可参考相关介绍[2]。相较而言,VBA具有编程简单、快速开发、运行效率高、功能强大等特点使其拥有不同于其他二次开发工具的特殊优势,也使其在各专业工程人员中的推广和继承具有了生命力。
基于VBA的这些优势,二次开发技术在桥梁工程中得以广泛应用[3]。本文对AutoCAD和Excel进行联合开发,利用Excel获取CAD图形数据生成桥梁工程专业计算软件桥博的脚本,辅助桥博软件的建模,提高了工作效率。在此基础上本文着重介绍了包括VBA理论模块、程序设计方法和关键技术,为相关工程的二次开发提供参考。
1 程序设计
1.1 VBA的调用对象
首先,二次开发的操作是基于对AutoCAD提供对象(Object)的操作,这些对象的种类非常丰富并且包含各种属性(Properties)和方法(Methods)。对象本质上是一种特殊的变量,可以进行定义、赋值、释放。AutoCAD中的对象按性质可以主要划分为以下几种[4]。
1)图形对象,如直线(Line)、文本(Text)、标注(Dimensions)等。
2)样式设置对象,如线型(Linetype)、文字样式(TextStyle)。
3)组织结构,如图层(Layers)、块(Blocks)。
4)图形显示对象,如视图(View)和视口(Viewport)。
5)AutoCAD 应 用 程 序 (Application) 和 文 档(Document)。
这些对象基本涉及到了AutoCAD的各方面并可以在VBA的对象浏览器中查询。各对象之间并不是随意排列,大多数都存在父对象和子对象的树形衍生关系,常用对象见图1。
图1 AutoCAD对象
如图1所示,AutoCAD中的图形对象基本都囊括在ModelSpace中,比如常用的各类线、文字等,用Add方法可以向AutoCAD的Document对象中添加各种图元,完成图形的绘制,而另外一个重要的对象Utility则集合了一系列的内部实用工具,比如获取两点间距(GetDistance)、获取对象(GetEntity)、获取坐标(GetPoint)等方法函数,用于获取图形中的各类信息。这两个基本类可以完成对AutoCAD的大部分常用操作。关于其余对象的定义、属性、方法及示例都可以在AutoCAD提供的官方帮助文件里查询。
1.2 程序的调用方法
使用VBA开发软件可以分为内部调用和外部调用两种方式。AutoCAD内置了VB的开发环境VBE(高版本需要安装VBA开发包),可以在VBE中直接开发VBA,这样能够在程序内部直接运行程序并查看在窗口中的运行结果,这是VBA相较其他开发语言的优势之一。缺点是内置的VBA没有办法进行封装,只能将代码部分通过加密的方式进行简单保护。
由于在AutoCAD中无法通过内部命令的方式直接运行内部VBA,所以通常会用LISP给VBA编写一个调用命令,可采用如下形式:
(defun c:CM()
(command“_vbarun”“cm_vba”)
)
这样,在加载这个lsp文件和dvb格式的源文件后,就可以通过在命令行中直接输入“CM”来内部调用名称为“cm_vba”的VBA程序。
在另外一些情况下,如果将部分代码封装为动态链接库后外部引用或者从其他程序的VBE、VB6.0和Visual Studio等开发工具进行外部控制时,则需要进行外部调用,首先要在窗口的“工具”-“引用”中调用基本库[5],然后在代码部分声明引用对象,获得软件的控制权限。
例如,当采用外部创建CAD文件时,可采用以下代码,依次获得对软件和新建文档的控制权:
DimAcadApp as AcadApplication
DimAcadDoc as AcadDocument
Set AcadApp
=CreateObject(“AutoCAD.Application”)
AcadApp.Visible=True
Set AcadDoc=AcadApp.ActiveDocument
外部调用的缺点是没有办法直接在AutoCAD中直接运行程序查看结果且需要考虑程序运行过程中输入、输出的接口问题。但是外部调用为AutoCAD与其他程序的交互提供了实施方法。
1.3 利用VBA与其他程序的交互
AutoCAD的优势在于对图形的处理,当涉及到其他方面的工作时,单一依赖AutoCAD或者完全靠VB本身的功能与函数去构建复杂的程序会拖累整体的运行效率。所以,与其他专业软件进行交互,是VBA的一项重要功能,见图2。
图2 VBA交互体系
Excel是微软公司开发的专业办公软件,所以Office已经内置了VBA的开发环境[6]。Excel协助AutoCAD能够完成数据提取、整理、运算、输出等一系列工作,结合Excel和AutoCAD可以避免大量使用VB窗口及控件,从而节省复杂的窗口设计工作。关于Excel的对象结构此处不多做介绍,具体参阅相关教材与手册。
在设计程序时,需要选择VBA基于的软件主体:如果程序的主要功能是运算和数据处理,需要从Au-toCAD定向获取、输出图形信息,可以选择从Excel控制AutoCAD,借用Excel的内置功能对数据信息进行处理;如果程序的主要任务是绘图,只是借助Excel的末端功能完成简单数据汇总、数据传递功能等,可以选择从AutoCAD控制Excel;如果希望编译独立可执行程序,可以直接用VB6.0、Visual Studio等开发工具调用其他VBA兼容软件。
1.4 程序的模块化处理
因为VBA语言本身没有划分模块的语法结构,所以在程序设计初期就应当考虑把程序定义成不同模块,以方便后期对程序进行定向维护和扩展,有以下几个基本原则可参考。
1)划分程序的主次,将具体执行各部分功能的操作归纳于不同的子程序中,而主程序用于控制所有子程序的运算流程,这里将最终脚本输出函数Genegrate_Script()作为主程序,而子程序负责各个部分脚本信息的统计和生成,见图3。
图3 程序模块
2)将自编的一些通用型功能函数归纳成各类函数模块,方便在不同的子程序中直接使用,也方便向其他程序进行移植,比如排序函数、插值函数、向量计算函数等。
Sub Array_Shrink(ByRefarr As Variant)
'清除多段线中重复节点
......
For i=2 Tonum-1 Step 2
tmp_array(m)=arr(i)
tmp_array(m+1)=arr(i+1)
Ifarr(i)=arr(i-2)And arr(i+1)=arr(i-1)Then
ReDimPreserve tmp_array(num-2)
Else
m=m+2
End If
Next i
arr=tmp_array
End Sub
3)VB不具备C++/C#等语言方便定义类的功能,但是依然可以利用Type语句在“模块”中自定义数据类型,可以将一些变量尽量对象化置于模块中,以方便对同对象变量进行识别,比如此处将箱梁截面定义成对象,包含截面的序号、坐标、插入点属性。
Public Type bdSection '定义箱梁截面
indexAs Integer '截面序号
Pt_List As Variant'截面组成坐标
InsertPt As Variant'截面插入点坐标
End Type
2 设计实例
以Excel为主体,通过VBA外部控制AutoCAD获取模型信息,自动生成桥博的脚本文件。主程序主要负责汇总各部分信息并输出为桥博脚本dbs类型文本。型式参照以下总体信息部分代码,引用的是init_ZTXX()函数
Print#1,"//总体信息*************"
Print#1,"GEN.PrjTitle=""桥梁博士脚本"";"
Print#1,"GEN.CalType="&init_ZTXX.CalType&";" '函数获取总体信息
Print#1,"GEN.BPrestress="&init_ZTXX.bPrestress&";"
Print#1,"GEN.SelfHumi=0.8;
Print#1,"GEN.Code="&init_ZTXX.Code&";"
Print#1,"GEN.cU="&init_ZTXX.cU&";"
从Excel内部控制AutoCAD需要识别已打开的CAD文件,使用的是GetObject()函数,型式如下
DimAcadApp as AcadApplication
DimAcadObj As AcadDocument
Set AcadApp=GetObject(,"AutoCAD.Application")
Set AcadObj=AcadApp.ActiveDocument
进入AutoCAD之后,由于模型空间的图形类型丰富,需要对选定对象类别进行限制,可以用FilterType、FilterData两个数组限定选择对象为多段线或者直线等图元类型
DimFilterType(0)As Integer
DimFilterData(0)As Variant
FilterType(0)=0
FilterData(0)="LWPOLYLINE"
Plset.SelectOnScreen FilterType,FilterData
在AutoCAD中通过鼠标点击获取坐标参考原点,使用Utility下的Getpoint()函数,但需要注意由于是外部控制程序,涉及对象语句必须前置主体对象A-cadObj,也就是CAD文件本身:
base_pt=AcadObj.Utility.GetPoint(,"选择参考基点:")
这里程序会返回一个三维双精度数组,表示点在三个方向的坐标值。
通过选择获得多段线对象后,即可以通过其Coordinates属性得到多段线上全部的节点坐标,返回值为一个数组,然后再返回给Excel
Num=Plset.count
For i=0 Tonum-1
Pl_cdn=plObj(i).Coordinates
Call Array_Shrink(Pl_cdn)
'自定义函数删除多段线上重复节点
Pl_num= (UBound(Pl_cdn)+1)/2
For j=0 ToPl_num-1
Cells(j+12,4*i+1).Value=j+1
Cells(j+12,4*i+2).Value=Round((Pl_cdn(2*j)-base_pt(0))/1000,3)
Cells(j+12,4*i+3).Value=Round((Pl_cdn(2*j+1)-base_pt(1))/1000,3)
Cells(j+12,4*i+4).Value=0
Next j
Next i
从AutoCAD中得到的图形信息本质就是节点坐标,利用Excel的数据统计功能可以方便的对这些坐标做自动化处理
DimSec_numAs Integer'截面类型数量
DimSections()As bdSection'截面类型
Sec_num=WorksheetFunction.CountA (Range("B4:B100"))
ReDimSections(1 ToSec_num)
这样就定义了一个截面对象数组,包含全部类型截面的坐标信息。
3 结语
VBA编程主要具有以下几个优点:
1)语法简单清晰、逻辑性强,能够协助工程人员快速掌握并开发程序,不需要花费大量时间去学习复杂的语法和数据结构原理方面的知识;
2)VBA具有通用性,可以用于二次开发Auto-CAD、Office等一系列软件,更可以用来联合不同功能的软件进行组合编程,实现功能上的互补;
3)利用二次开发技术,在面对需要批量化、重复性、数据处理类的工作时,能够明显提高完成速度。
当然,VBA的一些缺点限制了它的应用和发展,比如大部分使用者由于是非编程专业领域出身的工程人员,加之VB语法本身不够紧凑,很容易写出庞大繁冗的程序。VBA的类定义功能不全,它的优势在于对接口提供的类库进行直接应用而并不是深化创造,使得它在二次开发领域的应用扩展性比较受限。
但总而言之,对于工程领域的从业者来说,VBA实现的部分功能是一种极为高效简便的解决方案,本文简单介绍了其在桥博建模中的一种应用方法,可为在其他更广泛领域内的使用提供参考。