基于ObjectARX的AutoCAD块替换的实现
2015-02-25
(炬威冶金技术(上海)有限公司,上海 200083)
块是AutoCAD中的一个重要概念,它把相关的图形和信息组织在一起。在实际的绘图过程中,常常需要替换一个块。AutoCAD自带的简单的、不完善的块替换命令,把DWG文件中一个块的所有块引用替换为另一个块的块引用。块替换命令的使用是有条件的,对于旧块和新块,它们必须都是没有属性的简单块,或者各个属性Tag完全一致的属性块。如果有属性Tag不一致的情况,那么在执行块同步命令后,属性块的属性值会丢失。而为新块重新输入属性值的工作即枯燥又繁重。本文将基于AutoCAD的ObjectARX二次开发技术建立一个可以对属性定义不同的块进行替换处理的扩展程序。
1 ObjectARX简介
ObjectARX是Autodesk公司的一种编程环境,提供了面向对象的C++、C#和VB.NET应用编程接口,用于对AutoCAD和基于它的垂直产品进行二次开发。
ObjectARX编程环境包含了丰富而又灵活的工具集使得开发者可以充分利用AutoCAD软件的开放架构。同时还提供了直接访问AutoCAD数据库结构、图形系统和定义原生命令的方法。
利用ObjectARX技术可以开发出快速、高效、紧凑的AutoCAD应用,使得设计人员可以从重复性的任务中解放出来。
ObjectARX有两个版本,一个是原生接口,用于C++语言编程;一个是基于.NET环境的托管接口,用于C#和VB.NET编程[1]。
2 定义程序功能需求
根据可能出现的各种情况,程序需要实现三个函数:
1)替换简单块的函数;
2)替换只有一个属性的属性块的函数;
3)执行期间指定映射关系并替换有多个属性的属性块的函数。
3 程序架构
程序的功能不复杂,在效率和空间占用上也没有严格要求,在这里选择C#程序设计语言,访问托管版本ObjectARX进行程序设计和编写。
创建一个命名空间,类命名为BlockReplace,创建三个函数,分别处理简单块的替换、单属性块的替换和多属性块的替换。为了能够通过键盘命令调用这些函数,为他们添加命令方法属性[1-2]。三个方法的声明如下:
[CommandMethod("rb", CommandFlags.UsePickSet | CommandFlags.Redraw | CommandFlags.Modal)]
static public void RepalceBlock();
[CommandMethod("rsab", CommandFlags.UsePickSet | CommandFlags.Redraw | CommandFlags.Modal)]
static public void RepalceSingAttributeBlock();
[CommandMethod("rmab", CommandFlags.UsePickSet | CommandFlags.Redraw | CommandFlags.Modal)]
static public void RepalceMultiAttributeBlock();
最后需要弹出一个对话框来手动指定属性名的映射,这个对话框命名为AttributeMapDialogue,声明如下:
public partial class AttributeMapDialogue : Window;
按照ObjectARX的要求,这里不能使用常规的WinForm,必须采用基于WPF(Windows Presentation Foundation)的用户界面[3]。所以AttributeMapDialogue类派生自System.Windows.Window类[4]。
4 具体实现
程序需要实现三个可以被AutoCAD命令行调用的三个函数来完成简单块的替换、单属性块的替换和多属性块的替换。这三个函数大体上都分为三个步骤:
1)选择将要被替换的旧块引用;
2)选择用于替换的新块引用;
3)用新块引用替换旧块引用。
下面分别解释这三个步骤的实现。
4.1 选择旧块引用
在上面提到的三个函数中,分别要求被选择的块是无属性的简单块、单属性块和多属性块。为此,在指定单实体选择模式的基础上,还需要指定被选择对象的两个属性构造选择过滤器:一是实体的类型属性应该是“Insert”,也就是块;二是有无跟随属性。
获取选择集之后,遍历选择集中的块,确定它们拥有同一个名称,否则,退出函数。
4.2 选择新块引用
创建PromptEntityOptions对象,调用AddAllowedClass()方法,设置允许选择的对象类型为块。
选择之后对选择结果进行检查。对于无属性简单块的替换,要求属性集合的数量为0;对于单属性块的替换,要求属性集合的数量为1;对于多属性块的替换,要求属性集合的数量大于1。如果不满足其中之一需重新选择。
4.3 用新块引用替换旧块引用
这个步骤又分为三个小步骤:
1)创建新块引用;
2)拷贝Properties值和Attributes值;
3)删除旧块引用。
为一个旧块引用创建一个新块引用的时候,需确定两个参数,一是旧块引用的坐标,二是新块的名称。
拷贝Property值只需要在同名称的Property之间进行赋值。
拷贝Attribute值的方法取决于替换的块的类型。
a. 对于无属性简单块的替换,不需要拷贝Attribute值。
b. 对于单属性块的替换,需拷贝一个Attribute值。访问旧块引用,生成属性引用集合的枚举,直接把第一个——实际上也是唯一的一个——属性引用的值拷贝给一个字符串变量。之后遍历新块定义中的所有ObjectId,调用ObjectId的GetObject()方法,使用as关键字把对象引用转换成AttributeDefinition对象引用并赋值给一个AttributeDefinition类型的变量,如果该变量不为空,那我们就找到了新块的唯一一个AttributeDefinition[3]。
立即创建一个AttributeReference对象,调用SetAttributeFromBlock ( AttributeDefinition definition, Matrix3d blockTransform )方法从属性定义中拷贝位置、尺寸和格式信息,然后设置属性的位置变换和旋转角度,接着调用AdjustAlignment (Application.DocumentManager.MdiActiveDocu-ment.Database)方法参照当前的空间进行对齐调整。
完成这些操作之后,向新块引用的属性集合添加刚才创建的AttributeReference对象,并且通知transaction对象执行AddNewlyCreatedDBObject方法,把新块引用添加到数据库中。
c. 对于多属性块的替换,需拷贝不定数量的Attribute值,这里区别于单属性块的替换,要求Attribute必须不止一个。由于旧块和新块之间Attribute的Tag存在不同,在正式开始多属性块的替换之前,必须插入一个新的任务,指定旧块和新块之间多个Attribute的对应关系。
对此,预先在BlockReplace类中声明:
两个字符串类型的List对象分别储存旧块和新块中所有Attribute的名称;
一个Dictionary对象用来储存Attribute映射表。
代码如下:
public static List
public static List
public static Dictionary
在选择用于替换的新块引用之后,创建两个List对象:
oldBlockAttributeTagList = new List
newBlockAttributeTagList = new List
遍历旧块定义中的所有ObjectId,调用ObjectId的GetObject()方法,使用as关键字把对象引用转换成AttributeDefinition对象引用并赋值给一个AttributeDefinition类型的变量,如果该变量不为空,那我们就找到了旧块的一个AttributeDefinition。访问这个AttributeDefinition的Tag,调用ToString()方法,把返回的字符串添加到oldBlockAttributeTagList。
遍历新块定义中的所有ObjectId,调用ObjectId的GetObject()方法,使用as关键字把对象引用转换成AttributeDefinition对象引用并赋值给一个AttributeDefinition类型的变量,如果该变量不为空,那我们就找到了新块的一个AttributeDefinition。访问这个AttributeDefinition的Tag,调用ToString()方法,把返回的字符串添加到newBlockAttributeTagList。
现在创建一个Dictionary对象:
attTagMap = new Dictionary
重载AttributeMapDialogue类的构造函数,把前面所述的两个List对象和一个Dictionary对象作为形式参数[5]:
public AttributeMapDialogue ( List
AttributeMapDialogue类也声明了三个同类型的变量对应构造函数的三个形式参数,为了方便,它们简单地声明为:
public static Dictionary
public static List
public static List
重载的构造函数需要储存形式参数接受的对象引用:
oldBlockAttributeTagList_Copy = oldBlockAttributeTagList;
newBlockAttributeTagList_Copy = newBlockAttributeTagList;
attTagMap_Copy = attTagMap;
在AttributeMapDialogue对话框的界面上,可以调整旧块和新块的属性的排列顺序。
调整完毕后,把旧块和新块的属性对应关系存入Dictionary对象attTagMap_Copy。
从AttributeMapDialogue对话框返回之后,正式开始多属性块的替换。
创建一个新的Dictionary对象储存旧块引用的Attribute值:
Dictionary
旧块引用的AttributeCollection是一个ObjectId类型的集合,对每一个ObjectId调用GetObject()方法,使用as关键字把对象引用转换成AttributeReference对象引用并赋值给一个AttributeReference类型的变量。把这个AttributeReference的Tag和字符串值储存到oldTagValuePairs中[6]。
创建新块引用,然后就像单属性块的替换过程一样,遍历新块定义中的所有ObjectId,对每一个找到的AttributeDefinition,执行相似的Attribute值拷贝过程,唯一的不同之处是,这里通过当前AttributeDefinition的Tag,在attTagMap中查找对应的旧块中的AttributeDefinition的Tag,紧接着在oldTagValuePairs中根据这个结果Tag查找到一个字符串值,把它赋值给新块中的AttributeReference。
删除旧块引用是在创建完一个新块引用之后,调用Erase()方法完成。
5 结语
创建的块替换程序,可以方便地对各种简单块和属性块进行替换,特别是对属性块的替换可以手动指定块之间属性的映射关系,直接控制属性值的传递,有效地提高了相关工作的作业效率。
[1] 曾洪飞,卢择临,张帆. AutoCAD VBA&VB.NET开发基础与实例教程:第2版[M]. 北京:中国电力出版社,2013:1-22
[2] Karli Watson, Christian Nagel. C#入门经典:第5版[M]. 齐立波,译. 北京:清华大学出版社,2010:369-375
[3] 李冠亿.深入浅出AutoCAD.NET二次开发[M]. 北京:中国建筑工业出版社,2012:313-357
[4] Microsoft Corporation. Visual C#[EB/OL]. http://msdn.microsoft.com/en-us/library/vstudio/kx37x362.aspx
[5] Kean Walmsley. The right way to show modal and modeless dialogs in AutoCAD using .NET[EB/OL]. http://through-the-interface.typepad.com/through_the_interface/2008/08/the-right-way-t.html
[6] Autodesk Inc. ObjectARX for AutoCAD 2013: Managed Class Reference[M/OL]. http://usa.autodesk.com/adsk/servlet/item?siteID=123112&id=78555