Finding all the AutoCAD entities on a particular layer using .NET

This question came in recently by email:

Is there a way to obtain the object IDs of all the object on a layer? I found the GetAllObjects() method of the Transaction object but it doesn't work.

That's right: GetAllObjects() will return the objects accessed via (or added to) the transaction - it has nothing to do with retrieving objects based on any particular property.

What you need to do is Editor.SelectAll(), the equivalent of acedSSGet("X") in ObjectARX and (ssget "X") in AutoLISP. You need the version where you pass in a SelectionFilter specifying the layer for which to search.

Here's some C# code doing just this, with the hard work encapsulated in a function (GetEntitiesOnLayer()) to make it easier to integrate into your code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;


namespace EntitySelection

{

  public class Commands

  {

    [CommandMethod("EOL")]

    static public void EntitiesOnLayer()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Editor ed = doc.Editor;


      PromptResult pr =

        ed.GetString("\nEnter name of layer: ");

      if (pr.Status == PromptStatus.OK)

      {

        ObjectIdCollection ents =

          GetEntitiesOnLayer(pr.StringResult);

        ed.WriteMessage(

          "\nFound {0} entit{1} on layer {2}",

          ents.Count,

          (ents.Count == 1 ? "y" : "ies"),

          pr.StringResult

        );

      }

    }


    private static ObjectIdCollection

      GetEntitiesOnLayer(string layerName)

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Editor ed = doc.Editor;


      // Build a filter list so that only entities

      // on the specified layer are selected


      TypedValue[] tvs =

        new TypedValue[1] {

            new TypedValue(

              (int)DxfCode.LayerName,

              layerName

            )

          };

      SelectionFilter sf =

        new SelectionFilter(tvs);

      PromptSelectionResult psr =

        ed.SelectAll(sf);


      if (psr.Status == PromptStatus.OK)

        return

          new ObjectIdCollection(

            psr.Value.GetObjectIds()

          );

      else

        return new ObjectIdCollection();

    }

  }

}

Running EOL simply counts the entities on a particular layer (the following is from running in the 3D House.dwg sample drawing):

Command: EOL

Enter name of layer: A-Beam

Found 1 entity on layer A-Beam

Command: EOL

Enter name of layer: A-Concrete

Found 1 entity on layer A-Concrete

Command: EOL

Enter name of layer: Furniture

Found 14 entities on layer Furniture

Command: EOL

Enter name of layer: Legs

Found 16 entities on layer Legs

It would be straightforward to do something more than just count the results of the GetEntitiesOnLayer() function, of course, or even to adapt the function to filter on other properties.

May 2, 2008 in AutoCAD, AutoCAD .NET, Drawing structure, Selection | Permalink | Comments (2) | TrackBack

Understanding the properties of textual linetype segments in AutoCAD

In the last post we looked at using .NET to define complex linetypes containing text segments. In the post I admitted to not knowing specifics about the properties used to create the text segment in the linetype, and, in the meantime, an old friend took pity on me and came to the rescue. :-)

Mike Kehoe, who I've known for many years since we worked together in the Guildford office of Autodesk UK, sent me some information that I've reproduced below. Mike now works for Micro Concepts Ltd., an Autodesk reseller, developer and training centre. He originally wrote the below description in the R12/12 timeframe, but apparently most of it remains valid; and while it refers to the text string used to define a linetype in a .lin file, these are also mostly properties that are exposed via the .NET interface.

Example: Using Text within a Linetype.
A,.5,-.2,["MK",STANDARD,S=.2,R=0.0,X=-0.1,Y=-.1],-.2

The key elements for defining the TEXT are as follows:

"MK" - These are the letters that will be printed along the line.

STANDARD -This tells AutoCAD what text style to apply to the text.  NB: This is optional. When no style is defined AutoCAD will use the current text style – TextStyle holds the setting for the current text style.

[Note from Kean: I found the text style to be mandatory when using the .NET interface.]

S=.2 - This is the text scaling factor. However, there are 2 options: (1) when the text style's height is 0, then S defines the height; in this case, 0.2 units; or (2) when the text style's height parameter is non-zero, the height is found by multiplying the text style's height by this number; in this case, the linetype would place the text at 20% of the height defined in the text style.

R=0.0 - This rotates the text relative to the direction of the line; e.g.: 0.0 means there is no rotation. NB: This is optional. When no rotation is defined AutoCAD will assume zero degrees. The default measurement is degrees; NB: you can use r to specify radians, g for grads, or d for degrees, such as R=150g.

