.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Copy paste with new block definition

22 REPLIES 22
SOLVED
Reply
Message 1 of 23
PaulPotts
2066 Views, 22 Replies

Copy paste with new block definition

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!

 

 

 

22 REPLIES 22
Message 2 of 23
chiefbraincloud
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
Message 3 of 23
PaulPotts
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 ! Smiley Wink

Message 4 of 23
PaulPotts
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 !

Message 5 of 23
Alfred.NESWADBA
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 ... blog.hollaus.at ... CDay 2024
------------------------------------------------------------------------------------
(not an Autodesk consultant)
Message 6 of 23
PaulPotts
in reply to: Alfred.NESWADBA

Thank's ! it works  Smiley Happy !! 

 

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 ? 

Message 7 of 23
chiefbraincloud
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
Message 8 of 23
jeff
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
Message 9 of 23
chiefbraincloud
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
Message 10 of 23
jeff
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
Message 11 of 23
chiefbraincloud
in reply to: jeff

remarkably similar to what I just did, but needs one more thing (maybe).  If you want to maintain the AttributeReference Values of the original BlockReference, then you'll need to gather them up into a collection for when you insert the new BlockReference.

Dave O.                                                                  Sig-Logos32.png
Message 12 of 23
PaulPotts
in reply to: jeff

Thank's everyone who help me !! 

 

 Smiley Surprised Jeff's your answer works pefectly ! ty very much !  easy as hell !! Smiley Very Happy

Message 13 of 23
PaulPotts
in reply to: chiefbraincloud

that's truth chief,  how i could do that chief ?? 

 

I was trying using that code but without success 

 

                            For Each objId As ObjectId In btr

                                Dim obj As Object
                                obj = acTrans.GetObject(objId, OpenMode.ForWrite)

                                If TypeOf obj Is AttributeDefinition Then

                                    Dim AttDef As AttributeDefinition = obj
                                    Dim AttRef As New AttributeReference


                                    AttRef.SetAttributeFromBlock(AttDef, bob.BlockTransform)

                                End If

                            Next

 

 

Message 14 of 23
chiefbraincloud
in reply to: PaulPotts

Since I don't really know how you plan on using this code, I'm guessing a little here, but I have an idea that would greatly simplify the process:

 

Do you intend to delete the originally selected block?

Do you intend to have the new block in the same location/orientation as the original block?

 

 

Dave O.                                                                  Sig-Logos32.png
Message 15 of 23
PaulPotts
in reply to: chiefbraincloud

 

 

Do you intend to delete the originally selected block?

No, I only want to clone it, but without object references. solved.

 

Do you intend to have the new block in the same location/orientation as the original block?

I would like to have news blocks with the same orientation as the original but in a different selected point. solved.

 

My only problem now appears when i have clone it, if i create the blockreference by code i lose all attributes, but if i do it manually once i have clone it going to the insert option Autocad let me change all Attributes before insert it.

I would like to know what i have to do if i want to insert my attributes on my blockreference by code. 

Message 16 of 23
chiefbraincloud
in reply to: PaulPotts

Essentially you have a unique situation where you can make the process much easier by cloning the original block reference to create your new reference.

 

 Dim newBref As BlockReference
 Using MS As BlockTableRecord = acTrans.GetObject(Br.OwnerId, OpenMode.ForWrite, False, True)
     newBref = Br.Clone()
     newBref.BlockTableRecord = newBtrId
     MS.AppendEntity(newBref)
     acTrans.AddNewlyCreatedDBObject(newBref, True)
 End Using

 That way all the attributes are brought over with the clone, then move newBref to the new desired location, however it is you are doing that.

Dave O.                                                                  Sig-Logos32.png
Message 17 of 23
jeff
in reply to: PaulPotts

I am confused,

 

I first read through it quickly and the code I posted did not make much sense, but what I thought you were after and wanted.

 

Maybe I jumped in too quick and added to my confusion.

 

I apologize as Chief was getting trying to figure out your problem and my post might of side track it a bit.

 

The code I posted really just takes up space because it is just a copy of a existing 'BlockDefinition'.

 

From your first post, Chief's first reply would be the answer.

 

Just trying to help figure out what you after.

 

Maybe rewording question and replacing the word 'Block' with BlockReference or BlockDefinition might help?

 

 

 

 

You can also find your answers @ TheSwamp
Message 18 of 23
chiefbraincloud
in reply to: jeff

It's all good Jeff.  While my first response is one approach that would have worked, the DeepClone idea made the code much simpler, and as I mentioned earlier in the thread, the Explode option has issues with non-uniformly scaled block references, which the DeepClone option handles just fine.

 

I personally struggle to see the value of this routine, but I choose not to dwell on the perceived usefulness, and just focus on the question instead.  I figure he must have a purpose, even if that purpose is simply a learning experience.

 

 

Dave O.                                                                  Sig-Logos32.png
Message 19 of 23
jeff
in reply to: chiefbraincloud

I can't remeber off the top of my head but for some reason I was thinking that ExplodeToOwnerSpace worked with  non-uniformly scaled block references.

 

I could be wrong.

You can also find your answers @ TheSwamp
Message 20 of 23
chiefbraincloud
in reply to: jeff

In my code I have several blocks that are always scaled non-uniformly.  I think there are reasons that I have not used ExplodeToOwnerSpace, but I will check some stuff out...  I'll let you know

Dave O.                                                                  Sig-Logos32.png

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost