项目场景:
手上的Revit项目需要对CAD的一些实体对象做增删改查的操作,但是如果将CAD文件链接到Revit中做处理,会有诸多的麻烦,比如说在Revit二次开发中常用、且免费的用于处理CAD文件的dll文件是Teigha的Td_Mgd.dll,但是这个dll文件在使用过程中有诸多bug,并且有许多函数功能并没有完全开发完成,例如Entity.IntersectWith()函数。此外,这个dll文件也早已被Teigha官方抛弃了,早就不更新维护了。(Teigha现在改名为ODA了,他们官网有在售卖很多新的用于Revit,Naviswork,CAD二次开发的dll包,感兴趣的可以去看下,链接为:Home | Open Design Alliance)。所以Revit二次开发过程中,如果碰到了一些需要对CAD文件做处理的工作,可能还是需要移步到CAD二次开发。
问题描述
这真是个费解的问题,我在接触到CAD二次开发之初,第一件想干的事就是怎么获得活动文档中某一类型的所有对象,但是搜遍全网都没有一个合理的答案,要么是通过Selection,要么就是通过Filter获得对象的。就是找不到我想要的那种一步到位的方法(哭笑),并且夹杂着各种VB、C++的资料,对我们C#选手很不友好。博主niuge No.1通过ObjectId、选择集的方式获得指定类型的实体对象,博客链接为(134条消息) cad二次开发的一些简单入门实例_niuge No.1的博客-CSDN博客_cad二次开发。代码片段如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Colors;
using Autodesk.AutoCAD.EditorInput;
using System.Collections;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
using System.Reflection;namespace cad开发
{
public class Class1
{
#region "取得图层下的所有对象id"
/// <summary>
/// 取得图层下的所有对象id
/// </summary>
/// <param name="name">图层名称</param>
/// <returns>id集合</returns>
public ObjectIdCollection GetObjectIdsAtLayer(string name)
{
ObjectIdCollection ids = new ObjectIdCollection();
PromptSelectionResult ProSset = null;
TypedValue[] filList = new TypedValue[1] { new TypedValue((int)DxfCode.LayerName, name) };
SelectionFilter sfilter = new SelectionFilter(filList);
Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
ProSset = ed.SelectAll(sfilter);
if (ProSset.Status == PromptStatus.OK)
{
SelectionSet sst = ProSset.Value;
ObjectId[] oids = sst.GetObjectIds();
for (int i = 0; i < oids.Length; i++)
{
ids.Add(oids[i]);
}
}
return ids;
}
#endregion
/// <summary>
/// 得到当前图层的所有几何的id
/// </summary>
[CommandMethod("GetAllId")]
public void GetAllId()
{
Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
ObjectIdCollection ids = GetObjectIdsAtLayer("0");
string str = "";
Database db = HostApplicationServices.WorkingDatabase;
//定义一个指向当前数据库的事务处理,以添加直线
using (Transaction trans = db.TransactionManager.StartTransaction())
{
BlockTable acBlkTbl;
acBlkTbl = trans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable; //以读方式打开块表.
//以写方式打开模型空间块表记录.
BlockTableRecord acBlkTblRec;
acBlkTblRec = trans.GetObject(acBlkTbl[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
foreach (ObjectId item in ids)
{
Entity entity = (Entity)item.GetObject(OpenMode.ForRead, false, false);
switch (entity.GetRXClass().Name)
{
case "AcDbText":
DBText dbtext = entity as DBText;
string strtext = dbtext.TextString;
str += strtext + '\n';
break;
}
}
ed.WriteMessage(str);
trans.Commit(); //提交事务处理
}
}
#region "取得当前所有图层名称"
/// <summary>
/// 取得当前所有图层名称
/// </summary>
/// <returns>图层名称集合</returns>
[CommandMethod("GetAllLayer")]
public ArrayList GetLayerName()
{
ArrayList layers = new ArrayList();
using (Database db = HostApplicationServices.WorkingDatabase)
{
using (Transaction trans = db.TransactionManager.StartTransaction())
{
using (LayerTable lt = (LayerTable)trans.GetObject(db.LayerTableId, OpenMode.ForRead))
{
foreach (ObjectId id in lt)
{
LayerTableRecord ltr = (LayerTableRecord)trans.GetObject(id, OpenMode.ForRead);
layers.Add(ltr.Name);
}
}
trans.Commit();
}
}
return layers;
}
#endregion
}
}
原因分析:
大概也许是每个人的编程思路不一样吧,我就喜欢从整体到个体的思考方式。那么到底有没有从活动文档中直接整体获取指定类型的所有对象的方法了呢?
解决方案:
那肯定是有的,可以做一个泛型方法,具体如下:
public static List<T> GetAllT<T>(Autodesk.AutoCAD.ApplicationServices.Document doc) where T:DBObject
{
Database db = doc.Database;
List<T> tList = new List<T>();
using (Transaction trans = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead, false);
foreach (var item in bt)
{
BlockTableRecord btr = (BlockTableRecord)trans.GetObject(item, OpenMode.ForRead);
foreach (var r in btr)
{
DBObject dBObject = trans.GetObject(r, OpenMode.ForRead);
if (dBObject.GetType() == typeof(T))
{
T t = dBObject as T;
tList.Add(t);
}
}
}
trans.Commit();
}
return tList;
}
得到了整体的对象List集合以后,可以再根据自己项目的实际情况通过Where方法等做进一步的筛选。