[Note from Kean: just like ObjectARX, the .NET interface accepts radians for this value, in SetShapeRotationAt(). A quick reminder: 360 degrees = 2 x PI radians. So you can pass 90 degrees using "System.Math.PI / 2".]

A=0.0  - This rotates the text relative to the x-axis ("A" is short for Absolute); this ensures the text is always oriented in the same direction, no matter the direction of the line. The rotation is always performed within the text baseline and capital height. That's so that you don't get text rotated way off near the orbit of Pluto.

[Note from Kean: to use this style of rotation using .NET, you need to use SetShapeIsUcsOrientedAt() to make sure the rotation is calculated relative to the current UCS rather than the direction of the line.]

X=-0.1 - This setting moves the text just in the x-direction from the linetype definition vertex.

Y=-0.1 – This setting moves the text in the y-direction from the linetype definition vertex.
These 2 settings can be used to center the text in the line. The units are defined from the linetype scale factor, which is stored in system variable LtScale.

Thanks for the information, Mike!

January 11, 2008 in AutoCAD, AutoCAD .NET, Drawing structure, Object properties | Permalink | Comments (0) | TrackBack

Creating a complex AutoCAD linetype containing text using .NET

In my last post we saw some code to create a simple linetype using .NET. As a comment on that post, Mark said:

Kean, i tried you code and it works great and it also got me thinking... is it possible to programmitically add text in as well? I've tried using ltr.SetTextAt(1, "TEST") but so far i've had no luck, any suggestions???

It turned out to be quite a bit more complicated to make a linetype containing text than merely calling SetTextAt() on one of the segments. In order to understand what properties needed setting, I first loaded the HOT_WATER_SUPPLY linetype from acad.lin (using the LINETYPE command):

Loaded_linetype

I then looked at the contents of the linetype table using ArxDbg (the ObjectARX SDK sample that is very helpful for understanding drawing structure). Here's what the SNOOPDB command - defined by the ArxDbg application - showed for the loaded linetype:

Snooped_linetype

From there it was fairly straightforward to determine the code needed to create our own complex linetype containing text segments. I decided to call the new linetype "COLD_WATER_SUPPLY", and have it resemble the original in every way but placing "CW" in the middle segment, rather than "HW" (with the descriptions updated to match, of course). As I've simply copied the properties of an existing linetype, please don't ask me to explain what they all mean. :-)

Here's the C# code:

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.Geometry;

using Autodesk.AutoCAD.EditorInput;


namespace Linetype

{

  public class Commands

  {

    [CommandMethod("CCL")]

    public void CreateComplexLinetype()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;


      Transaction tr =

        db.TransactionManager.StartTransaction();

      using (tr)

      {

        // We'll use the textstyle table to access

        // the "Standard" textstyle for our text

        // segment


        TextStyleTable tt =

          (TextStyleTable)tr.GetObject(

            db.TextStyleTableId,

            OpenMode.ForRead

          );


        // Get the linetype table from the drawing


        LinetypeTable lt =

          (LinetypeTable)tr.GetObject(

            db.LinetypeTableId,

            OpenMode.ForWrite

          );


        // Create our new linetype table record...


        LinetypeTableRecord ltr =

          new LinetypeTableRecord();


        // ... and set its properties


        ltr.Name = "COLD_WATER_SUPPLY";

        ltr.AsciiDescription =

          "Cold water supply ---- CW ---- CW ---- CW ----";

        ltr.PatternLength = 0.9;

        ltr.NumDashes = 3;


        // Dash #1


        ltr.SetDashLengthAt(0, 0.5);


        // Dash #2


        ltr.SetDashLengthAt(1, -0.2);

        ltr.SetShapeStyleAt(1, tt["Standard"]);

        ltr.SetShapeNumberAt(1, 0);

        ltr.SetShapeOffsetAt(1, new Vector2d(-0.1,-0.05));

        ltr.SetShapeScaleAt(1, 0.1);

        ltr.SetShapeIsUcsOrientedAt(1, false);

        ltr.SetShapeRotationAt(1, 0);

        ltr.SetTextAt(1, "CW");


        // Dash #3


        ltr.SetDashLengthAt(2, -0.2);


        // Add the new linetype to the linetype table


        ObjectId ltId = lt.Add(ltr);

        tr.AddNewlyCreatedDBObject(ltr, true);


        // Create a test line with this linetype


        BlockTable bt =

          (BlockTable)tr.GetObject(

            db.BlockTableId,

            OpenMode.ForRead

          );

        BlockTableRecord btr =

          (BlockTableRecord)tr.GetObject(

            bt[BlockTableRecord.ModelSpace],

            OpenMode.ForWrite

          );


        Line ln =

          new Line(

            new Point3d(0, 0, 0),

            new Point3d(10, 10, 0)

          );


        ln.SetDatabaseDefaults(db);

        ln.LinetypeId = ltId;


        btr.AppendEntity(ln);

        tr.AddNewlyCreatedDBObject(ln, true);


        tr.Commit();

      }

    }

  }

}

