[CommandMethod("unnest")]
public void UnNestBlocks()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
PromptSelectionOptions pso
= new PromptSelectionOptions
(); pso.MessageForAdding = "\nSelect Blocks to Un-Nest";
SelectionFilter sf
= new SelectionFilter
(new TypedValue
[1] { new TypedValue
((int)DxfCode
.Start,
"INSERT") }); PromptSelectionResult psr = ed.GetSelection(pso, sf);
if (psr.Status != PromptStatus.OK) return;
Transaction tr = doc.TransactionManager.StartTransaction();
try
{
_tr = tr;
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
_msId = bt[BlockTableRecord.ModelSpace];
_ms = (BlockTableRecord)tr.GetObject(_msId, OpenMode.ForWrite);
HashSet
<BlockReference
> blocksToErase
= new HashSet
<BlockReference
>();
//get unique block defs from the block reference selection
foreach (var id in psr.Value.GetObjectIds().Select(x => (BlockReference)tr.GetObject(x, OpenMode.ForRead)).Select(x => x.BlockTableRecord).Distinct())
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
foreach (ObjectId refId in btr.GetBlockReferenceIds(true, true)) //process all references to block of interest
{
BlockReference bRef = (BlockReference)tr.GetObject(refId, OpenMode.ForRead);
if (bRef.OwnerId == _msId) continue;//if this block is in modelspace then skip it as we are at the desired result
BlockReference cRef = (BlockReference)bRef.Clone();
WalkTable(bRef.OwnerId, ref cRef);
blocksToErase.Add(bRef);
}
}
foreach (var block in blocksToErase)
{
block.UpgradeOpen();
block.Erase();
}
}
finally
{
tr.Commit();
tr.Dispose();
_tr = null;
_msId = ObjectId.Null;
_ms = null; ;
}
ed.Regen();
}
private Transaction _tr;
private ObjectId _msId;
private BlockTableRecord _ms;
/// <summary>
/// Walks up the block table looking for the path(s) to modelspace. Pass a clone of the inquiring block (we're going to transform up the tree, then erase original after.
/// </summary>
/// <param name="ownerId"></param>
/// <returns></returns>
private void WalkTable(ObjectId ownerId, ref BlockReference bRef)
{
if (ownerId == _msId)// if the owner is in modelspace then send copy into modelspace
{
_ms.AppendEntity(bRef);
_tr.AddNewlyCreatedDBObject(bRef, true);
return;
}
else//otherwise let's see if this tree gets referenced to modelspace
{
BlockTableRecord owner = (BlockTableRecord)_tr.GetObject(ownerId, OpenMode.ForWrite);
foreach (ObjectId id in owner.GetBlockReferenceIds(true,true))
{
BlockReference oRef = (BlockReference)_tr.GetObject(id, OpenMode.ForRead);
BlockReference cRef = (BlockReference)bRef.Clone();
cRef.TransformBy(oRef.BlockTransform);
WalkTable(oRef.OwnerId, ref cRef);
if (cRef.OwnerId == ObjectId.Null) cRef.Dispose();//if ownerId is null then this object was not appended to database
}
}
}