Author Topic: Block with Mtext loses Fields when exploded. How can I prevent this?  (Read 5158 times)

0 Members and 1 Guest are viewing this topic.

commodore

  • Newt
  • Posts: 51
I am inserting Mtext with Fields from a source drawing.
When I explode the block to get it back to Mtext all the Fields are gone.
How can I insert and explode it and NOT lose the all the fields?
Do I need to DeepClone instead of insert?

Here's what I am doing now...
Code: [Select]
                        Using ShtTr As Transaction = mySheetDB.TransactionManager.StartTransaction
                            Dim shtBlkTbl As BlockTable = ShtTr.GetObject(mySheetDB.BlockTableId, OpenMode.ForRead)
                            '' Open the Blocktablerecord Model space for read
                            Dim shtBlkTblRec As BlockTableRecord = ShtTr.GetObject(shtBlkTbl(BlockTableRecord.PaperSpace), OpenMode.ForWrite)

                            Dim BlkRef As New BlockReference(New Point3d(BlkX, BlkY, 0), shtBlkTbl(BlkName))

                            ' can change block properties here
                            BlkRef.Layer = "A-Anno-Titl"

                            ' explode the block
                            Dim DBObjColl As New DBObjectCollection
                            BlkRef.Explode(DBObjColl)
                            ' now we have a collection of all the objects in the block which now need to be added to the blocktablerecord
                            For Each acEnt As Entity In DBObjColl
                                ' Add the new objects to the block table record and the transaction
                                ' Dont add the original block or you will have both in the drawing.
                                shtBlkTblRec.AppendEntity(acEnt)
                                ShtTr.AddNewlyCreatedDBObject(acEnt, True)
                            Next

                            ' since the block was in memory only (not added w\AppendEntity and AddNewlyCreatedDBObject)
                            ' then just doing a commit here will dispose of the in memory block
                            ShtTr.Commit()

                            ' close transaction
                        End Using

mjfarrell

  • Seagull
  • Posts: 14444
  • Every Student their own Lesson
what happens if you insert the block exploded to start with?

does not the BURST command do this?
« Last Edit: March 04, 2011, 09:09:36 AM by Higgs Boson's Mate »
Be your Best


Michael Farrell
http://primeservicesglobal.com/

commodore

  • Newt
  • Posts: 51
what happens if you insert the block exploded to start with?

does not the BURST command do this?

forgive me but i'm still a .Net newb, how would i code inserting the block already exploded? Is there a different function other than blkref.insert I should be using?

I tried the dot net Burst function as found here http://www.theswamp.org/index.php?topic=18383.0 and it had the same result as blkref.explode (fields gone).

dan.glassman

  • Guest
BlockReference.ExplodeToOwnerSpace() doesn't appear to remove the fields, though Entity.Explode() does.  AutoCAD's 'explode' command doesn't remove the fields, either.

-drg


Jeff H

  • Needs a day job
  • Posts: 6151
Have not tested but if you are bringing in from external database use WblockcloneObjects

using file C:\Users\Jeff\Desktop\Test.dwg

and a block named "C"----- a cirlce with a field for drawing name and path

