由于工作原因,正式从一个公路交通规划的研究者转变为铁路站场的设计人员,因此目前cad以及bim软件的二次开发是主要的研究工作,之前的sumo学习笔记由于不再有sumo的使用需求,至此停更,谢谢各位的支持。
硕士三年时间,对python的使用渐渐得心应手,但是由于python在很多软件的二次开发中并不是主流,需要对其他语言进行学习,这存在一定的上手难度。由于公司存在对cad与bim软件二次开发的客观需求,因此一直在对这方面进行学习。前几天看到明经论坛的雪山飞狐大佬开发了一款pycad的工具包,是利用ironpython兼容.net的特性,提供了autocad的.net接口,并对.net中部分函数进行了集成,使二次开发更加简洁,并可以脱离python环境,生成dll库文件进行发布,正好符合个人的二次开发需求。鉴于网上对pycad的使用教程不多,开更pycad的学习笔记,方便个人与其他朋友在以后使用中遇到各类问题进行参考。
pycad通过cad中netload载入NFox.Pycad.Acad.dll使用,通过pye或者pyedit指令调用vscode进行二次开发,通过pyrb在cad中进行即时编译。其工具包可在github或者明经论坛中下载,安装方法不多赘述,可参考PyCad工具帮助文档。
下面就开始对pycad使用过程的一些心得进行记录。
一、pycad初探
使用pycad时主要通过导入两个函数调用整体的开发包,分别是:
from pycad.system import *
from pycad.runtime import *
调用后,即可使用http://cad.net中提供的所有函数工具对autocad进行控制。在system与runtime中,.net原始函数包被二次封装,以以下方式进行调用。
"acap": "Autodesk.AutoCAD.ApplicationServices",
"acdb": "Autodesk.AutoCAD.DatabaseServices",
"aced": "Autodesk.AutoCAD.EditorInput",
"acge": "Autodesk.AutoCAD.Geometry",
"acrx": "Autodesk.AutoCAD.Runtime",
"acws": "Autodesk.AutoCAD.Windows",
"acgi": "Autodesk.AutoCAD.GraphicsInterface",
"acgs": "Autodesk.AutoCAD.GraphicsSystem",
"acin": "Autodesk.AutoCAD.Internal",
"acps": "Autodesk.AutoCAD.PlottingServices",
"acco": "Autodesk.AutoCAD.Colors",
由于.net包对任何支持的语言开放相同的函数,因此我们可以比较简单的将其他语言的开发程序转换为python语言。以多段线的vb语言绘制为例,.net开发文档中提供了多段线的绘制程序,如下所示:
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
_
Public Sub AddLightweightPolyline()
'' 获得当前文档和数据库 Get the current document and database
Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
Dim acCurDb As Database = acDoc.Database
''启动一个事务 Start a transaction
Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
'' 以只读方式打开块表 Open the Block table for read
Dim acBlkTbl As BlockTable
acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead)
'' 以写方式打开模型空间块表记录 Open the Block table record Model space for write
Dim acBlkTblRec As BlockTableRecord
acBlkTblRec = acTrans.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), _
OpenMode.ForWrite)
'' 创建一条有两段的多段线 Create a polyline with two segments (3 points)
Dim acPoly As Polyline = New Polyline()
acPoly.SetDatabaseDefaults()
acPoly.AddVertexAt(0, New Point2d(2, 4), 0, 0, 0)
acPoly.AddVertexAt(1, New Point2d(4, 2), 0, 0, 0)
acPoly.AddVertexAt(2, New Point2d(6, 4), 0, 0, 0)
'' 添加新对象到块表记录和事务中 Add the new object to the block table record and the transaction
acBlkTblRec.AppendEntity(acPoly)
acTrans.AddNewlyCreatedDBObject(acPoly, True)
'' 保存新对象到数据库中 Save the new object to the database
acTrans.Commit()
End Using
End Sub
从vb语言角度,这是一个比较复杂的绘制过程。首先要获取当前文档与数据库,这是确定操作的对象;第二步是启动一个事务(实体操作必须启动事务,否则cad将崩溃);第三步是打开块表(块表储存了所有实体数据,因此建立实体时需要打开块表);第四步是打开模型空间(打开模型空间后才能在该空间内画图);第五步是添加多段线在模型空间绘制多段线;第六步是添加新对象到块表记录和事务中。
Pycad将这个过程以更简洁的方式进行记录,如下:
from pycad.system import *
from pycad.runtime import *
@command()#添加命令
def pltest(doc):
with dbtrans(doc) as tr: #获取当前文档、数据库并启动事务
btr = tr.opencurrspace() #打开块表与当前模型空间
#绘制多段线
pl=acdb.Polyline()
pl.AddVertexAt(0, acge.Point2d(2, 4), 0, 0, 0)
pl.AddVertexAt(1, acge.Point2d(4, 2), 0, 0, 0)
pl.AddVertexAt(2, acge.Point2d(6, 4), 0, 0, 0)
arc.SetDatabaseDefaults()
#添加新对象到块表记录和事务中
tr.addentity(btr, pl)
可以发现pycad可以较为简洁的实现.net的相关功能。而其他图元的pycad代码如下:
#直线测试
@command()
def helloworld(doc):
#打开事务
with dbtrans(doc) as tr:
#打开当前空间
btr = tr.opencurrspace()
#向当前空间添加直线
tr.addentity(btr, acdb.Line(acge.Point3d(0,0,0), acge.Point3d(10,10,0)))
#圆弧测试
@command()
def arctest(doc):
with dbtrans(doc) as tr:
btr = tr.opencurrspace()
#四个参数分别为中心点,半径,起始角度,终点角度
arc = acdb.Arc(acge.Point3d(6.25, 9.125, 0),6, 1.117, 3.5605)
arc.SetDatabaseDefaults()
tr.addentity(btr,arc)
#圆测试
@command()
def cirtest(doc):
with dbtrans(doc) as tr:
btr = tr.opencurrspace()
cir = acdb.Circle()
cir.Center = acge.Point3d(5,5,0)
cir.Radius = 5
cir.SetDatabaseDefaults()
tr.addentity(btr,cir)
#样条曲线测试
@command()
def spltest(doc):
with dbtrans(doc) as tr:
btr = tr.opencurrspace()
#获取样条点
p_collection = acge.Point3dCollection()
p_collection.Add(acge.Point3d(0,0,0))
p_collection.Add(acge.Point3d(5,5,0))
p_collection.Add(acge.Point3d(10,0,0))
#切向值
vecTan = acge.Point3d(0.5,0.5,0).GetAsVector()
#五个参数分别为样条点,起始切向,终止切向,degree,fitTolerance
spline = acdb.Spline(p_collection,vecTan,vecTan,4,0.0)
spline.SetDatabaseDefaults()
tr.addentity(btr,spline)
#点测试
@command()
def ptest(doc):
with dbtrans(doc) as tr:
btr = tr.opencurrspace()
p = acdb.DBPoint(acge.Point3d(4,3,0))
p.SetDatabaseDefaults()
tr.addentity(btr,p)
#通过tr对全局属性进行设置
tr.Database.Pdmode = 34
tr.Database.Pdsize = 1
#实体填充测试
@command()
def solidtest(doc):
with dbtrans(doc) as tr:
btr = tr.opencurrspace()
#多个参数对应实体填充的顶点
solid = acdb.Solid(acge.Point3d(10,0,0),acge.Point3d(15,0,0),acge.Point3d(10,8,0),acge.Point3d(15,8,0))
solid.SetDatabaseDefaults()
tr.addentity(btr,solid)
#面域测试
@command()
def Regiontest(doc):
with dbtrans(doc) as tr:
btr = tr.opencurrspace()
#建立圆
cir = acdb.Circle()
cir.Center = acge.Point3d(5,5,0)
cir.Radius = 5
#添加圆入对象组
objcoll = acdb.DBObjectCollection()
objcoll.Add(cir)
#将面域值添加至面域组
regioncoll = acdb.Region.CreateFromCurves(objcoll)
#获取面阈值
region = regioncoll[0]
tr.addentity(btr,region)
#组合面域测试
@command()
def CRegiontest(doc):
with dbtrans(doc) as tr:
btr = tr.opencurrspace()
#建立圆
cir1 = acdb.Circle()
cir1.Center = acge.Point3d(5,5,0)
cir1.Radius = 5
cir2 = acdb.Circle()
cir2.Center = acge.Point3d(5,5,0)
cir2.Radius = 3
#添加圆入对象组
objcoll = acdb.DBObjectCollection()
objcoll.Add(cir1)
objcoll.Add(cir2)
#将面域值添加至面域组
regioncoll = acdb.Region.CreateFromCurves(objcoll)
#获取面阈值
region1 = regioncoll[0]
region2 = regioncoll[1]
if region1.Area > region2.Area:
region1.BooleanOperation(acdb.BooleanOperationType.BoolSubtract,region2)
del region2
tr.addentity(btr,region1)
else:
region2.BooleanOperation(acdb.BooleanOperationType.BoolSubtract,region1)
del region1
tr.addentity(btr,region2)
del cir1,cir2
至此,CAD内部的各类图元都可以顺利导入,事实上,由于.net的特性,导致各个语言在单纯调用.net库使语法结构极其相似,对着C#写成pycad代码,可以很好的让自己意识到各个函数所在位置,建议大家在学习时可以直接参照C#或者vb的.net开发代码,在提升的同时,你会发现pycad在代码量中明显的简洁性。