And here's the result of calling the CCL command and zooming in on the created line:

Linetype_with_text

January 9, 2008 in AutoCAD, AutoCAD .NET, Drawing structure, Object properties | Permalink | Comments (6) | TrackBack

Creating an AutoCAD linetype programmatically using .NET

Happy New Year, everyone!

I had a very relaxing break over the holiday period: during the better part of two weeks I managed to stay away from my PC and even my BlackBerry, which I admit I'm generally not very good at ignoring. So now I'm easing back into the swing of things, remembering how to type and open modelspaces, among other things. :-)

To save my brain from unnecessary stress during the first few weeks of 2008, I've decided to take inspiration from the ADN website. Today's post is based on this DevNote, which shows how to create a custom linetype using ObjectARX.

Here's some equivalent code in C#:

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.Geometry;

using Autodesk.AutoCAD.EditorInput;


namespace Linetype

{

  public class Commands

  {

    [CommandMethod("CL")]

    public void CreateLinetype()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;


      Transaction tr =

        db.TransactionManager.StartTransaction();

      using (tr)

      {

        // Get the linetype table from the drawing


        LinetypeTable lt =

          (LinetypeTable)tr.GetObject(

            db.LinetypeTableId,

            OpenMode.ForWrite

          );


        // Create our new linetype table record...


        LinetypeTableRecord ltr =

          new LinetypeTableRecord();


        // ... and set its properties


        ltr.AsciiDescription = "T E S T -";

        ltr.PatternLength = 0.75;

        ltr.NumDashes = 2;

        ltr.SetDashLengthAt(0, 0.5);

        ltr.SetDashLengthAt(1,-0.25);

        ltr.Name = "TESTLINTEYPE";


        // Add the new linetype to the linetype table


        ObjectId ltId = lt.Add(ltr);

        tr.AddNewlyCreatedDBObject(ltr,true);


        // Create a test line with this linetype


        BlockTable bt =

          (BlockTable)tr.GetObject(

            db.BlockTableId,

            OpenMode.ForRead

          );

        BlockTableRecord btr =

          (BlockTableRecord)tr.GetObject(

            bt[BlockTableRecord.ModelSpace],

            OpenMode.ForWrite

          );


        Line ln =

          new Line(

            new Point3d(0, 0, 0),

            new Point3d(10, 10, 0)

          );


        ln.SetDatabaseDefaults(db);

        ln.LinetypeId = ltId;


        btr.AppendEntity(ln);

        tr.AddNewlyCreatedDBObject(ln, true);


        tr.Commit();

      }

    }

  }

}

Once you've run the CL command, Zoom Extents to see a line that has been created with our new custom linetype.

January 7, 2008 in AutoCAD, AutoCAD .NET, Drawing structure, Object properties | Permalink | Comments (4) | TrackBack

Accessing the active space or layout in an AutoCAD drawing using .NET

This question was asked as comment to a previous post by har!s:

Thanks a lot for the code. I have yet to see 2008 and MultiLeader. But I presume that it works on both Model and paper spaces. In that case, what is the best method to make the operation space independent? i.e., it should work on active space irrespective of whether it's model or paper. I think this will be generally applicable to almost all the entity creations.

The question is very valid and does indeed apply to a lot of entity creation - and other - activities. Most of the time I simply show how to open the modelspace in my code, for example:

  Document doc =

    Application.DocumentManager.MdiActiveDocument;

  Editor ed = doc.Editor;

  Database db = doc.Database;

  Transaction tr =

    db.TransactionManager.StartTransaction();

  using (tr)

  {

    BlockTable bt =

      (BlockTable)tr.GetObject(

        db.BlockTableId,

        OpenMode.ForRead

      );

    BlockTableRecord btr =

      (BlockTableRecord)tr.GetObject(

        bt[BlockTableRecord.ModelSpace],

        OpenMode.ForWrite

      );

    // ...

  }

