Birdy 发表于 2013-7-30 17:10:06

DGN Purge for 2012

Kean has posted this fix for purging DGN linetypes here, but it works for acad 2013 and above.
We are having serious problems with massive amounts of linetypes from DGN drawings, but are on acad 2012.
(see my comment in the link posted)
He suggests you can build the code (found here) to work for 2012, but I have no idea or experience with this.
Can any of you help?
Thanks in advance.

rkmcswain 发表于 2013-7-30 17:34:06

AFAIK, you have to have the dev tools to compile the code for the desired ACAD version.
I bet someone here at the swamp can do it   
See also, the comments in this thread: http://through-the-interface.typepad.com/through_the_interface/2012/12/purging-unwanted-dgn-linestyle-data-from-an-autocad-drawing-using-net.html

BlackBox 发表于 2013-7-30 17:38:07

Here's an Autoloader .bundle compiled to .NET 3.5 for 2012 products... Tested here using Civil 3D 2012 just fine... Just download, unblock, unzip to:
%AppData%\Autodesk\ApplicationPlugins\

... And restart your session. Lemon squeezy.
Cheers

BlackBox 发表于 2013-7-30 17:42:14

Also... For those who'd rather compile themselves, here's the source code (C#)....
Commands.cs
** Note the change from using Autodesk.AutoCAD.ApplicationServices.Core to using Autodesk.AutoCAD.ApplicationServices, and from acdb19.dll to acdb18.dll for the DllImport call.
using System;
using System.Runtime.InteropServices;
//using Autodesk.AutoCAD.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
            {
                // 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();
                }
            }
      }
    }
}

BlackBox 发表于 2013-7-30 17:42:30

... And dependent ReferenceFiler.cs
using System;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

namespace DgnPurger
{
    public class ReferenceFiler : DwgFiler
    {
      public ObjectIdCollection HardPointerIds;
      public ObjectIdCollection SoftPointerIds;
      public ObjectIdCollection HardOwnershipIds;
      public ObjectIdCollection SoftOwnershipIds;

      public ReferenceFiler()
      {
            HardPointerIds = new ObjectIdCollection();
            SoftPointerIds = new ObjectIdCollection();
            HardOwnershipIds = new ObjectIdCollection();
            SoftOwnershipIds = new ObjectIdCollection();
      }

      public override ErrorStatus FilerStatus
      {
            get { return ErrorStatus.OK; }

            set { }
      }

      public override FilerType FilerType
      {
            get { return FilerType.IdFiler; }
      }

      public override long Position
      {
            get { return 0; }
      }

      public override IntPtr ReadAddress() { return new IntPtr(); }
      public override byte[] ReadBinaryChunk() { return null; }
      public override bool ReadBoolean() { return true; }
      public override byte ReadByte() { return new byte(); }
      public override void ReadBytes(byte[] value) { }
      public override double ReadDouble() { return 0.0; }
      public override Handle ReadHandle() { return new Handle(); }
      public override ObjectId ReadHardOwnershipId()
      {
            return ObjectId.Null;
      }
      public override ObjectId ReadHardPointerId()
      {
            return ObjectId.Null;
      }
      public override short ReadInt16() { return 0; }
      public override int ReadInt32() { return 0; }
      public override long ReadInt64() { return 0; }
      public override Point2d ReadPoint2d() { return new Point2d(); }
      public override Point3d ReadPoint3d() { return new Point3d(); }
      public override Scale3d ReadScale3d() { return new Scale3d(); }
      public override ObjectId ReadSoftOwnershipId()
      {
            return ObjectId.Null;
      }
      public override ObjectId ReadSoftPointerId()
      {
            return ObjectId.Null;
      }
      public override string ReadString() { return null; }
      public override ushort ReadUInt16() { return 0; }
      public override uint ReadUInt32() { return 0; }
      public override ulong ReadUInt64() { return 0; }
      public override Vector2d ReadVector2d()
      {
            return new Vector2d();
      }
      public override Vector3d ReadVector3d()
      {
            return new Vector3d();
      }

      public override void ResetFilerStatus() { }
      public override void Seek(long offset, int method) { }

      public override void WriteAddress(IntPtr value) { }
      public override void WriteBinaryChunk(byte[] chunk) { }
      public override void WriteBoolean(bool value) { }
      public override void WriteByte(byte value) { }
      public override void WriteBytes(byte[] value) { }
      public override void WriteDouble(double value) { }
      public override void WriteHandle(Handle handle) { }
      public override void WriteInt16(short value) { }
      public override void WriteInt32(int value) { }
      public override void WriteInt64(long value) { }
      public override void WritePoint2d(Point2d value) { }
      public override void WritePoint3d(Point3d value) { }
      public override void WriteScale3d(Scale3d value) { }
      public override void WriteString(string value) { }
      public override void WriteUInt16(ushort value) { }
      public override void WriteUInt32(uint value) { }
      public override void WriteUInt64(ulong value) { }
      public override void WriteVector2d(Vector2d value) { }
      public override void WriteVector3d(Vector3d value) { }

      public override void WriteHardOwnershipId(ObjectId value)
      {
            HardOwnershipIds.Add(value);
      }

      public override void WriteHardPointerId(ObjectId value)
      {
            HardPointerIds.Add(value);
      }

      public override void WriteSoftOwnershipId(ObjectId value)
      {
            SoftOwnershipIds.Add(value);
      }

      public override void WriteSoftPointerId(ObjectId value)
      {
            SoftPointerIds.Add(value);
      }

      public void reset()
      {
            HardPointerIds.Clear();
            SoftPointerIds.Clear();
            HardOwnershipIds.Clear();
            SoftOwnershipIds.Clear();
      }
    }
}

Birdy 发表于 2013-7-30 18:00:25

DENIM!!!
about 10,000 linetypes gone from one problem file!(ok, I may be exaggerating a little.But probably over a thousand)
easy peasy.
Thanks BB.
When it comes to .net:

BlackBox 发表于 2013-7-30 18:14:54

DENIM!!!
about 10,000 linetypes gone from one problem file!(ok, I may be exaggerating a little.But probably over a thousand)
easy peasy.
Thanks BB.
When it comes to .net:

You're welcome; Kean (and others) did the all the work, I just put it together in a saweet looking package.

rkmcswain 发表于 2013-7-30 18:19:54

I knew someone blackbox would come through quickly!

BlackBox 发表于 2013-7-30 18:56:54


That is kind of you to say, R.K. :beer:

jan.gregorica 发表于 2013-8-2 03:27:35

Hi BlackBox
I downloaded "Autodesk DGN Purge.bundle.zip" file and it works perfectly. I finally managed to remove the thousands of linetypes.
Thank you for your help.
Regards
Jan
页: [1] 2
查看完整版本: DGN Purge for 2012