时下流行的开发AutoCAD的工具,一个是ObjectARX,另一个是AutoCAD自带的VBA(AutoCAD内置的Visual lisp本来也算一个,但它只能开发一些小型的程序,因此不能和前面的两个工具相比)。但两者都存在明显的不足,以VC++为基础的ObjectARX的开发功能无庸质疑是非常强大的,但要想学习并熟练掌握VC++及ObjectARX对于普通人来说是比较困难的。还有大家应该注意到的是,ObjectARX是以VC++为基础的,但就是最新的ObjectARX2006也只能用Visual Stuio.net 2001来进行开发,而不能使用现在普遍使用的Visual Studio.net 2003(呵呵,当然不能用更高版本的Visual Studio.net了)。而VBA正好相反,非常容易上手,但对于编写高效或者复杂的程序就不是那么简单的事情了。更为糟糕的是,VBA已没有更新的版本了,因为VB已经被VB.net取代了。
那到底有没有一种结合ObjectARX和VBA优点的开发AutoCAD的工具呢?答案就是利用功能强大并且易用的.net。对于AutoCAD 2004及以前的版本,大家可以使用ActiveX来进行AutoCAD 的.net程序开发(我也写过这方面的文章),但开发出来的程序还不是真正意义上的.net程序,功能不是很强大,和ObjectARX或VBA相比没有任何的优势而言。到了AutoCAD2005,有了真正的可以开发.net程序的ObjectARX® managed wrapper classes,但它的功能还是很有限,如连最基本的用于读取AutoCAD命令行的函数都没有。随着最新的AutoCAD2006的发布,ObjectARX® managed wrapper classes的性能被大幅度提升,以前只有ObjectARX才有的一些函数和功能(而这些东东往往对于AutoCAD的开发是非常重要的),现在ObjectARX® managed wrapper classes都提供了。
最令人激动的是,利用ObjectARX® managed wrapper classes,你可以非常方便的生成AutoCAD工具栏、面板和扩展多页对话框(呵呵,英文名为extend tabbed dialogs,可能翻译的不太准确,用过CAD的人都应该知道选项对话框吧,扩展多页对话框就是指的这一种,甚至你可以在选项对话框中添加你自定义的页,是不是很酷啊!),而这些往往是ObjectARX和VBA非常难以做到的。
类似于属性的面板
扩展多页对话框,竟然可以在AutoCAD的选项对话框中添加自定义的选项卡,太酷了!
呵呵,费话说了这么多,还是让我们来用一个具体的例子来看一下如何使用ObjectARX® managed wrapper classes(2006)来开发AutoCAD程序,这个例子是先在AutoCAD中画一个圆,再根据用户在命令行中的选择改变圆的颜色。先说明一下,你可以用任何版本的Visual Studio.net(不管是老版本的2001,还是2003,或者是最新的2005)来进行AutoCAD .net程序的开发,编程语言你可以用C#或VB.net。我用的是Visual Studio.net 2003,语言为C#,AutoCAD 版本为2006英文版。
下面是具体的步骤(可以看附件中的演示视频):
1.在Visual Studio.net 中,创建一个类库工程。
2.添加相关的引用。请把AutoCAD2006安装目录下的acdbmgd.dll和acmgd.dll添加到工程中。
3.在源代码文件中,加入以下代码:
using System;
//下面加入的命名空间都是开发AutoCAD程序时会用到的
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using DBTransMan=Autodesk.AutoCAD.DatabaseServices.TransactionManager;
namespace Example
{
public class Class1
{
//注册AutoCAD命令,你可以在AutoCAD的命令行中通过输入此命令来调用.net程序
[CommandMethod("Test")]
public void Test()
{
//定义圆的圆心
Point3d center=new Point3d(100,100,0);
//定义圆的半径
double radius=50;
//定义一个Circle对象来表示你要生成的圆,传入的第二个参数为圆的法向,就是把圆生、//成在什么面上,因为AutoCAD程序一般都是平面问题,因此你一般都把这个法向量定义成//z轴方向。
Circle circle=new Circle(center,new Vector3d(0.0,0.0,1.0),radius);
//获得当前活动AutoCAD文档所在的数据库
Database db=Application.DocumentManager.MdiActiveDocument.Database;
//获得事务处理管理器
DBTransMan tm=db.TransactionManager;
//开始事务处理,也就是往CAD中加入东西
using(Transaction trans=tm.StartTransaction())
{
//获得AutoCAD块表,AutoCAD将加入到图形中的对象的信息都放在这个表中
BlockTable bt=(BlockTable)
tm.GetObject(db.BlockTableId,OpenMode.ForRead,false);
//获得块表记录
BlockTableRecord btr=(BlockTableRecord)
tm.GetObject(bt[BlockTableRecord.ModelSpace],OpenMode.ForWrite,false);
//向块表记录加入圆的相关信息
btr.AppendEntity(circle);
//向AutoCAD加入圆
tm.AddNewlyCreatedDBObject(circle,true);
trans.Commit();
}
}
}
}
是不是看了上面的东西觉得有点难?(呵呵,如果你要弄清楚什么块表、块表记录、事务处理的,你得先了解AutoCAD内在的一些东西,这我会在以后讲)不就是加入一个圆吗?要这么复杂?!为了让初学者快速地进入.net开发AutoCAD的世界,我给大家编了一个库ZHFARX,你可以通过这个库来简化上面的程序(关于ZHFARX库,你可以在附件中下载。关于这个库的详细介绍请大家看我下一期的文章)。下面是引用ZHFARX库后加入圆的代码:
using System;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using DBTransMan=Autodesk.AutoCAD.DatabaseServices.TransactionManager;
using ZHFARX;//这是引用的ZHFARX库
namespace Example
{
public class Class1
{
[CommandMethod("Test")]
public void Test()
{
Point3d center=new Point3d(100,100,0);
double radius=50;
//Circles是ZHFARX库中对应于Circle类的类
Circles circle=new Circles(center,radius);
//Entities是ZHFARX库中用来向AutoCAD中加入图形的一个类
Entities.AddEntity(circle);
}
}
}
呵呵,是不是简单了许多。
下面的代码是根据用户在命令行中的选择来改变圆的颜色。
//Editor代表AutoCAD命令行
Editor ed=Entities.Editor;
// PromptKeywordOptions定义一个关键字列表选项
PromptKeywordOptions opt=
new PromptKeywordOptions("选择颜色[绿色(G)/蓝色(B)]<红色(R)>");
//加入关键字列表
opt.Keywords.Add("R");
opt.Keywords.Add("G");
opt.Keywords.Add("B");
//获取用户输入的关键字
PromptResult result=ed.GetKeywords(opt);
//判断是否输入了定义的关键字
if (result.Status==PromptStatus.OK)
{
//根据用户选择的关键字,来改变圆的颜色
switch(result.StringResult) {
case "R":
// PutColorIndex是ZHFARX库中改变对象颜色的函数
Entities.PutColorIndex(circle,1);
break;
case "G":
Entities.PutColorIndex(circle,3);
break;
case "B":
Entities.PutColorIndex(circle,5);
break;
}
}
编译这个程序,生成Example.dll文件,这就是你编写的.net程序。
完整的源程序放在附件中。
4.打开AutoCAD,在命令行中输入NETLOAD命令。在弹出的对话框中选择刚才生成的Example.dll。接下来请在命令行中输入在程序中定义的命令的名字Test,好了应该可以看到一个圆了。这时命令行中出现选择颜色[绿色(G)/蓝色(B)]<红色(R)>[R/G/B] 的提示,你可以键入R,则圆变为红色;键入G,圆变为绿色;键入B,圆变为蓝色。
下面向大家介绍ZHFARX库中的主要函数及如何用它来编写.NET程序。关于ZHFARX库的所有函数的说明,请大家参考本章附件中的ZHFARX帮助文档。
在介绍ZHFARX库之前,让我们首先来了解一下有关的基本概念。你可以把AutoCAD看作为一个数据库,而AutoCAD中有关的东西都放在这个数据库的相关表中。例如,你用Line命令在AutoCAD的模型空间中添加了一条直线,那么AutoCAD会创建一个直线类的实例并把它加入到数据库的模型空间块表记录中。在传统的C++编写ObjectARX程序的时候,你必须首先打开当前数据库的块表(因为模型空间是在块表中的),然后打开模型空间对应的块表记录,在记录中加入直线类的实例,然后分别关闭块表和模型空间块表记录。而在.NET程序中,相应的代码编写是这样的:
Database db= Application.DocumentManager.MdiActiveDocument.Database;
//获得当前数据库
DBTransMan tm=db.TransactionManager;
//获取事务处理
using(Transaction trans=tm.StartTransaction())//开始事务处理
{
BlockTable bt=(BlockTable)tm.GetObject(db.BlockTableId,OpenMode.ForRead,false);
//打开当前数据库的块表
BlockTableRecord btr=(BlockTableRecord)tm.GetObject(bt[BlockTableRecord.ModelSpace],OpenMode.ForWrite,false);
//打开模型空间块表记录
btr.AppendEntity(ent);//在记录中加入实体
tm.AddNewlyCreatedDBObject(ent,true);//
trans.Commit();//提交事务
}
从上面的代码中可以看到,.net用事务处理代替了C++中的打开和关闭操作(当然你也可以像C++一样使用相应的Open和Close函数来进行打开和关闭的操作,但ObjectARX托管封装类已把这两个函数标记成了过时的函数,也就是说不建议用户使用它们)。
有一点要大家注意的是,对象没有被加入到AutoCAD数据库之前,你可以对它进行直接的操作(如改变颜色,移动,设置实体的几何属性等)。但一旦对象被加入到AutoCAD数据库中,你就必须使用事务处理来打开它然后进行相应的操作。比如说,你在AutoCAD中加入了上面的直线,而你想改变这条直线的颜色,你不能直接调用直线的Color或ColorIndex属性来进行设置,你必须首先用事务处理的GetObject()函数打开这个直线对象,然后你才能调用Color或ColorIndex属性来对直线设置颜色。
ZHFARX库的作用正是为了简化以上这些操作,有了它你在AutoCAD中加入对象的时候就不必再打开AutoCAD数据库的表,也可以直接对已加入到数据库中的对象进行操作,它还包括了以下这些功能:更为方便地创建AutoCAD实体的构造函数,遍历数据库表,添加组和扩展字典及其它一些常用的函数。
首先向大家介绍ZHFARX库中的Tools类。这个类是ZHFARX库的主要类,上面介绍的ZHFARX库的主要功能都是在这个库中实现的。下面介绍这个类中的主要成员(这个类的成员都是静态的):
l 属性
包括3个:Database(获取当前数据库),Editor(获取AutoCAD命令行),TransactinManager(获取事务处理管理器)。通过这三个属性,你就不要再输入诸如Application.DocumentManager.MdiActiveDocument.Database这么长的代码了,而只要简单地写为Tools.Database。
l 函数
按照函数的功能可以分为以下几类:
1. 加入对象
包括以下几个:
Ø public static ObjectId AddEntity(Entity ent);
这个函数向AutoCAD数据库加入实体类对象(如直线、圆等),下面的代码向数据库加入一条直线:
Line line;
…….
Tools.AddEntity(line);
Ø public static ObjectId AddSymbolTableRecord(SymbolTableRecord str,ObjectId symbolTableId)
这个函数向AutoCAD数据库加入符号表记录,符号表是AutoCAD数据库中的一系列表如层、线型等。函数的输入参数一个为要加入的符号表记录对象(str),另一个是符号表记录要加入的符号表的对象Id(可以通过访问数据库的属性获得,如LayerTableId属性就表示数据库的层表)。下面的代码向数据库添加一个新层:
LayerTableRecord ltr;
……
Tools.AddSymbolTableRecord(ltr,Tools.Database.LayerTableId);
Ø public static ObjectId AddDictionaryObject(string searchKey)
加入字典对象。关于字典对象的有关介绍,请看我以后写的文章。
Ø public static ObjectId AddDictionaryObject(string searchKey,DBObject newValue,ObjectId ownerId)
加入字典类对象,如扩展对象、组等。
2. 设置或读取对象的通用属性
通用属性包括:颜色(Color),颜色索引(ColorIndex),层(Layer),线型(Linetype),线型比例 (LinetypeScale),线宽(LineWeight),打印样式名(PlotStyleName)和可见性(Visible)。
设置通用属性的函数都以Put开头再加上对应的通用属性名,如设置对象颜色的函数为PutColor。设置每一种通用属性的函数都有两种形式,下面以设置颜色的函数为例来进行说明。
第一种形式为PutColor(Entity ent,Color color),第一个参数为对象的实例,第二个参数则是要设置的值。
第二种形式为PutColor(ObjectId id,Color color),第一个参数为对象实例的Id,第二个参数则是要设置的值。
获取通用属性的函数都以Get开头再加上对应的通用属性名,如获取对象颜色的函数为GetColor。也有两种形式,下面以获取颜色的函数为例来进行说明。
第一种形式为GetColor(Entity ent),输入参数为对象的实例。
第二种形式为GetColor(ObjectId id),输入参数为对象实例的Id。
3. 变换操作
令人非常不解的是在ObjectARX 托管封装类中,实体类(Entity)没有诸如旋转、平移、缩放之类的函数,你只能通过实体类的TransformBy()函数来实现这些变化操作。而TransformBy()函数由于要使用到一个矩阵参数,用起来不是很方便。在ZHFARX库中,已经给大家重新编写了用于变换操作的函数,你可以使用它们来方便地进行相关的变换操作。变换操作函数有两种形式,区别是第一个输入函数可以是实体对象的实例,也可以是实体对象的Id,在下面的介绍中我只介绍输入参数是实体对象的实例的那一种,对于另一种形式,你只要把相应的输入参数改成实体对象的Id就可以了。变换操作函数如下:
Ø public static void Move(Entity ent,Point3d fromPoint,Point3d toPoint)
把实体ent从点fromPoint移动到点toPoint
Ø public static void Rotate(Entity ent,Point3d basePoint,double rotationAngle)
以点basePoint为基准点,把实体ent旋转rotationAngle角度(为弧度值)。
Ø public static void Scale(Entity ent,Point3d basePoint,double scaleFactor)
以点basePoint为基准点,把实体ent缩放scaleFactor倍(>1为放大,<1为缩小)。
Ø public static ObjectId Mirror(Entity ent,Point3d mirrorPoint1,Point3d mirrorPoint2,bool eraseSourceObject)
对实体ent以由点mirrorPoint1和点mirrorPoint2组成的直线线进行镜像拷贝,参数eraseSourceObject表示是否删除源对象。
4. 其它一些常用的操作函数
Ø public static ObjectId Copy(Entity ent)
对实体ent进行复制,还有一个重载函数,输入参数为实体的Id。
Ø public static void Erase(Entity ent)
删除实体ent,还有一个重载函数,输入参数为实体的Id。
Ø public static Entity GetEntity(ObjectId id)
通过对象Id来获得实体对象(而获得实体的对象Id,你只要访问它的ObjectId属性就可以了)。
Ø public static DBObject GetDBObject(ObjectId id)
通过对象Id来获得非实体类对象。
Ø public static DBObjectCollection GetIteratorForSymbolTable(ObjectId id)
获取用于遍历符号表(由id表示)的遍历器(对象集合)。
Ø public static ObjectIdCollection GetIteratorForSymbolTableID(ObjectId id)
获取用于遍历符号表(由id表示)的遍历器(对象Id集合)。
Ø public static Point3d GetMidPoint(Point3d pt1,Point3d pt2)
获取两点表示的线段的中点。(呵呵,本来还想写诸如求交点、判断是否平行、垂直等的数学函数,但ObjectARX托管封装类都有相关的函数,就没有写)。
终于介绍完了Tools类的成员,再来介绍ZHFARX库中其它的类。Tools类外的其它类都是一些对AutoCAD实体类如直线、圆等的改写,以方便.NET程序的编写。到目前的ZHFARX版本为止,我改写的实体类有:直线(Line),圆(Circle),圆弧(Arc),椭圆(Ellipse),多段线(Polylines,这个多段线是二维的,也就轻量多段线),单行文本(DBText,请大家注意,在ObjectARX托管封装类中单行文本所在的类不是Text,而是DBText),多行文本(MText),表格(Table),填充(Hatch),各种标注(包括对齐标注AlignedDimension、直径标注DiametricDimension、角度标注LineAngularDimension2、半径标注RadialDimension和旋转标注RotatedDimension)。改写的实体类都是由这些实体类派生的,实体类的所有函数和属性改写类都可以使用。改写类的名字为实体类原名后加上s,如改写的直线类就是Lines,而改写的圆类就是Circles。你可能要说了,改写这些类有什么用?呵呵,答案有两个。一个是为了方便创建实体,另外一个就是你可以方便地修改实体的属性,不管它有没有加入到数据库中。ObjectARX的托管封装类中创建AutoCAD实体的函数,也就是构造函数,通常只有一种形&,如圆只能通过圆心、半径还有一个基本上不需要使用的法向量来创建。而我们知道在AutoCAD中有许多种创建圆的方式,如通过三点、通过二点的直径来创建圆。在ZHFARX库的Circles类中就包含了这些创建圆的构造函数。下面的例子说明了通过三点来创建一个圆:
Circles circle=new Circles(pt1,pt2,pt3);
关于这些构造函数的说明,大家可以参考附件中的帮助文档,里面有详细的说?库中的实体是不能直接访问的,而这些改写的类就可以。下面就以两段代码作比较来说明(以圆为例),首先来看一般的实体类:
Circle circle=new Circle (center,normal,radius);
circle.Radius=1;//由于圆还没有加入到数据库中,改变圆的半径属性是允许的
Tools.AddEntity(circle);//利用ZHFARX库的简化函数把圆加入到数据库中
circle. Radius =2;
//这句是错误的,因为圆已经加入到数据库中,你必须首先打开它,然后再进行相关
//的操作,不能这样直接访问圆
下面是改写类的代码:
Circles circle =new Circles (center, radius);//呵呵,连构造函数也比上面的简单了
circle. Radius =1;//在圆没有加入到数据库之前,改变圆的半径属性
Tools.AddEntity(circle);//利用ZHFARX库的简化函数把圆加入到数据库中
circle. Radius =2;// 圆虽然已加入到数据库中,但你仍然可以直接修改它的属性
还有一点大家要注意的是,对于诸如颜色、层等的通用属性,请使用Tools类的Get类和Put类函数(关于这些函数,请大家参考前面的内容),这些函数对于一般类和改写类都是适用的。