天天看點

AutoCAD C# 二次開發項目----批量替換塊(2)

項目總體規劃

考慮到項目需求,決定采用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指令檔案。

項目的具體實施

1. 開發.net DLL程式

一、開發塊引入程式

經過對項目需求的進一步分析,本人覺得最佳的方法就是建立一個AutoCAD檔案,在此檔案中建立兩個塊DTL-L和DTL-R,分别對應即将被替換掉的TCDN()-L, TCDN()-R, 其中()内可能為任意字元。

下圖是建立好的dwg檔案,命名為StandardBlock.dwg

AutoCAD C# 二次開發項目----批量替換塊(2)

建立好這個StandardBlock.dwg後,我們需要做的第一步就是在每一個待修改的圖紙中,執行一個指令,将StandardBlock.dwg中的這兩個塊(DTL-L和DTL-R)引入到目前圖紙中,然後進行替換。我們先來開發如何實作從另一份圖紙中拷貝塊的資訊到目前圖紙。

1)建立.net framework 類庫項目

本人使用VS2019,其他版本類似

AutoCAD C# 二次開發項目----批量替換塊(2)
2)命名類庫名稱并更改.NET Framework 版本

類庫項目名稱命名為CADSmart, 注意,.NET Framework架構版本很重要,太低的話有可能會導緻與AutoCAD的DLL不相容。這裡我選用.NET Framework 4.6用來相容AutoCAD 2018

AutoCAD C# 二次開發項目----批量替換塊(2)
3)添加AutoCAD 庫的引用

在AutoCAD的安裝目錄中找到如下DLL并添加到項目引用

AutoCAD C# 二次開發項目----批量替換塊(2)
4)建立Utility類并添加靜态方法

建立此類的目的是将所有關于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<ObjectId> listId = new List<ObjectId>();
               
               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();
           }
       }
           

繼續閱讀