Time to go back to basics. I realised recently – on receiving this comment – that I hadn’t specifically covered the nature of Entity.Explode() in a post (even if it’s been used in a few of them, over the years).
Entity.Explode() is one of those tricky methods: it’s actually a faux-ami with the AutoCAD command of the same name, in a very similar way to Database.Purge(). The way in which Explode() and Purge() differ from their “equivalent” commands is that they’re non-destructive: they don’t actually result in a change to the AutoCAD drawing database. Explode() populates a DBObjectCollection with the results of the explode operation, and it’s then up to the caller of the function to add them to the appropriate location (typically the current – i.e. model- or paper- – space). Purge() checks a list of objects for ones that can safely be erased, and then it’s up to the caller of the function to do so.
So there is some occasional – and understandable – confusion around Explode() or Purge() not working as expected.
Here’s a simple approach to mimicking the behaviour of the EXPLODE command programmatically: after calling Entity.Explode() on each selected entity, we optionally erase the original entities and add the results of the Explode() to the drawing.
There’s a lot this code doesn’t do – such as check for entities that did not actually generate any exploded results (and so probably shouldn’t be erased) or output some feedback on what is happening to the command-line – but the principle should be clear enough.
Here’s the C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
namespace Explosion
{
public class Commands
{
[CommandMethod("EXP", CommandFlags.UsePickSet)]
public void ExplodeEntities()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
// Ask user to select entities
PromptSelectionOptions pso =
new PromptSelectionOptions();
pso.MessageForAdding = "\nSelect objects to explode: ";
pso.AllowDuplicates = false;
pso.AllowSubSelections = true;
pso.RejectObjectsFromNonCurrentSpace = true;
pso.RejectObjectsOnLockedLayers = false;
PromptSelectionResult psr = ed.GetSelection(pso);
if (psr.Status != PromptStatus.OK)
return;
// Check whether to erase the original(s)
bool eraseOrig = false;
if (psr.Value.Count > 0)
{
PromptKeywordOptions pko =
new PromptKeywordOptions("\nErase original objects?");
pko.AllowNone = true;
pko.Keywords.Add("Yes");
pko.Keywords.Add("No");
pko.Keywords.Default = "No";
PromptResult pkr = ed.GetKeywords(pko);
if (pkr.Status != PromptStatus.OK)
return;
eraseOrig = (pkr.StringResult == "Yes");
}
Transaction tr =
db.TransactionManager.StartTransaction();
using (tr)
{
// Collect our exploded objects in a single collection
DBObjectCollection objs = new DBObjectCollection();
// Loop through the selected objects
foreach (SelectedObject so in psr.Value)
{
// Open one at a time
Entity ent =
(Entity)tr.GetObject(
so.ObjectId,
OpenMode.ForRead
);
// Explode the object into our collection
ent.Explode(objs);
// Erase the original, if requested
if (eraseOrig)
{
ent.UpgradeOpen();
ent.Erase();
}
}
// Now open the current space in order to
// add our resultant objects
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
db.CurrentSpaceId,
OpenMode.ForWrite
);
// Add each one of them to the current space
// and to the transaction
foreach (DBObject obj in objs)
{
Entity ent = (Entity)obj;
btr.AppendEntity(ent);
tr.AddNewlyCreatedDBObject(ent, true);
}
// And then we commit
tr.Commit();
}
}
}
}
The results of calling the EXP command should be obvious enough – and do not result in anything very visually stimulating – so I’ll finish the post here.