Code: [Select]

        <CommandMethod("ImportBlock")> _
        Public Sub ImportBlock()

            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor

            Dim extDB As New Database(False, True)
            extDB.ReadDwgFile("C:\Users\Jeff\Desktop\Test.dwg", FileOpenMode.OpenForReadAndAllShare, True, "")

            Using trx As Transaction = db.TransactionManager.StartTransaction
                Using extTrx As Transaction = extDB.TransactionManager.StartTransaction


                    Dim bt As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead)
                    Dim extBT As BlockTable = extDB.BlockTableId.GetObject(OpenMode.ForRead)

                    Dim mdlSpace As BlockTableRecord = bt(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForRead)

                    Dim btrCircle As BlockTableRecord = extBT("C").GetObject(OpenMode.ForRead)

                    Dim map As New IdMapping

                    Dim extobjIdColl As New ObjectIdCollection
                    extobjIdColl.Add(extBT("C"))
                    db.WblockCloneObjects(extobjIdColl, bt.ObjectId, map, DuplicateRecordCloning.Replace, False)
                    Dim btrId As ObjectId = bt("C").GetObject(OpenMode.ForRead).ObjectId

                    mdlSpace.UpgradeOpen()
                    Dim bref As New BlockReference(Point3d.Origin, btrId)
                    mdlSpace.AppendEntity(bref)
                    trx.AddNewlyCreatedDBObject(bref, True)

                    Dim exploeObjs As New DBObjectCollection
                    bref.Explode(exploeObjs)

                    For Each ent As Entity In exploeObjs
                        mdlSpace.AppendEntity(ent)
                        trx.AddNewlyCreatedDBObject(ent, True)
                    Next

                    bref.Erase()

                    trx.Commit()

                End Using
            End Using
        End Sub


Jeff H

  • Needs a day job
  • Posts: 6151
BlockReference.ExplodeToOwnerSpace() doesn't appear to remove the fields, though Entity.Explode() does.  AutoCAD's 'explode' command doesn't remove the fields, either.

-drg




I get different results depending if field is attribute or not.

For example the AutoCAD's 'explode' removes field if attribute placed by pressing "insert field" button from attribute dialog box in block editor.
AutoCAD's 'explode' does not remove field if 'Field' command is used in block editor to place field.
Basically if it is a attribute 'explode' removes field

Code: [Select]

        <CommandMethod("ImportBlockField")> _
        Public Sub ImportBlockField()

            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor

            Dim extDB As New Database(False, True)
            extDB.ReadDwgFile("C:\Users\Jeff\Desktop\Test.dwg", FileOpenMode.OpenForReadAndAllShare, True, "")

            Using trx As Transaction = db.TransactionManager.StartTransaction
                Using extTrx As Transaction = extDB.TransactionManager.StartTransaction


                    Dim bt As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead)
                    Dim extBT As BlockTable = extDB.BlockTableId.GetObject(OpenMode.ForRead)

                    Dim mdlSpace As BlockTableRecord = bt(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForRead)

                    Dim btrCircle As BlockTableRecord = extBT("C").GetObject(OpenMode.ForRead)

                    Dim map As New IdMapping

                    Dim extobjIdColl As New ObjectIdCollection
                    extobjIdColl.Add(extBT("C"))
                    db.WblockCloneObjects(extobjIdColl, bt.ObjectId, map, DuplicateRecordCloning.Replace, False)
                    Dim btr As BlockTableRecord = bt("C").GetObject(OpenMode.ForRead)

                    mdlSpace.UpgradeOpen()
                    Dim bref As New BlockReference(Point3d.Origin, btr.ObjectId)
                    mdlSpace.AppendEntity(bref)
                    trx.AddNewlyCreatedDBObject(bref, True)

                    Dim fldId As ObjectId

                    For Each id As ObjectId In btr
                        If id.ObjectClass.Name = "AcDbAttributeDefinition" Then
                            Dim attDef As AttributeDefinition = id.GetObject(OpenMode.ForWrite)

                            If attDef.HasFields Then
                                fldId = attDef.GetField()
                                attDef.Tag = fldId.ToString
                            End If

                            Dim attRef As New AttributeReference()
                            attRef.SetAttributeFromBlock(attDef, bref.BlockTransform)
                            bref.AttributeCollection.AppendAttribute(attRef)
                            trx.AddNewlyCreatedDBObject(attRef, True)

                        End If
                    Next



                    Dim exploeObjs As New DBObjectCollection
                    bref.Explode(exploeObjs)

                    For Each ent As Entity In exploeObjs

                        If TypeOf ent Is AttributeDefinition Then
                            Dim attDef As AttributeDefinition = CType(ent, AttributeDefinition)

                            If attDef.Tag = fldId.ToString Then

                                Dim fld As Field = fldId.GetObject(OpenMode.ForWrite)
                                fld.Evaluate()
                                Dim fieldEval As FieldEvaluationStatusResult = fld.EvaluationStatus

                                If fieldEval.Status = FieldEvaluationStatus.Success Then
                                    attDef.SetField(fld)

                                End If


                            End If

                        End If
                        mdlSpace.AppendEntity(ent)
                        trx.AddNewlyCreatedDBObject(ent, True)
                    Next

                    bref.Erase()

                    trx.Commit()

                End Using
            End Using
        End Sub

Jeff H

  • Needs a day job
  • Posts: 6151
commodore,

Are you trying to insert another drawing or a block from from another drawing?

If so this is like insert command

Code: [Select]
<CommandMethod("InsertDwg")> _
        Public Sub InsertDwg()
            Dim doc As Document = DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor
            Dim fname As String = "C:\Users\Jeff\Documents\Drawing1.dwg"
            Dim ObjId As ObjectId
            Using trx As Transaction = db.TransactionManager.StartTransaction
                Dim bt As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead)
                Dim btrMs As BlockTableRecord = bt(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForWrite)
                Using dbInsert As New Database(False, True)
                    dbInsert.ReadDwgFile(fname, IO.FileShare.Read, True, "")
                    ObjId = db.Insert(Path.GetFileNameWithoutExtension(fname), dbInsert, True)
                End Using
                Dim ppo As New PromptPointOptions(vbCrLf & "Insertion Point")
                Dim ppr As PromptPointResult
                ppr = ed.GetPoint(ppo)
                If ppr.Status <> PromptStatus.OK Then
                    ed.WriteMessage(vbCrLf & "You decided to QUIT!")
                    Exit Sub
                End If
                Dim insertPt As Point3d = ppr.Value
                Dim bref As New BlockReference(insertPt, ObjId)
                btrMs.AppendEntity(bref)
                trx.AddNewlyCreatedDBObject(bref, True)
                trx.Commit()
            End Using

        End Sub

commodore

  • Newt
  • Posts: 51
Perfect!
Thanks everyone.
I combined Jeff's and Dan's answers to get exactly what I needed as shown below.

Code: [Select]
                    Using acLckDoc As DocumentLock = SheetDoc.LockDocument()

                        Using trx As Transaction = mySheetDB.TransactionManager.StartTransaction
                            Dim ObjId As ObjectId
                            Dim bt As BlockTable = mySheetDB.BlockTableId.GetObject(OpenMode.ForRead)
                            Dim btrMs As BlockTableRecord = bt(BlockTableRecord.PaperSpace).GetObject(OpenMode.ForWrite)
                            Using dbInsert As New Database(False, True)
                                dbInsert.ReadDwgFile(BlkFullPath, IO.FileShare.Read, True, "")
                                ObjId = mySheetDB.Insert(Path.GetFileNameWithoutExtension(BlkFullPath), dbInsert, True)
                            End Using

                            Dim BlkRef As New BlockReference(New Point3d(BlkX, BlkY, 0), ObjId)
                            btrMs.AppendEntity(BlkRef)
                            trx.AddNewlyCreatedDBObject(BlkRef, True)

                            ' explode the block
                            BlkRef.ExplodeToOwnerSpace()

                            trx.Commit()
                        End Using

                    End Using

commodore

  • Newt
  • Posts: 51
My code to purge just the recently inserted block is not working. What am i doing wrong?
see the post below to see the code i used to add the block. This additional code is located immediatley following the "BlkRef.ExplodeToOwnerSpace()" line.



Code: [Select]
                  Dim BlkRefCol As New ObjectIdCollection
                            BlkRefCol.Add(BlkRef.ObjectId)
                            mySheetDB.Purge(BlkRefCol)
                            BlkRef.Erase()
« Last Edit: March 05, 2011, 09:39:13 AM by commodore »

Jeff H

  • Needs a day job
  • Posts: 6151
From the docs for

Database.Purge Method (ObjectIdCollection)
 
Description