The key statement here is at the end, where we use GetObject() to open the BlockTableRecord to which we want to (for example) append an entity. The form we use is:

  bt[BlockTableRecord.ModelSpace]

Breaking this down: we're actually looking up the ObjectId of the BlockTableRecord with the name of "*MODEL_SPACE", which is the string stored in the static ModelSpace property of the BlockTableRecord class.

Here are a few different options for what we might do here:

  1. Use either BlockTableRecord.ModelSpace or BlockTableRecord.PaperSpace, if we know that we want to access either of these containers (the current approach).
  2. Use foreach() on the BlockTable to iterate through the various BlockTableRecords: you can open each one using GetObject() and check the IsLayout property to find those that are either modelspace or paperspace layouts.
  3. Use db.CurrentSpaceId to open the currently active space in that particular database.

Option 3 is really the answer to this question, which makes the code like this:

  Document doc =

    Application.DocumentManager.MdiActiveDocument;

  Editor ed = doc.Editor;

  Database db = doc.Database;

  Transaction tr =

    db.TransactionManager.StartTransaction();

  using (tr)

  {

    BlockTable bt =

      (BlockTable)tr.GetObject(

        db.BlockTableId,

        OpenMode.ForRead

      );

    BlockTableRecord btr =

      (BlockTableRecord)tr.GetObject(

        db.CurrentSpaceId,

        OpenMode.ForWrite

      );

    // ...

  }

September 10, 2007 in AutoCAD, AutoCAD .NET, Drawing structure | Permalink | Comments (2) | TrackBack

Purging registered application names from a folder of AutoCAD drawings using .NET

In the last post we looked at some code to programmatically purge Registered Application names from the drawing currently active in AutoCAD. In this post we take the "batching" code first used in this previous post and apply it to this problem.

What we end up with is an additional command called PF which asks the user to specify a folder and then purges the RegApps from the DWGs in that folder, saving those files that end up being modified with the "_purged" suffix.

One point to note is the use of the Database.RetainOriginalThumbnailBitmap property: as we're not making any graphical changes it's fairly safe to set this to true, which retains the pervious thumbnail bitmap, rather than it being blank in the new drawing. If you were to set it to true after graphical changes nothing especially serious would happen, but it could be confusing for users if the preview differed substantially from the DWG contents.

Here's the C# code with the additional lines in red:

    1 using Autodesk.AutoCAD.ApplicationServices;

    2 using Autodesk.AutoCAD.DatabaseServices;

    3 using Autodesk.AutoCAD.EditorInput;

    4 using Autodesk.AutoCAD.Runtime;

    5 using System.IO;

    6 using System;

    7

    8 namespace Purger

    9 {

   10   public class Commands

   11   {

   12     [CommandMethod("PF")]

   13     public void PurgeFiles()

   14     {

   15       Document doc =

   16         Application.DocumentManager.MdiActiveDocument;

   17       Editor ed = doc.Editor;

   18

   19       PromptResult pr =

   20         ed.GetString(

   21           "\nEnter folder containing DWGs to process: "

   22         );

   23       if (pr.Status != PromptStatus.OK)

   24         return;

   25       string pathName = pr.StringResult;

   26

   27       string[] fileNames =

   28         Directory.GetFiles(pathName, "*.dwg");

   29

   30       // We'll use some counters to keep track

   31       // of how the processing is going

   32

   33       int processed = 0, saved = 0, problem = 0;

   34

   35       foreach (string fileName in fileNames)

   36       {

   37         if (fileName.EndsWith(

   38               ".dwg",

   39               StringComparison.CurrentCultureIgnoreCase

   40             )

   41         )

   42         {

   43           string outputName =

   44             fileName.Substring(

   45               0,

   46               fileName.Length - 4) +

   47             "_purged.dwg";

   48           Database db = new Database(false, true);

   49           using (db)

   50           {

   51             try

   52             {

   53               ed.WriteMessage(

   54                 "\n\nProcessing file: " + fileName

   55               );

   56

   57               db.ReadDwgFile(

   58                 fileName,

   59                 FileShare.ReadWrite,

   60                 false,

   61                 ""

   62               );

   63

   64               db.RetainOriginalThumbnailBitmap = true;

   65

   66               int objectsPurged =

   67                 PurgeDatabase(db);

   68

   69               // Display the results

   70

   71               ed.WriteMessage(

   72                 "\nPurged {0} object{1}",

   73                 objectsPurged,

   74                 objectsPurged == 1 ? "" : "s"

   75               );

   76

   77               // Only save if we changed something

   78

   79               if (objectsPurged > 0)

   80               {

   81                 ed.WriteMessage(

   82                   "\nSaving to file: {0}", outputName

   83                 );

   84

   85                 db.SaveAs(

   86                   outputName,

   87                   DwgVersion.Current

   88                 );

   89                 saved++;

   90               }

   91               processed++;

   92             }

   93             catch (System.Exception ex)

   94             {

   95               ed.WriteMessage(

   96                 "\nProblem processing file: {0} - \"{1}\"",

   97                 fileName,

   98                 ex.Message

   99               );

  100               problem++;

  101             }

  102           }

  103         }

  104       }

  105       ed.WriteMessage(

  106         "\n\nSuccessfully processed {0} files," +

  107         " of which {1} had objects to purge" +

  108         " and an additional {2} had errors " +

  109         "during reading/processing.",

  110         processed,

  111         saved,

  112         problem

  113       );

  114     }

  115

  116     [CommandMethod("PC")]

  117     public void PurgeCurrentDocument()

  118     {

  119       Document doc =

  120         Application.DocumentManager.MdiActiveDocument;

  121       Database db = doc.Database;

  122       Editor ed = doc.Editor;

  123

  124       int count =

  125         PurgeDatabase(db);

  126

  127       ed.WriteMessage(

  128         "\nPurged {0} object{1} from " +

  129         "the current database.",

  130         count,

  131         count == 1 ? "" : "s"

  132       );

  133     }

  134

  135     private static int PurgeDatabase(Database db)

  136     {

  137       int idCount = 0;

  138

  139       Transaction tr =

  140         db.TransactionManager.StartTransaction();

  141       using (tr)

  142       {

  143         // Create the list of objects to "purge"

  144

  145         ObjectIdCollection idsToPurge =

  146           new ObjectIdCollection();

  147

  148         // Add all the Registered Application names

  149

  150         RegAppTable rat =

  151           (RegAppTable)tr.GetObject(

  152             db.RegAppTableId,

  153             OpenMode.ForRead

  154         );

  155

  156         foreach (ObjectId raId in rat)

  157         {

  158           if (raId.IsValid)

  159           {

  160             idsToPurge.Add(raId);

  161           }

  162         }

  163

  164         // Call the Purge function to filter the list

  165

  166         db.Purge(idsToPurge);

  167

  168         Document doc =

  169           Application.DocumentManager.MdiActiveDocument;

  170         Editor ed = doc.Editor;

  171

  172         ed.WriteMessage(

  173           "\nRegistered applications being purged: "

  174         );

  175

  176         // Erase each of the objects we've been

  177         // allowed to

  178

  179         foreach (ObjectId id in idsToPurge)

  180         {

  181           DBObject obj =

  182             tr.GetObject(id, OpenMode.ForWrite);

  183

  184           // Let's just add to me "debug" code

  185           // to list the registered applications

  186           // we're erasing

  187

  188           RegAppTableRecord ratr =

  189             obj as RegAppTableRecord;

  190           if (ratr != null)

  191           {

  192             ed.WriteMessage(

  193               "\"{0}\" ",

  194               ratr.Name

  195             );

  196           }

  197

  198           obj.Erase();

  199         }

  200

  201         // Return the number of objects erased

  202         // (i.e. purged)

  203

  204         idCount = idsToPurge.Count;

  205         tr.Commit();

  206       }

  207       return idCount;

  208     }

  209   }

  210 }

You can download the source file from here.

August 15, 2007 in AutoCAD, AutoCAD .NET, Batch processing, Drawing structure, Purge | Permalink | Comments (10) | TrackBack

Purging registered application names in the current AutoCAD drawing using .NET

Purging can seriously reduce the size of AutoCAD drawings by removing unnecessary symbol table and dictionary entries. The PURGE command in AutoCAD allows you to safely purge these non-graphical objects (layers, linetypes, block definitions, etc.).

Since AutoCAD 2005 (if I recall correctly), PURGE also supports the removal of Registered Application names. Applications that make use of Extended Entity Data (XData) must register unique application names in drawings. A few applications have, in the past, created many more names than they required, and as these RegApp names get copied from drawing to drawing (when they get XRefed, for instance), they ended spreading from DWG file to DWG file (one comparison I remember hearing was to a virus, although that was perhaps a little extreme). To the best of my knowledge the applications that mistakenly caused this problem have now been fixed (and shall remain nameless), but there are still drawings out there with a lot of these records, which is ultimately why we extended PURGE to address the problem from within AutoCAD.

