October 2014

Sun Mon Tue Wed Thu Fri Sat
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  










« API wishlist surveys for Max and Maya | Main | Creating an AutoCAD MText object containing different colours using .NET »

June 04, 2010

Changing the layer of an entity in an AutoCAD block using .NET

After seeing Shaan list the results of the latest AUGI wishlist, I started thinking about which of the items would be worth covering either on this blog or via a Plugin of the Month. The second item on the list, “Automatically Differentiate Manually Edited Dimensions”, has (hopefully) been addressed by Dimension Patrol, this month’s Plugin of the Month, so that’s a good start, anyway.

The first item, “Change Objects in a Block to a new Layer”, seemed as good a good place to start as anywhere.

Here’s some C# code that builds upon a technique for selecting/highlighting nested entities shown in a previous post to actually modify their layers.

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.Runtime;

 

namespace NestedObjectModification

{

  public class Commands

  {

    [CommandMethod("CNL")]

    static public void ChangeNestedLayer()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;

 

      // Collection of our selected entities

 

      ObjectIdCollection ids = new ObjectIdCollection();

 

      // The results object for our nested selection

      // (will be reused)

 

      PromptNestedEntityResult rs;

 

      // Start a transaction... will initially be used

      // to highlight the selected entities and then to

      // modify their layer

 

      Transaction tr =

        doc.TransactionManager.StartTransaction();

      using (tr)

      {

        // Loop until cancelled or completed

 

        do

        {

          rs = ed.GetNestedEntity("\nSelect nested entity: ");

 

          if (rs.Status == PromptStatus.OK)

          {

            ids.Add(rs.ObjectId);

 

            HighlightSubEntity(doc, rs);

          }

        }

        while (rs.Status == PromptStatus.OK);

 

        if (ids.Count > 0)

        {

          // Get the name of our destination later

 

          PromptResult pr =

            ed.GetString("\nNew layer for these objects: ");

          if (pr.Status == PromptStatus.OK)

          {

            // Check that the layer exists

 

            string newLay = pr.StringResult;

 

            LayerTable lt =

              tr.GetObject(db.LayerTableId, OpenMode.ForRead)

                as LayerTable;

 

            if (lt.Has(newLay))

            {

              // If so, set the layer name to be the one chosen

              // on each of the selected entitires

 

              for (int i = 0; i < ids.Count; i++)

              {

                Entity ent =

                  tr.GetObject(ids[i], OpenMode.ForWrite) as Entity;

                if (ent != null)

                {

                  ent.Layer = newLay;

                }

              }

            }

            else

            {

              ed.WriteMessage(

                "\nLayer not found in current drawing."

              );

            }

          }

        }

        tr.Commit();

 

        // Regen clears highlighting and reflects the new layer

 

        ed.Regen();

      }

    }

 

    private static void HighlightSubEntity(

      Document doc, PromptNestedEntityResult rs

    )

    {

      // Extract relevant information from the prompt object

 

      ObjectId selId = rs.ObjectId;

      ObjectId[] objIds = rs.GetContainers();

      int len = objIds.Length;

 

      // Reverse the "containers" list

 

      ObjectId[] revIds = new ObjectId[len + 1];

      for (int i = 0; i < len; i++)

      {

        ObjectId id =

          (ObjectId)objIds.GetValue(len - i - 1);

        revIds.SetValue(id, i);

      }

 

      // Now add the selected entity to the end

 

      revIds.SetValue(selId, len);

 

      // Retrieve the sub-entity path for this entity

 

      SubentityId subEnt =

        new SubentityId(SubentityType.Null, 0);

      FullSubentityPath path = new FullSubentityPath(revIds, subEnt);

 

      // Open the outermost container, relying on the open

      // transaction...

 

      ObjectId id2 = (ObjectId)revIds.GetValue(0);

      Entity ent = id2.GetObject(OpenMode.ForRead) as Entity;

 

      // ... and highlight the nested entity

 

      if (ent != null)

        ent.Highlight(path, false);

    }

  }

}

I’d really categorise this as a first attempt, as there are some minor quirks that I’m not fully happy with. For instance, when you cancel the initial selection loop using the escape key, the application still proceeds to ask the user for the destination layer. Also, the current implementation doesn’t limit modification of objects inside Xrefs, which clearly won’t result in an actual drawing change, as the nested entity is not being modified via a long transaction.

But as it stands the application should be complete enough to prove useful and should certainly allow people to provide feedback on whether this should be developed further into a future Plugin of the Month.

After building and NETLOADing the application, you can use the CNL command to change the layer of the nested entities you select. Here are some sample blocks that ship with AutoCAD, followed by the highlighting during the selection and finally the updated contents:

Some standard blocks Selected block contents Modified block contents

blog comments powered by Disqus

Feed/Share

10 Random Posts