Quote
This function searches through the database to see if there are any hard references to objects with object ID entities in the ids array. If any such objects are found, their object ID entities are removed from the ids array. So, when this function returns, the ids array will contain only object ID entities of objects that are not currently hard-referenced and thus can safely be erased.

If the database is in a partially opened state, object ID entities of objects that were not created in the current editing session are also removed from the ids array.

Note

Quote
This function does not modify the database in any way.

To duplicate the AutoCAD purge mechanism functionality, use this function to determine what database objects (of the type desired) can be purged or erased, and then open each such object, call its erase() method to erase it, and close it. For example, to purge all unreferenced layers, call the purge method, passing in an array containing the object ID entities of all the LayerTableRecords in the LayerTable, then erase all the objects whose object ID entities are still in the array after the purge function has returned.


dan.glassman

  • Guest
Re: Block with Mtext loses Fields when exploded. How can I prevent this?
« Reply #10 on: March 06, 2011, 12:01:56 AM »
Eek -- I now consider using Entity.Explode() on a block reference harmful. 

There's this case -- mtext with fields.

I checked geometric contraints.  The explode command preserves them; Entity.Explode() does not; BlockReference.ExplodeToOwnerSpace() does.

There's probably many others waiting to be found. 

-drg

kaefer

  • Guest
Re: Block with Mtext loses Fields when exploded. How can I prevent this?
« Reply #11 on: March 07, 2011, 02:48:16 AM »
Eek -- I now consider using Entity.Explode() on a block reference harmful. 

There's this case -- mtext with fields.

I checked geometric contraints.  The explode command preserves them; Entity.Explode() does not; BlockReference.ExplodeToOwnerSpace() does.

There's probably many others waiting to be found. 

This is about expectations. What would be the typical use of Entity.Explode() and why should we expect all the nifty features to be supported?

It should be sufficient to extract some transformed primitive geometry, which we can find by looping through the DBObjectCollection returned. The same thing, only more complete, could be accomplished by wrapping BlockReference.ExplodeToOwnerSpace() in a Database.ObjectAppended event handler and collect the exploded entities in a data structure of our own.

That would show that the cost of a field is in reality 2 fields, and a nested DBDictionary to boot.

Regards, Thorsten

dan.glassman

  • Guest
Re: Block with Mtext loses Fields when exploded. How can I prevent this?
« Reply #12 on: March 07, 2011, 09:20:01 AM »
Yes -- 'harmful' isn't a correct blanket statement.  Only harmful when the expectation is to match/implement the explode command.  Which seems fairly typical.

Kean's recent post purports to demonstrate this, as does SuperBurst, indirectly.  Certainly that was OP's expectation.

In other cases, Explode() is sufficient, harmless.

-drg

commodore

  • Newt
  • Posts: 51
Re: Block with Mtext loses Fields when exploded. How can I prevent this?
« Reply #13 on: March 07, 2011, 09:46:40 AM »
one thing I noticed with "ExplodetoOwnerSpace" is that it leaves the original block inserted in the drawing in addition to the exploded version.
I had to BlkRef.Erase() to remove the original block after I exploded it or I ended up with the block appearing to be in the drawing twice (1 a block, the other exploded).
Thanks for all the help.

Jeff H

  • Needs a day job
  • Posts: 6151
Re: Block with Mtext loses Fields when exploded. How can I prevent this?
« Reply #14 on: March 07, 2011, 07:36:20 PM »
one thing I noticed with "ExplodetoOwnerSpace" is that it leaves the original block inserted in the drawing in addition to the exploded version.
I had to BlkRef.Erase() to remove the original block after I exploded it or I ended up with the block appearing to be in the drawing twice (1 a block, the other exploded).
Thanks for all the help.

You can look in the docs or in the link to Kean's recent post by Dan to see that should be expected also with Entity.Explode().


In docs for BlockReference.ExplodeToOwnerSpace() it says
Quote
BlockReference must be in a database and must be uniformly scaled.

If it is not uniformly scaled does it fail or throw an error?

If I get a chance I will test it, but if not I was wondering if anyone has dealt with that.