I stumbled across this wishlist request on the forums, the other day, and thought it worth covering in a blog post.
It’s an interesting little piece of code – nothing very startling, but obviously whenever removing data you have to be a bit careful: in fact I would probably add an “are you sure?” question prior to actually removing the various annotation scales, even if the operation participates in the undo mechanism and can therefore be rolled back easily by the user.
Here’s the C# code for the AIOBJECTSCALEREMOVEOTHERS command (yes, I would normally use a slightly more succinct name, myself, such as DABC for “Delete All But Current”, but I decided to make this one more consistent with the AIOBJECTSCALEREMOVE command).
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
namespace AnnotationScaling
{
public class Commands
{
[CommandMethod(
"AIOBJECTSCALEREMOVEOTHERS",
(CommandFlags.Modal | CommandFlags.UsePickSet)
)]
static public void RemoveAllButCurrentScale()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
// Get the manager object and the list of scales
ObjectContextManager ocm = db.ObjectContextManager;
ObjectContextCollection occ =
ocm.GetContextCollection("ACDB_ANNOTATIONSCALES");
// Prompt the user for objects to process (or get them
// from the pickfirst set)
PromptSelectionOptions pso = new PromptSelectionOptions();
pso.MessageForAdding = "\nSelect annotative objects";
PromptSelectionResult psr = ed.GetSelection(pso);
if (psr.Status != PromptStatus.OK)
return;
// Maintain counters of objects modified and scales removed
int objCount = 0, scaCount = 0;
// Use a flag to check when we first modify an object
bool scalesRemovedForObject = false;
Transaction tr =
doc.TransactionManager.StartTransaction();
using (tr)
{
// If we can't find the current annotation scale in our
// dictionary, we have a problem
if (!occ.HasContext(db.Cannoscale.Name))
{
ed.WriteMessage(
"\nCannot find current annotation scale."
);
return;
}
// Get the ObjectContext associated with the current
// annotation scale
ObjectContext curCtxt =
occ.GetContext(db.Cannoscale.Name);
// Check each selected object
foreach (SelectedObject so in psr.Value)
{
// Open it for read
ObjectId id = so.ObjectId;
DBObject obj = tr.GetObject(id, OpenMode.ForRead);
// Check it's annotative and has the current scale
if (obj.Annotative == AnnotativeStates.True &&
obj.HasContext(curCtxt)
)
{
// Now we get it for write
obj.UpgradeOpen();
// Loop through the various annotation scales in
// the drawing
foreach (ObjectContext oc in occ)
{
// If it's on the object but not current
// (for some reason we have to check the name
// rather than oc == curCtxt)
if (obj.HasContext(oc) &&
oc.Name != db.Cannoscale.Name
)
{
// Remove it and increment our counter/set our
// flag
obj.RemoveContext(oc);
scaCount++;
scalesRemovedForObject = true;
}
}
// Increment our counter for objects once per pass
// and then reset the flag
if (scalesRemovedForObject)
{
objCount++;
scalesRemovedForObject = false;
}
}
}
tr.Commit();
// Report the results
ed.WriteMessage(
"\n{0} scales removed from {1} objects.",
scaCount, objCount
);
}
}
}
}
For fun, I went ahead and manually added the command via the CUI editor, and added it to the corresponding ribbon panel:
If we then launch this command and select some annotative objects, we see that the command reports removing superfluous scales from the selected objects:
Command: AIOBJECTSCALEREMOVEOTHERS
Select annotative objects: Specify opposite corner: 4 found
Select annotative objects:
12 scales removed from 4 objects.
It should be noted that – while it’s unlikely a command this long is going to be entered at the command-line – this command does make use of the implied (aka pickfirst) selection set, should you prefer to prefer working in the noun-verb style. The ribbon item clears the pickfirst selection when launching the command, but it does work if launched via the command-line, in case.