jun353835273 发表于 2020-2-25 12:48:00

清理dgn

原贴搬运清理dgn
//http://www.theswamp.org/index.php?topic=45030.msg502441#msg502441
using System;
using System.Runtime.InteropServices;
//using Autodesk..ApplicationServices.Core;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using System.Collections.ObjectModel;

namespace DgnPurger
{
    public class Commands
    {
      const string dgnLsDefName = "DGNLSDEF";
      const string dgnLsDictName = "ACAD_DGNLINESTYLECOMP";

      public struct ads_name
      {
            public IntPtr a;
            public IntPtr b;
      };

      //[DllImport("acdb19.dll",
      [DllImport("acdb18.dll",
          CharSet = CharSet.Unicode,
          CallingConvention = CallingConvention.Cdecl,
          EntryPoint = "acdbHandEnt")]
      public static extern int acdbHandEnt(string h, ref ads_name n);

      
      public void PurgeDgnLinetypes()
      {
            var doc =
            Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            using (var tr = doc.TransactionManager.StartTransaction())
            {
                // Start by getting all the "complex" DGN linetypes
                // from the linetype table

                var linetypes = CollectComplexLinetypeIds(db, tr);

                // Store a count before we start removing the ones
                // that are referenced

                var ltcnt = linetypes.Count;

                // Remove any from the "to remove" list that need to be
                // kept (as they have references from objects other
                // than anonymous blocks)

                var ltsToKeep =
                  PurgeLinetypesReferencedNotByAnonBlocks(db, tr, linetypes);

                // Now we collect the DGN stroke entries from the NOD

                var strokes = CollectStrokeIds(db, tr);

                // Store a count before we start removing the ones
                // that are referenced

                var strkcnt = strokes.Count;

                // Open up each of the "keeper" linetypes, and go through
                // their data, removing any NOD entries from the "to
                // remove" list that are referenced

                PurgeStrokesReferencedByLinetypes(tr, ltsToKeep, strokes);

                // Erase each of the NOD entries that are safe to remove

                int erasedStrokes = 0;

                foreach (ObjectId id in strokes)
                {
                  try
                  {
                        var obj = tr.GetObject(id, OpenMode.ForWrite);
                        obj.Erase();
                        if (
                        obj.GetRXClass().Name.Equals("AcDbLSSymbolComponent")
                        )
                        {
                            EraseReferencedAnonBlocks(tr, obj);
                        }
                        erasedStrokes++;
                  }
                  catch (System.Exception ex)
                  {
                        ed.WriteMessage(
                        "\nUnable to erase stroke ({0}): {1}",
                        id.ObjectClass.Name,
                        ex.Message
                        );
                  }
                }

                // And the same for the complex linetypes

                int erasedLinetypes = 0;

                foreach (ObjectId id in linetypes)
                {
                  try
                  {
                        var obj = tr.GetObject(id, OpenMode.ForWrite);
                        obj.Erase();
                        erasedLinetypes++;
                  }
                  catch (System.Exception ex)
                  {
                        ed.WriteMessage(
                        "\nUnable to erase linetype ({0}): {1}",
                        id.ObjectClass.Name,
                        ex.Message
                        );
                  }
                }

                // Remove the DGN stroke dictionary from the NOD if empty

                var nod =
                  (DBDictionary)tr.GetObject(
                  db.NamedObjectsDictionaryId, OpenMode.ForRead
                  );

                ed.WriteMessage(
                  "\nPurged {0} unreferenced complex linetype records" +
                  " (of {1}).",
                  erasedLinetypes, ltcnt
                );

                ed.WriteMessage(
                  "\nPurged {0} unreferenced strokes (of {1}).",
                  erasedStrokes, strkcnt
                );

                if (nod.Contains(dgnLsDictName))
                {
                  var dgnLsDict =
                      (DBDictionary)tr.GetObject(
                        (ObjectId)nod,
                        OpenMode.ForRead
                      );

                  if (dgnLsDict.Count == 0)
                  {
                        dgnLsDict.UpgradeOpen();
                        dgnLsDict.Erase();

                        ed.WriteMessage(
                        "\nRemoved the empty DGN linetype stroke dictionary."
                        );
                  }
                }

                tr.Commit();
            }
      }

      // Collect the complex DGN linetypes from the linetype table

      private static ObjectIdCollection CollectComplexLinetypeIds(
          Database db, Transaction tr
      )
      {
            var ids = new ObjectIdCollection();

            var lt =
            (LinetypeTable)tr.GetObject(
                db.LinetypeTableId, OpenMode.ForRead
            );
            foreach (var ltId in lt)
            {
                // Complex DGN linetypes have an extension dictionary
                // with a certain record inside

                var obj = tr.GetObject(ltId, OpenMode.ForRead);
                if (obj.ExtensionDictionary != ObjectId.Null)
                {
                  var exd =
                      (DBDictionary)tr.GetObject(
                        obj.ExtensionDictionary, OpenMode.ForRead
                      );
                  if (exd.Contains(dgnLsDefName))
                  {
                        ids.Add(ltId);
                  }
                }
            }
            return ids;
      }

      // Collect the DGN stroke entries from the NOD

      private static ObjectIdCollection CollectStrokeIds(
          Database db, Transaction tr
      )
      {
            var ids = new ObjectIdCollection();

            var nod =
            (DBDictionary)tr.GetObject(
                db.NamedObjectsDictionaryId, OpenMode.ForRead
            );

            // Strokes are stored in a particular dictionary

            if (nod.Contains(dgnLsDictName))
            {
                var dgnDict =
                  (DBDictionary)tr.GetObject(
                  (ObjectId)nod,
                  OpenMode.ForRead
                  );

                foreach (var item in dgnDict)
                {
                  ids.Add(item.Value);
                }
            }

            return ids;
      }

