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: