Assuming I have a BlockReferenceId As ObjectId returned from a function that selects an object, how do I go about saving this specific object to a new file after exploding it's contents (nested explode if possible).
I have been trying to add the objects as DBObjects to a separate Database() and save that, but it isn't working correctly.
Public Function SelectBlockRef(ByVal doc As Document) As ObjectId
Dim peo As New PromptEntityOptions("Select a Part to Delete")
peo.AllowNone = True
peo.SetRejectMessage("Only BlockReferences may be selected.")
peo.AddAllowedClass(GetType(BlockReference), True)
Dim per As PromptEntityResult = doc.Editor.GetEntity(peo)
If per.Status = PromptStatus.OK Then
Using doc.TransactionManager.StartTransaction()
Dim br As BlockReference = DirectCast(per.ObjectId.GetObject(OpenMode.ForRead), BlockReference)
Return br.BlockTableRecord
End Using
Else
Return ObjectId.Null
End If
End Function
Dim selId = SelectBlockRef(doc)
If (selId.IsNull) Then
Core.Application.ShowAlertDialog("Please select an block to continue.")
Return
End If
Using tempFileDb As New Database(False, False)
Using tr As Transaction = db.TransactionManager.StartTransaction()
'Dim bt As BlockTable = tr.GetObject(selId, OpenMode.ForRead)
'Dim btr As BlockTableRecord = tr.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead)
Dim btr As BlockTableRecord = DirectCast(tr.GetObject(selId, OpenMode.ForRead), BlockTableRecord)
Dim addedSelectedObjects As Int32 = 0
For Each btrID As ObjectId In btr
Dim dboObj As DBObject = tr.GetObject(btrID, OpenMode.ForRead)
tempFileDb.AddDBObject(dboObj)
addedSelectedObjects += 1
Next
If addedSelectedObjects > 0 Then
tr.Commit()
tempFileDb.SaveAs(tempDirectory + tempFileName, DwgVersion.AC1027)
End If
End Using
End Using
Solved! Go to Solution.
Solved by norman.yuan. Go to Solution.
You cannot just open DBObjects (in your code entities in a BlockTableRecord in "db" - current drawing's database, I suppose), and then add them to another database (tempFileDb). You need to use Database.WblockCloneObjects() to copy DBObjects from a drawing database to another. Search this forum or the internet for WblockCloneObjects(), you would find plenty of sample code.
Norman Yuan
What then would be the easiest way to select a block, explode it, then export everything to a .SAT file?
Now, your question is total different from your original post and different from the code your originally showed.
I do not work with Solid and *.sat file, and only knows that you need to use AutoCAD COM API's AcadDocument.Export() to export Solid/Region data to *.sat file. However, I do not see exporting SAT file has anything to do with exploding block (BlockReference!), at least not directly.
Exploding BlockReference would be very easy and straightforward: just get the block reference (either ask user to select, or identify by your code with certain criteria you know), then call Explode() or ExplodeToOwnerSpace(), depending what you want to do with the generated block elements. The former, gives all elements as non-database-residing entities and you decide whether to add them to the current drawing's database or not; the latter added the element into the Model/PaperSpace the block reference is in. IN both case, you also are responsible to decide what to do with the original Block reference: keeping it or erasing it.
Again, as for exporting to SAT file, you'd better provide more info, such as: what do yo want to export, why it has anything to do with block reference exploding, why you need to have another drawing database involved...
Norman Yuan
I appreciate you trying to help..
The block selection happens already as part of the parent command I am trying to add to.
Public Function SelectBlockRef(ByVal doc As Document) As ObjectId
Dim peo As New PromptEntityOptions("Select a Part to Delete")
peo.AllowNone = True
peo.SetRejectMessage("Only BlockReferences may be selected.")
peo.AddAllowedClass(GetType(BlockReference), True)
Dim per As PromptEntityResult = doc.Editor.GetEntity(peo)
If per.Status = PromptStatus.OK Then
Using doc.TransactionManager.StartTransaction()
Dim br As BlockReference = DirectCast(per.ObjectId.GetObject(OpenMode.ForRead), BlockReference)
Return br.BlockTableRecord
End Using
Else
Return ObjectId.Null
End If
End Function
At some point after this we save it to a DXF for certain Milling/Routing machines.
I am encountering 2 new ones that require .SAT files for their import.
The ACISOut command only works on solids, regions, or bodies hence the need to explode the block.
Ignore my poor attempt at populating a DB with the objects but my hope was to store the block exploded as a temp file (or temp document or database?) then just iterate through the exploded objects and populate the ObjectIdCollection to pipe into the Body.AcisOut command.
Using tempDb As New Database(False, True)
tempDb.ReadDwgFile(tempDirectory + tempFileName, FileOpenMode.OpenForReadAndAllShare, False, "")
tempDb.CloseInput(True)
Using tempTr As Transaction = tempDb.TransactionManager.StartTransaction()
Dim objCollection As New DBObjectCollection()
Dim dbObj As DBObject
Dim bt As BlockTable = tempTr.GetObject(tempDb.BlockTableId, OpenMode.ForRead)
Dim tempBtr As BlockTableRecord = tempTr.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead)
' get all non-block solid/region/body objects
For Each id As ObjectId In tempBtr
dbObj = tempTr.GetObject(id, OpenMode.ForRead)
If TypeOf dbObj Is Solid3d Or TypeOf dbObj Is Region Or TypeOf dbObj Is Body Then
objCollection.Add(dbObj)
End If
Next
If (objCollection.Count > 0) Then
Body.AcisOut("C:\\Temp\\test.sat", objCollection)
End If
End Using
End Using
The snippet above works just fine on non-blocks. I'm just struggling with exploding (a possibly nested block) to get the solid objects to output to the export function.
OK, this the case you are facing, as I understand: you want to explode a block reference (because some or all the elements of the block definition are either Solid, or Region), so that you can get all exploding-generated Solids/Regions. Sorry I am not sure Body.AcisOut accept non-database residing Soloids/Regions or not. But Assume it does, then the code would be rather simple:
using (var tran=....StartTransaction())
{
var exportEntities=new DBObjectCollection();
var model=(BlockTableRecord)tran.GetObject([open ModelSapce block], OpenMode.ForRead);
foreach (ObjectId id in model)
{
var dbObject=tran.GetObject(id, OpenMode.ForRead);
if (dbObject is Solid3d || dbObject is Region)
{
// It the object is Solid/Region
exportEntities.Add(dbObject);
}
else if (dbObject is BlockReference)
{
// explode the block and collect Solid/region element back
var elements=ExplodeBlock((BlockReference)dbObject);
foreach (var obj in elements)
{
exportEntities.Add(obj);
}
}
}
if (exportEntities.Count>0)
{
// export to *.sat file
// Again, I do not know if non-database-residing DBObject would work or not
Body.AcisOut("xxxxx", exportEntities)
}
// Make sure the non-database-residing DBObject is disposed
foreach (DBObject obj in exportEntities)
{
if (obj.ObjectId.IsNull) obj.Dispose();
}
tran.Commit()
}
private List<DBObject> ExplodeBlock(BlockReference blk)
{
var lst=new List<DBObject>();
var dbObjects=new DBObjectCollection();
blk.Explode(dbObjects);
foreach (DBObject obj in dbObjects)
{
if (obj is Solid3d || obj is Region)
{
lst.Add(obj);
}
else
{
obj.Dispose();
}
}
return lst;
}
Norman Yuan
Can't find what you're looking for? Ask the community or share your knowledge.