.NET

Reply
Contributor
cwelkusl
Posts: 19
Registered: ‎01-18-2011
Message 1 of 18 (1,233 Views)
Accepted Solution

"Clone" an object from one drawing to another with modifications possible?

1233 Views, 17 Replies
01-25-2011 02:56 PM

Hi All,

 

     I'm hoping someone here can help me with what I've been beating my head against the wall trying to do all day.  Essentially this is the problem I'm trying to solve:

  • I have two open drawings, a source and a destination drawing in ACAD
  • I have different layers and linetypes in each drawing
  • I need to get the objects on a specified layer in the source drawing and copy them to the destination drawing, but ensure that they are put on a specified layer in that drawing which differs in name from the original drawing.

I've tried coming at this a few different ways, but can't really seem to come a conclusion on how to do this.  WBlockCloneObjects, of course, allows me to clone the items to the new drawing, but in doing so, drags along all the layers and linetypes with it which I don't want "contaminating" my new drawing.  I'm trying to keep the conversion as clean as possible.  I can't pre-change the layer name or linetype, etc as the destination for these values doesn't exist in the source drawing. 

 

Is there a way to create a new entity (an anonymous one, independent of the source ObjectClass that I need so I don't have to create multiple routines to handle each one), not attached to a DB, copy the values from the source DB entity and then modify the layer, linetype, color etc before appending the entity to the destination database?

 

 

Here is my code for what I have, but since I don't really have a clue where to turn with this, all this really shows at the moment is a straight cloning of the objects from one DB to another.  As a side note, I'm working in Civil 3D 2011 and when WBlockCloneObjects is called an "AutoCAD Map Messages" window appears with no messages in it.  Anyone seen that before? 

 

I appreciate any help or ideas that anyone can provide,

 

Chris Welk

 

Public Function CopyLayerContents(ByVal acdocSource As Document, ByVal strSourceLayer As String, ByVal acdocDest As Document, ByVal strDestLayer As String, ByVal bCopyBlocks As Boolean) As Boolean
        Dim bComplete = False
        Dim acSourceDB As Database = acdocSource.Database
        Dim acDestDB As Database = acdocDest.Database
        Dim acSourceBlockTable As BlockTable
        Dim acSourceModelSpace As BlockTableRecord
        Dim acDestBlockTable As BlockTable
        Dim acDestModelSpace As BlockTableRecord
        Dim acSourceLayerTable As LayerTable
        Dim acDestLayerTable As LayerTable
        Dim acObjIDs As ObjectIdCollection = New ObjectIdCollection()
        Dim acIDMap As IdMapping = New IdMapping()
        

Try
            Using acDocLock As DocumentLock = acdocDest.LockDocument()
                Using acSourceTrans As Transaction = acSourceDB.TransactionManager.StartTransaction()
                    Using acDestTrans As Transaction = acDestDB.TransactionManager.StartTransaction()
                        acSourceBlockTable = acSourceTrans.GetObject(acSourceDB.BlockTableId, OpenMode.ForRead)
                        acSourceModelSpace = acSourceTrans.GetObject(acSourceBlockTable
(BlockTableRecord.ModelSpace), OpenMode.ForRead)
                        acSourceLayerTable = acSourceTrans.GetObject(acSourceDB.LayerTableId, OpenMode.ForRead)
                        acDestBlockTable = acDestTrans.GetObject(acDestDB.BlockTableId, OpenMode.ForWrite)
                        acDestModelSpace = acDestTrans.GetObject(acDestBlockTable(BlockTableRecord.ModelSpace), 
OpenMode.ForWrite)
                        acDestLayerTable = acDestTrans.GetObject(acDestDB.LayerTableId, OpenMode.ForRead)
                        If acSourceLayerTable.Has(strSourceLayer) And acDestLayerTable.Has(strDestLayer) Then
                            For Each acObjID As ObjectId In acSourceModelSpace
                                Dim acEnt As Entity = acSourceTrans.GetObject(acObjID, OpenMode.ForRead)
                                If acEnt.Layer = strSourceLayer Then
                                    acObjIDs.Add(acObjID)
                                End If
                            Next acObjID
                            acSourceDB.WblockCloneObjects(acObjIDs, acDestModelSpace.ObjectId, acIDMap,  _

                                DuplicateRecordCloning.Replace, False)
                            acDestTrans.Commit()

                            bComplete = True
                        Else
                            bComplete = False
                        End If

                    End Using
                End Using
            End Using
        Catch ex As Exception
            MessageBox.Show("Error importing objects: " & ex.Message & vbCrLf & vbTab & ex.StackTrace, "DASMAP - " 
& System.Reflection.MethodBase.GetCurrentMethod().Name, MessageBoxButtons.OK, MessageBoxIcon.Error)
            bComplete = False
        End Try


        Return bComplete
    End Function

Chris Welk
Urban Systems Ltd.
Engineering Technologist (Civil)/CADD Applications Developer

IdMapping would be one way to go, but I think you would still have to do something about the source layers being copied into the destDB.

 

I am making one assumption, that everything on source layer X will end up on destination layer Y, as opposed to different things on source layer X going to different destination layers.  If that is the case, then I reccomend that you open the source LayerTable and just change the names from sourcename to destname, then when you do your clone, use DuplicateRecordCloning.Ignore instead of Replace.  This would have the added benefit of automatically taking care of entities in BlockTableRecords and BlockReferences.

 

Depending on your actual needs, you may still need to do something about linetypes (perhaps just load the ones you need into the source and change the layer's linetype at the same time as renaming it).

 

*Expert Elite*
Hallex
Posts: 1,569
Registered: ‎10-08-2008
Message 2 of 18 (1,196 Views)

Re: "Clone" an object from one drawing to another with modifications p

01-26-2011 09:48 AM in reply to: cwelkusl

This code is working for me (tested on A2009 only)

   Public Function CopyLayerContents(ByVal acdocDest As Document, ByVal fname As String, ByVal strSourceLayer As String, ByVal strDestLayer As String, ByVal bCopyBlocks As Boolean) As Boolean
        Dim bComplete = False
        'Dim acSourceDB As Database = acdocSource.Database
        Dim acDestDB As Database = acdocDest.Database
        Dim acSourceBlockTable As BlockTable
        Dim acSourceModelSpace As BlockTableRecord
        Dim acDestBlockTable As BlockTable
        Dim acDestModelSpace As BlockTableRecord
        Dim acSourceLayerTable As LayerTable
        Dim acDestLayerTable As LayerTable
        Dim acObjIDs As ObjectIdCollection = New ObjectIdCollection()
        Dim acIDMap As IdMapping = New IdMapping()


        Try
            Using acDocLock As DocumentLock = acdocDest.LockDocument()

                Using acSourceDB As New Database(False, True)
                    Using acSourceTrans As Transaction = acSourceDB.TransactionManager.StartTransaction()
                        acSourceDB.ReadDwgFile(fname, IO.FileShare.Read, True, "")
                        Using acDestTrans As Transaction = acDestDB.TransactionManager.StartTransaction()
                            acSourceBlockTable = acSourceTrans.GetObject(acSourceDB.BlockTableId, OpenMode.ForRead)
                            acSourceModelSpace = acSourceTrans.GetObject(acSourceBlockTable(BlockTableRecord.ModelSpace), OpenMode.ForRead)
                            acSourceLayerTable = acSourceTrans.GetObject(acSourceDB.LayerTableId, OpenMode.ForRead)
                            acDestBlockTable = acDestTrans.GetObject(acDestDB.BlockTableId, OpenMode.ForWrite)

                            acDestModelSpace = acDestTrans.GetObject(acDestBlockTable(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
                            acDestLayerTable = acDestTrans.GetObject(acDestDB.LayerTableId, OpenMode.ForRead)
                            If acSourceLayerTable.Has(strSourceLayer) And acDestLayerTable.Has(strDestLayer) Then
                                For Each acObjID As ObjectId In acSourceModelSpace
                                    Dim acEnt As Entity = acSourceTrans.GetObject(acObjID, OpenMode.ForRead)
                                    If acEnt.Layer = strSourceLayer Then
                                        acObjIDs.Add(acObjID)
                                    End If
                                Next acObjID
                                acSourceDB.WblockCloneObjects(acObjIDs, acDestModelSpace.ObjectId, acIDMap, DuplicateRecordCloning.Ignore, False)
                                acDestTrans.Commit()

                                bComplete = True
                            Else
                                bComplete = False
                            End If
                        End Using
                    End Using
                End Using
            End Using
        Catch ex As Exception
            MsgBox("Error importing objects: " & ex.Message & vbCrLf & vbTab & ex.StackTrace, MsgBoxStyle.Critical)
            bComplete = False
        End Try


        Return bComplete
    End Function
    <CommandMethod("CopyFromLayer")> _
    Public Sub CopyFromLayer()
        Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
        Dim ed As Editor = doc.Editor
        Dim fname As String = "c:\UsedFiles\abc.dwg"
        ed.WriteMessage(vbCr & vbTab & "Result = {0}", CopyLayerContents(doc, fname, "0", "0", False))

    End Sub

 

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Contributor
cwelkusl
Posts: 19
Registered: ‎01-18-2011
Message 3 of 18 (1,193 Views)

Re: "Clone" an object from one drawing to another with modifications p

01-26-2011 10:15 AM in reply to: cwelkusl

Thanks for the response Hallex, but that wasn't really what I was after.  Maybe I can explain it better...

 

The problem wasn't my code.  I only supplied it as an example of where I am currently at.  The problem I guess is more of trying to find some direction for what I'm trying to do.

 

My code (and yours) works fine for cloning objects between two databases.  The added caveat is that I need to partially clone those objects into the new DB. I want all aspects of the object, but want to modify the layer, linetype and color to match set properties that exist in the destination drawing.  If I just clone the objects as is, it will drag across layers and linetypes that I don't want in my destination drawing.  This would be easy if working within a single drawing, as I could clone the entity, and change the properties I need.  But since the layers and linetypes between the databases don't match, how do I go about acheiving this?

 

Ideas I had were:

  • Importing the destination drawings, layers and linetypes into the source database, pre-editing the entities and then cloning them across to the destination database.
  • Changing the source entities to a dummy layer and "ByLayer" linetype in the source drawing.  Cloning them across to the destination drawing, then modifying all entities that exist in the destination drawing on that dummy layer to match the appropriate layer/linetype properties they need to be on.
  • Creating a "dummy" entity object (one not attached to a DB) that contains the properties of the source entity.  Modify the properties of that dummy entity to what I need them to be in the destination DB and then append it to the model space record.  Similar thought-proces of how you would create a new line or circle, but with a non-specific entity, so I don't have to write custom routines for the various objectclass types.  I don't even know if this one is possible.
  • Create a method that looks at the ObjectClass of each entity on that layer and then runs a custom routine for each ObjectClass type to re-create the object in the destination drawing on the appropriate layer.

And that's about where my ideas run-out.  I've only been working with ACAD coding off and on for about 8 months, so I was hoping someone out there might be seeing a solution I haven't thought or wasn't aware of, and would be able to point me in the right direction.

Chris Welk
Urban Systems Ltd.
Engineering Technologist (Civil)/CADD Applications Developer
Active Contributor
dan.glassman
Posts: 43
Registered: ‎09-23-2008
Message 4 of 18 (1,185 Views)

Re: "Clone" an object from one drawing to another with modifications p

01-26-2011 10:50 AM in reply to: cwelkusl

You can probably use the IdMapping() that WBlockCloneObjects fills out to do some post-processing on the destination entities, but..

 

I would instead WBlockCloneObjects to a new, temporary database.  Do your layer/linetype manipulations in the temporary database, then either Insert that into the final destination or set up a new WBlockCloneObjects from temp->dest.

 

-drg

*Expert Elite*
chiefbraincloud
Posts: 753
Registered: ‎02-13-2008
Message 5 of 18 (1,180 Views)

Re: "Clone" an object from one drawing to another with modifications p

01-26-2011 11:24 AM in reply to: cwelkusl

IdMapping would be one way to go, but I think you would still have to do something about the source layers being copied into the destDB.

 

I am making one assumption, that everything on source layer X will end up on destination layer Y, as opposed to different things on source layer X going to different destination layers.  If that is the case, then I reccomend that you open the source LayerTable and just change the names from sourcename to destname, then when you do your clone, use DuplicateRecordCloning.Ignore instead of Replace.  This would have the added benefit of automatically taking care of entities in BlockTableRecords and BlockReferences.

 

Depending on your actual needs, you may still need to do something about linetypes (perhaps just load the ones you need into the source and change the layer's linetype at the same time as renaming it).

 

Dave O.                                                                  Sig-Logos32.png
Contributor
cwelkusl
Posts: 19
Registered: ‎01-18-2011
Message 6 of 18 (1,145 Views)

Re: "Clone" an object from one drawing to another with modifications p

01-27-2011 07:11 AM in reply to: chiefbraincloud

Thanks for the input everyone.  I've essentially gone with chiefbraincloud's suggestion of just pre-modifying the layer and properties as needed and then cloning them over as required. 

 

I still have the issue of the blank "AutoCAD Map Messages" window popping up when WBlockCloneObjects executes for some reason.  But it's relatively minor, since as far as I can tell the objects are still coming across ok.  If anyone has an answer for that, feel free to post something!

 

Here is the updated code for anyone else who stumbles across this thread looking for a solution:

 

Public Function CopyLayerContents(ByVal acdocSource As Document, ByVal strSourceLayer As String, ByVal acdocDest As Document, ByVal strDestLayer As String, ByVal bCopyBlocks As Boolean) As Boolean
        Dim bComplete = False
        Dim acSourceDB As Database = acdocSource.Database
        Dim acDestDB As Database = acdocDest.Database
        Dim acSourceBlockTable As BlockTable
        Dim acSourceModelSpace As BlockTableRecord
        Dim acDestBlockTable As BlockTable
        Dim acDestModelSpace As BlockTableRecord
        Dim acSourceLayerTable As LayerTable
        Dim acDestLayerTable As LayerTable
        Dim acObjIDs As ObjectIdCollection = New ObjectIdCollection()
        Dim acIDMap As IdMapping = New IdMapping()
        Dim intCopyCount = 0
        Dim intBlockCount = 0
        Try
            Using acDestDocLock As DocumentLock = acdocDest.LockDocument()
                Using acSourceDocLock As DocumentLock = acdocSource.LockDocument()
                    Using acSourceTrans As Transaction = acSourceDB.TransactionManager.StartTransaction()
                        Using acDestTrans As Transaction = acDestDB.TransactionManager.StartTransaction()
                            acSourceBlockTable = acSourceTrans.GetObject(acSourceDB.BlockTableId, OpenMode.ForRead)
                            acSourceModelSpace = acSourceTrans.GetObject(acSourceBlockTable(BlockTableRecord.ModelSpace), OpenMode.ForRead)
                            acSourceLayerTable = acSourceTrans.GetObject(acSourceDB.LayerTableId, OpenMode.ForRead)
                            acDestBlockTable = acDestTrans.GetObject(acDestDB.BlockTableId, OpenMode.ForRead)
                            acDestModelSpace = acDestTrans.GetObject(acDestBlockTable(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
                            acDestLayerTable = acDestTrans.GetObject(acDestDB.LayerTableId, OpenMode.ForRead)
                            If acSourceLayerTable.Has(strSourceLayer) And acDestLayerTable.Has(strDestLayer) Then
                                Dim acSourceLayerTableRec As LayerTableRecord = acSourceTrans.GetObject(acSourceLayerTable(strSourceLayer), OpenMode.ForWrite)
                                Dim acSourceLineTypeTable As LinetypeTable = acSourceTrans.GetObject(acSourceDB.LinetypeTableId, OpenMode.ForRead)
                                acSourceLayerTableRec.Name = strDestLayer
                                acSourceLayerTableRec.LinetypeObjectId = acSourceLineTypeTable("Continuous")
                                For Each acObjID As ObjectId In acSourceModelSpace
                                    Using acDBObj As DBObject = acSourceTrans.GetObject(acObjID, OpenMode.ForWrite)
                                        Dim acEnt As Entity = CType(acDBObj, Entity)
                                        If acEnt.Layer = strDestLayer Then
                                            If (bCopyBlocks = False) And TypeOf (acDBObj) Is BlockReference Then
                                                'Do not copy entity as it is a block and the CopyBlocks parameter has been set to False
                                                intBlockCount += 1
                                            Else
                                                acEnt.Linetype = "ByLayer"
                                                acEnt.Color = Colors.Color.FromColorIndex(Colors.ColorMethod.ByAci, 256)
                                                acObjIDs.Add(acObjID)
                                            End If
                                        End If
                                    End Using
                                    intCopyCount += 1
                                Next acObjID
                                acSourceDB.WblockCloneObjects(acObjIDs, acDestModelSpace.ObjectId, acIDMap, DuplicateRecordCloning.Ignore, False)
                                acSourceTrans.Dispose()
                                acDestTrans.Commit()
                                bComplete = True
                            Else
                                bComplete = False
                            End If
                        End Using
                    End Using
                End Using
            End Using
        Catch ex As Exception
            MessageBox.Show("Error importing objects: " & ex.Message & vbCrLf & vbTab & ex.StackTrace, "DASMAP - " & System.Reflection.MethodBase.GetCurrentMethod().Name, MessageBoxButtons.OK, MessageBoxIcon.Error)
            bComplete = False
        End Try
        Return bComplete
    End Function

Chris Welk
Urban Systems Ltd.
Engineering Technologist (Civil)/CADD Applications Developer
Contributor
NovayaEra
Posts: 13
Registered: ‎08-10-2011
Message 7 of 18 (513 Views)

Re: "Clone" an object from one drawing to another with modifications p

12-26-2012 02:15 AM in reply to: cwelkusl

When I do 

acSourceDB.WblockCloneObjects(acObjIDs, acDestModelSpace.ObjectId, acIDMap, DuplicateRecordCloning.Ignore, False)

 can I set point of insertion?

Moderator
Alexander.Rivilis
Posts: 1,434
Registered: ‎04-09-2008
Message 8 of 18 (507 Views)

Re: "Clone" an object from one drawing to another with modifications p

12-26-2012 03:29 AM in reply to: NovayaEra

freestyler8 wrote:

When I do 

acSourceDB.WblockCloneObjects(acObjIDs, acDestModelSpace.ObjectId, acIDMap, DuplicateRecordCloning.Ignore, False)

 can I set point of insertion?


No. But you can open all cloned entities and call method TransformBy for each in order to move entities in new location.


Пожалуйста не забывайте про Утвердить в качестве решения! Утвердить в качестве решения и Give Kudos!Баллы
Please remember to Accept Solution! Accept as Solution and Give Kudos!Kudos

Distinguished Contributor
djonio
Posts: 105
Registered: ‎12-29-2005
Message 9 of 18 (496 Views)

Re: "Clone" an object from one drawing to another with modifications p

12-26-2012 05:58 AM in reply to: cwelkusl

Concerning that message box issue.... maybe this will resolve it.

 

       static public int ErrSetLevel(short _lvl)
        {
            int resbuf_result_status = 0;
            ResultBuffer args1 = new ResultBuffer();
            args1.Add(new TypedValue((int)LispDataType.Text, "ade_errsetlevel"));
            args1.Add(new TypedValue((int)LispDataType.Int16, (short)_lvl));
            ResultBuffer resbuf_result1 = InvokeLisp(args1, ref resbuf_result_status);
            return resbuf_result_status;
        }
        [System.Security.SuppressUnmanagedCodeSecurity]
        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl)]
        extern static private int acedInvoke(IntPtr args, out IntPtr result);
        public static ResultBuffer InvokeLisp(ResultBuffer args, ref int stat)
        {
            IntPtr rb = IntPtr.Zero;
            stat = acedInvoke(args.UnmanagedObject, out rb);
            if (stat == (int)PromptStatus.OK && rb != IntPtr.Zero)
                return (ResultBuffer)DisposableWrapper.Create(typeof(ResultBuffer), rb, true);
            return null;
        }

 

            ErrSetLevel((short)2);

//or 1 if memory serves..

 

r,

dennis

Contributor
NovayaEra
Posts: 13
Registered: ‎08-10-2011
Message 10 of 18 (470 Views)

Re: "Clone" an object from one drawing to another with modifications p

12-26-2012 10:16 PM in reply to: Alexander.Rivilis

Alexander.Rivilis wrote:
you can open all cloned entities and call method TransformBy for each in order to move entities in new location.

How to find cloned entities in destination dwg after cloning? When it was cloned, it got new ObjectID, truly?

 

 

djonio, Thanks, but it so difficult for me :-(

Post to the Community

Have questions about Autodesk products? Ask the community.

New Post
Need installation help?

Start with some of our most frequented solutions or visit the Installation and Licensing Forum to get help installing your software.