• Industries
  • Products
  • Buy
  • Services & Support
  • Communities
  • Discussion Groups

    .NET

    Reply
    Active Member
    PaulPotts
    Posts: 7
    Registered: ‎09-08-2011
    Accepted Solution

    Copy paste with new block definition

    614 Views, 21 Replies
    09-08-2011 06:35 AM
    I'm trying to develop one tool with that objective:
    • Let the user select Blocks into the current drawing
    • For each block selected, create a new Block definition and copy all objects inside. " new block definition and objects inside may not be referenced with our selected block". 
    • Paste all objects created where user wants 

     

    Problems :

     

    I was trying copy objects using .clone or .copyfrom but i don't know how to copy objects without references between new and selected block.

     

     My Code :

     

        Dim acdoc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
            Dim acCurDb As Database = acdoc.Database
            Dim acBt As BlockTable
            Dim acBtr As BlockTableRecord
            Dim E As Integer
            Dim newBtrId As ObjectId
    
            Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction
                acBt = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForWrite)
                acBtr = acTrans.GetObject(acBt(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
    
                'Let the user select Objects from drawing
                Dim acSSPrompt As PromptSelectionResult = acdoc.Editor.GetSelection()
                If acSSPrompt.Status = PromptStatus.OK Then
                    Dim acSSet As SelectionSet = acSSPrompt.Value
    
                    'Paste position
                    Dim myPoint As PromptPointResult = acdoc.Editor.GetPoint("Paste point: ")
    
                    'Read Selection Set
                    For Each acSSObj As SelectedObject In acSSet
    
                        'Look for ObjectId of my Selected Object
                        For Each acObjId As ObjectId In acBtr
                            If acObjId = acSSObj.ObjectId Then
    
                                'Take selected object as Blockreference
                                Dim Et As Entity = acTrans.GetObject(acObjId, OpenMode.ForWrite)
                                If TypeOf Et Is BlockReference Then
    
                                    'Current Block Selected
                                    Dim Br As BlockReference = Et
    
                                   'Here I should Paste all objects from Br to BlkRef ...
    
                                    'Create a new BlockTableRecord
                                    Dim blkRef As BlockTableRecord = New BlockTableRecord()
                                    blkRef.Name = "beta" & E + 1
    
                                    'Add BlockTableRecord
                                    newBtrId = acBt.Add(blkRef)
                                    acTrans.AddNewlyCreatedDBObject(blkRef, True)
    
                                    'Paint BlockReference
                                    Dim bob As New BlockReference(myPoint, newBtrId)
                                    acBtr.AppendEntity(bob)
                                    acTrans.AddNewlyCreatedDBObject(bob, True)
                                    E = E + 1
    
                                End If
    
                            End If
                        Next
                    Next
                    acTrans.Commit()
                End If
            End Using
    
        End Sub

     

     Any idea will be apreciated ! 

     

    Thank's a lot!

     

     

     

    Please use plain text.
    *Expert Elite*
    chiefbraincloud
    Posts: 736
    Registered: ‎02-13-2008

    Re: Copy paste with new block definition

    09-08-2011 12:16 PM in reply to: PaulPotts

    I would call the .Explode method on each of the selected blocks, then add the entities created by .Explode to the new BlockTableRecord.

     

    'first declare a New DbObjectCollection

    Dim ExpObjs as New DbObjectCollection()

    'I would change this loop   "For Each acSSObj As SelectedObject In acSSet" to ->

    For Each AcObjId as ObjectId in acSSet.GetObjectIds
    'And lose this loop altogether "For Each acObjId As ObjectId In acBtr"
         .....

         .....

        Dim Br As BlockReference = Et

        Br.Explode(ExpObjs)

        Dim blkRef As BlockTableRecord = New BlockTableRecord()
        blkRef.Name = "beta" & E + 1
        For Each dbo as DbObject in ExpObjs

             blkref.AppendEntity(dbo)

             acTrans.AddNewlyCreatedDbObject(dbo, True)

        Next
        newBtrId = acBt.Add(blkRef)
        acTrans.AddNewlyCreatedDBObject(blkRef, True)

    Edit:  I am slightly confused as to whether you intend to create 1 new block for each block selected, or 1 new block containing all blocks selected, and unfortunately the example as typed is a combination of the two.  If you want a new block to be created for each of the blocks selected, then you should move the declaration of the New DbObjectCollection to inside the For Loop.  If you want one new block containing all of the selected blocks, then you should move the new For Loop (for each dbo as DbObject in ExpObjs) and the new block insert to outside the main For Loop.

    Dave O.                                                                                Sig-Logos32.png
    Please use plain text.
    Active Member
    PaulPotts
    Posts: 7
    Registered: ‎09-08-2011

    Re: Copy paste with new block definition

    09-08-2011 01:06 PM in reply to: chiefbraincloud

    Thank's chief ! 

     

    I would like one new block definition for each block selected, 

     

    I'm gonna try what you said thank you very very much ! :smileywink:

    Please use plain text.
    Active Member
    PaulPotts
    Posts: 7
    Registered: ‎09-08-2011

    Re: Copy paste with new block definition

    09-09-2011 01:31 AM in reply to: PaulPotts

     

     

    I was trying your answer but i have an error on:

     

              For Each dbo As DBObject In ExpObjs
                                blkRef.AppendEntity(dbo)
                                acTrans.AddNewlyCreatedDBObject(dbo, True)
              Next

     

    Autodesk.AutoCAD.Runtime.Exception: eNotInDatabase   Autodesk.AutoCAD.DatabaseServices.TransactionManager.AddNewlyCreatedDBObject(DBObject obj, Boolean add)

     

    All code :

     

     Public Sub Copy_Paste()
    
            Dim acdoc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
            Dim acCurDb As Database = acdoc.Database
            Dim acBt As BlockTable
            Dim acBtr As BlockTableRecord
            Dim E As Integer
            Dim newBtrId As ObjectId
    
            Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction
                acBt = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForWrite)
                acBtr = acTrans.GetObject(acBt(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
    
    
                Dim acSSPrompt As PromptSelectionResult = acdoc.Editor.GetSelection()
                If acSSPrompt.Status = PromptStatus.OK Then
                    Dim acSSet As SelectionSet = acSSPrompt.Value
    
                    For Each AcObjId As ObjectId In acSSet.GetObjectIds
                        Dim Et As Entity = acTrans.GetObject(AcObjId, OpenMode.ForWrite)
                        If TypeOf Et Is BlockReference Then
                            Dim Br As BlockReference = Et
                            Dim ExpObjs As New DBObjectCollection()
                            Br.Explode(ExpObjs)
    
                            Dim blkRef As BlockTableRecord = New BlockTableRecord()
                            blkRef.Name = "beta" & E + 1
    
                            For Each dbo As DBObject In ExpObjs
                                blkRef.AppendEntity(dbo)
                                acTrans.AddNewlyCreatedDBObject(dbo, True)
                            Next
    
                            newBtrId = acBt.Add(blkRef)
                            acTrans.AddNewlyCreatedDBObject(blkRef, True)
    
                            E = E + 1
    
                        End If
                    Next
    
                End If
            End Using
    
        End Sub

     i don't know what i'm missing... 

     

    thank's !

    Please use plain text.
    *Expert Elite*
    Posts: 6,474
    Registered: ‎06-29-2007

    Re: Copy paste with new block definition

    09-09-2011 01:45 AM in reply to: PaulPotts

    Hi,

     

    you do create a BlockTableRecord (blkRef)

    then you add objects into this blockdefinition and - now the error - the transaction should add an object to a blockreference, that is not known by the transaction.

     

    So: after creating the BlockTableRecord ==> add this to the BlockTable and to the current transaction

    After that (!) add objects to the BlockTableRecord.

     

    So the code-snippet should look like:

    Dim blkRef As BlockTableRecord = New BlockTableRecord()
    blkRef.Name = "beta" & E + 1
    
    'now these two lines where moved upwards
    newBtrId = acBt.Add(blkRef)
    acTrans.AddNewlyCreatedDBObject(blkRef, True)
    
    For Each dbo As DBObject In ExpObjs
        blkRef.AppendEntity(dbo)
        acTrans.AddNewlyCreatedDBObject(dbo, True)
    Next

     

    HTH, - alfred -

    -------------------------------------------------------------------------
    Alfred NESWADBA
    Ingenieur Studio HOLLAUS ... www.hollaus.at
    -------------------------------------------------------------------------
    Please use plain text.
    Active Member
    PaulPotts
    Posts: 7
    Registered: ‎09-08-2011

    Re: Copy paste with new block definition

    09-09-2011 07:07 AM in reply to: alfred.neswadba

    Thank's ! it works  :smileyhappy: !! 

     

    I missed to copy all attributes to the new block , I tried doing as what i pasted here, but i think that's not the correct way to do it :

     

                          For Each atrib As ObjectId In Br.AttributeCollection
                                Dim att As AttributeReference
                                att = acTrans.GetObject(atrib, OpenMode.ForWrite)
                                blkRef.AppendEntity(att)
                                acTrans.AddNewlyCreatedDBObject(att, True)
                            Next

     How i could add into a blocktablerecord an Attribute ? 

    Please use plain text.
    *Expert Elite*
    chiefbraincloud
    Posts: 736
    Registered: ‎02-13-2008

    Re: Copy paste with new block definition

    09-09-2011 10:55 AM in reply to: PaulPotts

    Sorry I missed that Paul, but yes, as you have discovered, the BlockTableRecord must be Database Resident before you start adding thins to it.

     

    To be thorough, I should also mention that the Explode method will fail if the block is not Uniformly Scaled, just as the AutoCAD Explode command does.

     

    As far as the attributes, You should open the BlockTableRecord of the BlockReference you are exploding, and create new AttributeReferences from the AttributeDefinitions in the BlockTableRecord.

     

    To be honest, having to do that means you almost might as well just copy everything to your new block from there, and skip the Explode.  I'll spend a few minutes working up a sample.

    Dave O.                                                                                Sig-Logos32.png
    Please use plain text.
    Mentor
    Posts: 241
    Registered: ‎05-12-2009

    Re: Copy paste with new block definition

    09-09-2011 11:25 AM in reply to: chiefbraincloud

    Why don't you just get the BlockTableRecord of the BlockReference and DeepClone it?

    You can also find your answers @ TheSwamp
    Please use plain text.
    *Expert Elite*
    chiefbraincloud
    Posts: 736
    Registered: ‎02-13-2008

    Re: Copy paste with new block definition

    09-09-2011 11:31 AM in reply to: jeff

    Frankly, I was trying to stick closer to his code and pick it up from there, but as I was just working on it, I realized that a deep clone would be easier, faster, and avoid the problem of non-uniformly scaled block references.

    Dave O.                                                                                Sig-Logos32.png
    Please use plain text.
    Mentor
    Posts: 241
    Registered: ‎05-12-2009

    Re: Copy paste with new block definition

    09-09-2011 12:08 PM in reply to: chiefbraincloud

    This was thrown together very quickly need error handling etc....

     

            <CommandMethod("DeepCloneBlock")> _
            Public Sub DeepCloneBlock()
                Dim doc As Document = Application.DocumentManager.MdiActiveDocument
                Dim db As Database = doc.Database
                Dim ed As Editor = doc.Editor
    
                Using trx As Transaction = db.TransactionManager.StartTransaction()
    
                    Dim tvs() As TypedValue = {New TypedValue(0, "INSERT")}
                    Dim selectionFilter As New SelectionFilter(tvs)
    
    
                    Dim result As SelectionSet = ed.GetSelection(selectionFilter).Value
    
                    Dim bt As BlockTable = trx.GetObject(db.BlockTableId, OpenMode.ForWrite)
    
    
    
                    For Each objId As ObjectId In result.GetObjectIds
                        Dim bref As BlockReference = trx.GetObject(objId, OpenMode.ForRead)
                        Dim btr As BlockTableRecord = trx.GetObject(bref.BlockTableRecord, OpenMode.ForRead)
    
                        If Not bt.Has(btr.Name & " Copy") Then
                            Dim map As New IdMapping()
    
                            Dim newBtr As BlockTableRecord = btr.DeepClone(bt, map, False)
    
                            newBtr.Name = btr.Name & " Copy"
                            bt.Add(newBtr)
                            trx.AddNewlyCreatedDBObject(newBtr, True)
    
                        End If
    
                    Next
    
                    trx.Commit()
                End Using
            End Sub

     

     

     

    You can also find your answers @ TheSwamp
    Please use plain text.