Anyway, I've chosen to implement a command to purge these RegApp names - even though it's now there in the product - really just an example of how to code this type of functionality. It could very easily be extended to handle the specific data you feel needs purging in your company's (or customers') DWG files.

The Database.Purge() function available in .NET wraps AcDbDatabase::purge(). These functions are both misleadingly named, as neither of them actually performs a purge on the database. What they do - and this is actually more useful, as it gives you more control - is filter a list of object IDs you pass in, removing any that cannot safely be purged by your application. So they would more accurately be named TellMeWhatCanSafelyBePurged(), or something like that. Typically objects get removed from the list because a reference exists somewhere in the drawing to that object - such as from an entity to a layer (making the layer dangerous to purge). The code calling the Purge function will usually then erase the objects that have been returned. And that's how the PURGE command is implemented.

Here's some C# code that purges the Registered Application names in the current document:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using System.IO;

using System;


namespace Purger

{

  public class Commands

  {

    [CommandMethod("PC")]

    public void PurgeCurrentDocument()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;


      int count =

        PurgeDatabase(db);


      ed.WriteMessage(

        "\nPurged {0} object{1} from " +

        "the current database.",

        count,

        count == 1 ? "" : "s"

      );

    }


    private static int PurgeDatabase(Database db)

    {

      int idCount = 0;


      Transaction tr =

        db.TransactionManager.StartTransaction();

      using (tr)

      {

        // Create the list of objects to "purge"


        ObjectIdCollection idsToPurge =

          new ObjectIdCollection();


        // Add all the Registered Application names


        RegAppTable rat =

          (RegAppTable)tr.GetObject(

            db.RegAppTableId,

            OpenMode.ForRead

        );


        foreach (ObjectId raId in rat)

        {

          if (raId.IsValid)

          {

            idsToPurge.Add(raId);

          }

        }


        // Call the Purge function to filter the list


        db.Purge(idsToPurge);


        Document doc =

          Application.DocumentManager.MdiActiveDocument;

        Editor ed = doc.Editor;


        ed.WriteMessage(

          "\nRegistered applications being purged: "

        );


        // Erase each of the objects we've been

        // allowed to


        foreach (ObjectId id in idsToPurge)

        {

          DBObject obj =

            tr.GetObject(id, OpenMode.ForWrite);


          // Let's just add to me "debug" code

          // to list the registered applications

          // we're erasing


          RegAppTableRecord ratr =

            obj as RegAppTableRecord;

          if (ratr != null)

          {

            ed.WriteMessage(

              "\"{0}\" ",

              ratr.Name

            );

          }


          obj.Erase();

        }


        // Return the number of objects erased

        // (i.e. purged)


        idCount = idsToPurge.Count;

        tr.Commit();

      }

      return idCount;

    }

  }

}

Here's what happens when you run the PC command:

Command: PC

Registered applications being purged: "AcadAnnoPO" "PE_URL" "AcadAnnoAV"

"ACAD_EXEMPT_FROM_CAD_STANDARDS"

Purged 4 objects from the current database.

In the next post we'll look at extending this to - once again - work on a folder of drawings.

August 13, 2007 in AutoCAD, AutoCAD .NET, Drawing structure, Purge | Permalink | Comments (4) | TrackBack

Moving entities from one AutoCAD layer to another using .NET

Firstly I should apologise to those readers using RSS to access this site: I've been playing around with the configuration, to integrate FeedBurner but also to switch from publishing entire articles via RSS to publishing introductions - my posts are just too long, which seems to cause a problem for some RSS readers. So you may have received multiple versions of the same articles for the last few weeks - sorry about that.

For those of you who have not yet subscribed via RSS - please see the new options in the side-bar on the left: it should now be simpler for you to use your favourite RSS reader to pull down excerpts of the content I publish, rather than checking the site itself.

OK, now onto the real content. I had this question come in from António Rodrigues, an engineering student from Portugal:

I'm doing a project at school about hydraulics calculations, where i have get some data from AutoCAD. [...] I need to get all the objects from a single layer in the drawing, so i can use them to perform the calculations needed.

I put together some code for Antonio which uses Editor.SelectAll() with an appropriate SelectionFilter to get the list of entities on a particular layer. Just for fun I then extended the code to allow the user to enter a new layer name for these entities to be moved to.

Here's the C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;


namespace LayerTools

{

  public class Commands

  {