新疆水利水电勘测设计研究院,新疆 乌鲁木齐 830000
摘要:使用C#语言对Autodesk Civil 3D软件进行二次开发,其实就是利用Civil3D提供的丰富的API接口来实现对软件的扩展。根据工作中的实际需求,扩展一些相应的功能,比如将一些重复性的操作进行计算机化,提高工作效率。
关键词:Civil3D .net ;civil3D二次开发;C#;API;cad插件
AutoCAD Civil 3D 是一款广泛应用于基础设施建设行业中的设计软件,它是在AutoCAD软件的基础上专门针对于土木工程行业进行二次开发定制的工具包,可以快速的完成道路规划、场地放坡、土方计算等设计工作,它的动态关联设计方式使设计人员能够准确高效的完成大量的繁琐工作。同时它又提供了丰富的二次开发接口API,使用户根据实际工作需要定制个性化工具,进一步提高工作效率。C#是由微软公司推出的一种面向对象的高级计算机语言,语法于C和C++类似,但是C#更加简单易学,也是Autodesk推荐的二次开发语言。本文利用Civil3D提供的API接口,使用C#语言结合管道项目工作中的实际需求,编写了一些实用的命令,并将这些命令集中在一起,形成了一个工具集。在长距离管道等工程项目平纵横设计过程中经常会用到的命令包括:导出纵断图中的标注栏数据,向平面或纵断面图中批量插入建筑物标签,纵横断面图的范围调整等。利用本工具集可以快速方便的完成这些繁琐的重复性操作,节约设计者的时间,从而提高工作效率。
利用Visual Studio 2015编辑器,引用Civil3D提供的库文件(acdbmgd.dll,acmgd.dll,accoremgd.dll,AecBaseMgd.dll和AeccDbMgd.dll),编写代码完成后,生成一个.dll的类库文件,在civil3d命令行中输入“netload”命令,加载上述生成的类库文件,结果如下图所示,不同的命令显示到不同的面板中,方便查找和操作。
在管道工程或其它长距离线性工程中,需要向纵断面图中插入几十个甚至几百个建筑物标签比如排气阀、泄水阀、排洪建筑物等,而且还要保证插入的桩号位置准确无误,这是一件很繁琐的事情,为此编写了批量插入命令。在工具集中点击“向纵断面图中批量插入建筑物标签”命令,弹出的对话框界面如下左侧所示,点击“导入txt数据”按钮,弹出选择数据文件对话框如下右侧所示(该文件的数据格式包含三列数据,中间空格或逗号隔开即可),选择准备好的txt数据文件,然后在模型空间框选所有纵断面图,程序就会按照txt文件中的桩号数据在纵断面图中对应的桩号位置处批量插入标签文本。
代码实现的过程的为:定义标签类,将数据文件转换成标签集合对象,然后框选纵断面图,根据桩号数据将标签插入到对应的位置,主要代码如下:
class BulidingLabel : IComparable//自定义建筑物标签类,并且实现排序接口
{ private double _stakeMark;//桩号记号
private string _name;//名称
private string _blockName;//块名
public string BlockName
{ get{return _blockName;}
set{ _blockName = value; } }
public string BulidingName
{ get { return _name; }
Set { _name = value; } }
public double StakeMark
{ get { return _stakeMark; }
Set { _stakeMark = value; } }
public int CompareTo(BulidingLabel other)//实现排序
{ return this.StakeMark.CompareTo(other.StakeMark); } }
#region 根据块定义 创建标签的块参照,包含属性对象,
ObjectId btrId = bt[blockName]; //获取块表记录的id;
//打开块表记录,获取块定义
BlockTableRecord record = trans.GetObject(btrId, OpenMode.ForWrite) as BlockTableRecord;
//创建一个参照并设置插入点
BlockReference br;//定义一个块参照;
double rotateAngle = 0;//块的旋转角度
br = new BlockReference(pt2, btrId);
br.ScaleFactors = new Scale3d(scale);
br.Layer = layerName;//layerName,, "0"
br.Rotation = rotateAngle.DegreeToRad();
space.AppendEntity(br);//向模型空间中添加块参照实例
#endregion
#region 创建参照块中的属性对象
// 添加属性值,属性块中只包含"桩号"和"名称"这两个属性
attNameValues.Add("桩号", listLabels[i].StakeMark.DoubleToZH());
attNameValues.Add("名称", listLabels[i].BulidingName);
if (record.HasAttributeDefinitions)//判断块定义中是否包含属性定义
{ foreach (ObjectId id in record) //检查是否是一个属性定义
{ AttributeDefinition attDef = trans.GetObject(id, OpenMode.ForRead) as AttributeDefinition;
if (attDef != null)//不等于null,说明具有属性定义,那么就创建属性对象实例
{ //创建一个新的属性对象---实例对象--类似于一个单行文本
AttributeReference attributeText = new AttributeReference();
//从属性定义中获得属性对象的对象特性
attributeText.SetAttributeFromBlock(attDef, br.BlockTransform);
//设置属性对象的其他特性
attributeText.Position = attDef.Position.TransformBy(br.BlockTransform);
attributeText.Rotation = attDef.Rotation;
attributeText.AdjustAlignment(db);
if (textStyleId != ObjectId.Null)
{ attributeText.TextStyleId = textStyleId;//tst[MyAppCon.textStyleName]; }
if (attNameValues.ContainsKey(attDef.Tag))//判断是否包含指定的属性名称,如果有则改属性值
{ attributeText.TextString = attNameValues[attDef.Tag];//设置属性值 }
//向块参照中添加属性对象
br.AttributeCollection.AppendAttribute(attributeText); trans.AddNewlyCreatedDBObject(attributeText, true);
}//end if
}//end foreach
}//end if
#endregion
trans.AddNewlyCreatedDBObject(br, true);
……
插入标签后的实际效果如下图:
当 横断面比较多的时候,手动调整宽度方向和高程方向的显示范围就比较繁琐了,解决方法就是利用工具集命令,框选需要调整的多个横断面,同时进行范围调整。点击“框选横断面图-批量调高程和宽度范围”命令后,弹出的界面如下,设置好调整步长,连续点击相应的按钮,就可以在模型空间中动态观察横断面图的范围显示变化。
现给出“底部高程上升”的主要代码:
using (DocumentLock lockDoc = doc.LockDocument())
{ using (OpenCloseTransaction trans = db.TransactionManager.StartOpenCloseTransaction())
{ try {
//打开块表
BlockTable bt = trans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
//打开模型空间
BlockTableRecord space = trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
foreach (ObjectId sectionViewId in sectionViewIds)
{ //获取横断面对象
SectionView sv = trans.GetObject(sectionViewId, OpenMode.ForWrite) as SectionView;
sv.IsElevationRangeAutomatic = false;
if ((sv.ElevationMin + elevationStep) >= sv.ElevationMax)
{ continue;//如果底部高程大于顶部高程,就进行下一个 }
sv.ElevationMin += elevationStep; }
trans.Commit();//提交修改 ,所有的修改都提交给数据库
_instance.Hide();
_instance.Show(); }
catch (System.Exception ex)
{ MessageBox.Show("\n sorry sorry" + "\n" + ex.Message);
trans.Abort(); }
}//end using 结束事务
}//end using 解锁文档
……
在出纵断面图时,经常需要将纵断面的数据(桩号,高程等)导出来供其他人使用。点击工具集中的命令“纵断面图数据”,弹出如下界面,点击“框选标注栏”按钮,拾取纵断面图中的标注栏行,程序就会自动将数据行按列显示到控件中,最后使用复制粘贴即可将数据导入到Excel中。
下 面给出主要代码:
//声明一个嵌套集合,用来存储多个 List
List> bandList = new List>();
//获取选择集中的数据
SelectionSet ss = selectRes.Value;
int count = ss.Count;//记录下选择了几行数据
ed.WriteMessage("\n你选择了{0}个对象", count);
for (int i = 0; i < count; i++)
{
List mtextList = new List();
ObjectId objId = ss[i].ObjectId;//标注栏对象
//标注栏的标签对象炸开后会产生一个块参照
DBObjectCollection objCollection;//里面只有一个块参照对象
using (OpenCloseTransaction trans = db.TransactionManager.StartOpenCloseTransaction())
{
Autodesk.AutoCAD.DatabaseServices.Entity ent = trans.GetObject(objId, OpenMode.ForWrite) as Autodesk.AutoCAD.DatabaseServices.Entity;
objCollection = new DBObjectCollection();
ent.Explode(objCollection);//里面只有一个块参照对象
trans.Abort();
}
//声明一个mtext集合用于存储数据,因为上面的块炸掉之后会产生很多mtext对象
DBObjectCollection mtextCollection = new DBObjectCollection();
foreach (Autodesk.AutoCAD.DatabaseServices.Entity item in objCollection)
{item.Explode(mtextCollection);//块炸掉之后会产生很多mtext对象
foreach (MText mtext in mtextCollection)
{ mtextList.Add(mtext.Text);}
}
bandList.Add(mtextList);//获取数据并存到list集合中,以便后面使用
}
……
使用C#语言利用Civil3D提供的API接口进行二次开发,在管道工程项目中将遇到的繁琐的操作流程交给计算机处理,提高设计者的工作效率。在其他类似的工程案例中也可以归纳总结,编写出具有针对性的工具集,以应对不同的专业。
[1] 曾洪飞,卢泽林,张帆.AutoCAD VBA & VB.NET开发基础与实例教程(C#版)[M].北京:中国电力出版社,2013.
[2] 李冠亿. 深入浅出AutoCAD.NET 二次开发[M].北京:中国建筑工业出版社,2012.
6