      // Remove the linetype IDs that have references from objects
      // other than anonymous blocks from the list passed in,
      // returning the ones removed in a separate list

      private static ObjectIdCollection
          PurgeLinetypesReferencedNotByAnonBlocks(
            Database db, Transaction tr, ObjectIdCollection ids
          )
      {
            var keepers = new ObjectIdCollection();

            // To determine the references from objects in the database,
            // we need to open every object. One reasonably efficient way
            // to do so is to loop through all handles in the possible
            // handle space for this drawing (starting with 1, ending with
            // the value of "HANDSEED") and open each object we can

            // Get the last handle in the db

            var handseed = db.Handseed;

            // Copy the handseed total into an efficient raw datatype

            var handseedTotal = handseed.Value;

            // Loop from 1 to the last handle (could be a big loop)

            var ename = new ads_name();

            for (long i = 1; i < handseedTotal; i++)
            {
                // Get a handle from the counter

                var handle = Convert.ToString(i, 16);

                // Get the entity name using acdbHandEnt()

                var res = acdbHandEnt(handle, ref ename);

                if (res != 5100) // RTNORM
                  continue;

                // Convert the entity name to an ObjectId

                var id = new ObjectId(ename.a);

                // Open the object and check its linetype

                var obj = tr.GetObject(id, OpenMode.ForRead, true);
                var ent = obj as Entity;
                if (ent != null && !ent.IsErased)
                {
                  if (ids.Contains(ent.LinetypeId))
                  {
                        // If the owner does not belong to an anonymous
                        // block, then we take it seriously as a reference

                        var owner =
                        (BlockTableRecord)tr.GetObject(
                            ent.OwnerId, OpenMode.ForRead
                        );
                        if (
                        !owner.Name.StartsWith("*") ||
                        owner.Name.ToUpper() == BlockTableRecord.ModelSpace ||
                        owner.Name.ToUpper().StartsWith(
                            BlockTableRecord.PaperSpace
                        )
                        )
                        {
                            // Move the linetype ID from the "to remove" list
                            // to the "to keep" list

                            ids.Remove(ent.LinetypeId);
                            keepers.Add(ent.LinetypeId);
                        }
                  }
                }
            }
            return keepers;
      }

      // Remove the stroke objects that have references from
      // complex linetypes (or from other stroke objects, as we
      // recurse) from the list passed in

      private static void PurgeStrokesReferencedByLinetypes(
          Transaction tr,
          ObjectIdCollection tokeep,
          ObjectIdCollection nodtoremove
      )
      {
            foreach (ObjectId id in tokeep)
            {
                PurgeStrokesReferencedByObject(tr, nodtoremove, id);
            }
      }

      // Remove the stroke objects that have references from this
      // particular complex linetype or stroke object from the list
      // passed in

      private static void PurgeStrokesReferencedByObject(
          Transaction tr, ObjectIdCollection nodIds, ObjectId id
      )
      {
            var obj = tr.GetObject(id, OpenMode.ForRead);
            if (obj.ExtensionDictionary != ObjectId.Null)
            {
                // Get the extension dictionary

                var exd =
                  (DBDictionary)tr.GetObject(
                  obj.ExtensionDictionary, OpenMode.ForRead
                  );

                // And the "DGN Linestyle Definition" object

                if (exd.Contains(dgnLsDefName))
                {
                  var lsdef =
                      tr.GetObject(
                        exd.GetAt(dgnLsDefName), OpenMode.ForRead
                      );

                  // Use a DWG filer to extract the references

                  var refFiler = new ReferenceFiler();
                  lsdef.DwgOut(refFiler);

                  // Loop through the references and remove any from the
                  // list passed in

                  foreach (ObjectId refid in refFiler.HardPointerIds)
                  {
                        if (nodIds.Contains(refid))
                        {
                            nodIds.Remove(refid);
                        }

                        // We need to recurse, as linetype strokes can reference
                        // other linetype strokes

                        PurgeStrokesReferencedByObject(tr, nodIds, refid);
                  }
                }
            }
            else if (
            obj.GetRXClass().Name.Equals("AcDbLSCompoundComponent") ||
            obj.GetRXClass().Name.Equals("AcDbLSPointComponent")
            )
            {
                // We also need to consider compound components, which
                // don't use objects in their extension dictionaries to
                // manage references to strokes...

                // Use a DWG filer to extract the references from the
                // object itself

                var refFiler = new ReferenceFiler();
                obj.DwgOut(refFiler);

                // Loop through the references and remove any from the
                // list passed in

                foreach (ObjectId refid in refFiler.HardPointerIds)
                {
                  if (nodIds.Contains(refid))
                  {
                        nodIds.Remove(refid);
                  }

                  // We need to recurse, as linetype strokes can reference
                  // other linetype strokes

                  PurgeStrokesReferencedByObject(tr, nodIds, refid);
                }
            }
      }

      // Erase the anonymous blocks referenced by an object

      private static void EraseReferencedAnonBlocks(
          Transaction tr, DBObject obj
      )
      {
            var refFiler = new ReferenceFiler();
            obj.DwgOut(refFiler);

            // Loop through the references and erase any
            // anonymous block definitions
            //
            foreach (ObjectId refid in refFiler.HardPointerIds)
            {
                BlockTableRecord btr =
                  tr.GetObject(refid, OpenMode.ForRead) as BlockTableRecord;
                if (btr != null && btr.IsAnonymous)
                {
                  btr.UpgradeOpen();
                  btr.Erase();
                }
            }
      }
    }
}

single-yu 发表于 2020-2-26 15:02:00

这个是干嘛用的啊?

jinshuitumu 发表于 2020-3-14 19:05:00

好东西
页: [1]
查看完整版本: 清理dgn