VB.NET Save selected objects to file after explording in code

Joshua_claytonWV5WP
Enthusiast
Enthusiast

VB.NET Save selected objects to file after explording in code

Joshua_claytonWV5WP
Enthusiast
Enthusiast

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

 

 

0 Likes
Reply
Accepted solutions (1)
577 Views
5 Replies
Replies (5)

norman.yuan
Mentor
Mentor

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

Drive CAD With Code

EESignature

0 Likes

Joshua_claytonWV5WP
Enthusiast
Enthusiast

What then would be the easiest way to select a block, explode it, then export everything to a .SAT file?

0 Likes

norman.yuan
Mentor
Mentor

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

Drive CAD With Code

EESignature

Joshua_claytonWV5WP
Enthusiast
Enthusiast

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.

0 Likes

norman.yuan
Mentor
Mentor
Accepted solution

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

Drive CAD With Code

EESignature