考虑到项目需求,决定采用AutoCAD中的Accoreconsole.exe+.Net Dll来实现,对Accoreconsole不太了解的同学可以自行百度,总之一句话,要想高效的批量处理dwg文件,这个AutoCAD控制台是必须要了解的。
对AutoCAD进行批量处理,以愚人之见,就是如下三个步骤:
- 用C#开发.net DLL程序,生成所有需要的AutoCAD命令(Command)。
- 编写SCR指令文件,在SCR中使用netload加载以上DLL并处理需要的AutoCAD命令(Command)。
- 用VBS捏合所有关于关于window下文件的处理(很遗憾,本人来自工控行业,目前只考虑windows平台,MAC、Linux暂不考虑)并调用Accoreconsole.exe,处理第2步中的SCR指令文件。
经过对项目需求的进一步分析,本人觉得最佳的方法就是新建一个AutoCAD文件,在此文件中新建两个块DTL-L和DTL-R,分别对应即将被替换掉的TCDN()-L, TCDN()-R, 其中()内可能为任意字符。
下图是创建好的dwg文件,命名为StandardBlock.dwg
创建好这个StandardBlock.dwg后,我们需要做的第一步就是在每一个待修改的图纸中,执行一个命令,将StandardBlock.dwg中的这两个块(DTL-L和DTL-R)引入到当前图纸中,然后进行替换。我们先来开发如何实现从另一份图纸中拷贝块的信息到当前图纸。
本人使用VS2019,其他版本类似
类库项目名称命名为CADSmart, 注意,.NET Framework框架版本很重要,太低的话有可能会导致与AutoCAD的DLL不兼容。这里我选用.NET Framework 4.6用来兼容AutoCAD 2018
在AutoCAD的安装目录中找到如下DLL并添加到项目引用
创建此类的目的是将所有关于AutoCAD的操作封装成静态方法,从而在CADSmart.cs中进行调用。
static public void ImportBlocksFrmDwg(this Database desdb, string sourceFileName)
{
Database sourceDb = new Database(false, true);
try
{
sourceDb.ReadDwgFile(sourceFileName, System.IO.FileShare.Read, true, null);
ObjectIdCollection blocks = new ObjectIdCollection();
Autodesk.AutoCAD.DatabaseServices.TransactionManager tranm = sourceDb.TransactionManager;
using (Transaction tran = tranm.StartTransaction())
{
BlockTable bt = (BlockTable)tran.GetObject(sourceDb.BlockTableId, OpenMode.ForRead, false);
foreach (ObjectId btrId in bt)
{
BlockTableRecord btr = tranm.GetObject(btrId, OpenMode.ForRead, false) as BlockTableRecord;
//只加入命名块和非布局块到复制列表中
if (!btr.IsAnonymous && !btr.IsLayout)
{
blocks.Add(btrId);
}
btr.Dispose();
}
bt.Dispose();
}
IdMapping mapping = new IdMapping();
sourceDb.WblockCloneObjects(blocks, desdb.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog("错误信息" + ex.Message);
}
//操作完成,销毁源数据库
sourceDb.Dispose();
}
二、开发块替换程序
同样在Utility.cs中添加如下静态方法,使用引入的块进行块的替换,首先得到原先块参照的EID,保存在strEID中,并保存原块参照的插入位置(oldLocation)和比例(oldScale),之后删除此块参照,并根据此块参照的类型,决定是插入DTL-L还是DTL-R,插入块后,更新块属性,将strEID赋值给块属性。
static public void ReplaceBlock(this Database db)
{
using (var tr = db.TransactionManager.StartTransaction())
{
var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
// check if the block table contains old block
List listId = new List();
foreach (ObjectId id in bt)
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead, false);
if (btr.Name.Length!=7)
{
continue;
}
if(btr.Name.Substring(0,4)=="TCDN" && (btr.Name.Substring(5,2)=="-L" || btr.Name.Substring(5, 2) == "-R"))
{
listId.Add(id);
}
}
// check if the block table contains onew block
ObjectId newBlockIdL = new ObjectId();
ObjectId newBlockIdR = new ObjectId();
if (bt.Has("DTL-L"))
{
newBlockIdL = bt["DTL-L"];
}
if (bt.Has("DTL-R"))
{
newBlockIdR = bt["DTL-R"];
}
foreach (ObjectId objectId in listId)
{
// replace all references to old block by references to new block
var oldBtr = (BlockTableRecord)tr.GetObject(objectId, OpenMode.ForRead);
foreach (ObjectId id in oldBtr.GetBlockReferenceIds(true, true))
{
var br = (BlockReference)tr.GetObject(id, OpenMode.ForWrite);
AttributeCollection attCol = br.AttributeCollection;
string strEID = string.Empty;
foreach (ObjectId attId in attCol)
{
AttributeReference attRef = (AttributeReference)tr.GetObject(attId, OpenMode.ForWrite);
if (attRef.Tag == "EID")
{
strEID = attRef.TextString;
break;
}
}
Scale3d oldScale = br.ScaleFactors;
Point3d oldLocation = br.Position;
br.Erase();
//BlockReference newBR;
ObjectId myBlockId = new ObjectId();
string blkName = string.Empty;
if (oldBtr.Name.Substring(0, 4) == "TCDN" && oldBtr.Name.Substring(5, 2) == "-L")
{
myBlockId = newBlockIdL;
blkName = "DTL-L";
}
else
{
myBlockId = newBlockIdR;
blkName = "DTL-R";
}
BlockTableRecord ms = bt[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForWrite) as BlockTableRecord;
BlockTableRecord blockDef = bt[blkName].GetObject(OpenMode.ForRead) as BlockTableRecord;
using (BlockReference blockRef = new BlockReference(oldLocation, blockDef.ObjectId))
{
//Add the block reference to modelspace
blockRef.ScaleFactors = oldScale;
ms.AppendEntity(blockRef);
tr.AddNewlyCreatedDBObject(blockRef, true);
foreach (ObjectId myid in blockDef)
{
DBObject obj = myid.GetObject(OpenMode.ForRead);
AttributeDefinition attDef = obj as AttributeDefinition;
if ((attDef != null) && (!attDef.Constant))
{
using (AttributeReference attRef = new AttributeReference())
{
attRef.SetAttributeFromBlock(attDef, blockRef.BlockTransform);
attRef.TextString = strEID;
blockRef.AttributeCollection.AppendAttribute(attRef);
tr.AddNewlyCreatedDBObject(attRef, true);
}
}
}
}
}
}
tr.Commit();
}
}



