Author Topic: Import Layer from External File  (Read 3238 times)

0 Members and 1 Guest are viewing this topic.

GumbyCAD

  • Newt
  • Posts: 84
Import Layer from External File
« on: April 08, 2014, 02:42:43 AM »
Just when you think you have it.... Bam... :ugly:

Im sure this is an easy one... For you Guru's out there.

I pass a list of Strings (being the layers I want to import) from the External File.

If the SourceDB has the The Layers I want I record the OBJECTID's of Layer and Linetypes
and try to clone them into current drawing.

I have done this before and could get it working.......  Can Anyone help????  Pease ?????
Im just bashing m head into the wall.


Code - vb.net: [Select]
  1.     Private Function ImportLayersFromFile(ByVal SourceFileName As String, ByVal LayerNames As List(Of String)) As String
  2.  
  3.         Dim CurrentDoc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
  4.         Dim ed As Editor = CurrentDoc.Editor()
  5.  
  6.         'Get orignal drawing
  7.         Dim CurrentDB As Database = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database
  8.         Dim Result As String = ""
  9.  
  10.         Dim LDets As List(Of LayerDets) = New List(Of LayerDets)
  11.  
  12.         Try
  13.  
  14.             'lock the current drawing
  15.             Using DokLock As DocumentLock = CurrentDoc.LockDocument
  16.  
  17.                 'Read source Drawing
  18.                 Dim SourceDB As Database = New Database(True, False)
  19.                 SourceDB.ReadDwgFile(SourceFileName, System.IO.FileShare.Read, False, "")
  20.  
  21.                 'start Transaction
  22.                 Using tr As Transaction = SourceDB.TransactionManager.StartTransaction()
  23.  
  24.                     'Make the working database the new database
  25.                     HostApplicationServices.WorkingDatabase = SourceDB
  26.  
  27.                     'Get Layer Table
  28.                     Dim SourceLayerTable As LayerTable = TryCast(tr.GetObject(SourceDB.LayerTableId, OpenMode.ForRead), LayerTable)
  29.                     Dim SourceLineTypeTable As LinetypeTable = TryCast(tr.GetObject(SourceDB.LinetypeTableId, OpenMode.ForRead), LinetypeTable)
  30.  
  31.                     'Get Each layer from Layer Table
  32.                     For Each LayerObjectID As ObjectId In SourceLayerTable
  33.  
  34.                         'set Layer Infomation
  35.                         Dim SourceLayer As LayerTableRecord = TryCast(tr.GetObject(LayerObjectID, OpenMode.ForRead, False), LayerTableRecord)
  36.  
  37.                         If SourceLayer.Name <> "0" AndAlso LayerNames.Contains(SourceLayer.Name.ToUpper) Then
  38.  
  39.                             'Initaliase CLass
  40.                             Dim NewLay As New LayerDets
  41.  
  42.                             NewLay.LayerName = SourceLayer.Name
  43.                             NewLay.LayerObjectID = SourceLayer.ObjectId
  44.  
  45.                             'Set LineType Information
  46.                             Dim LineTypeRec As LinetypeTableRecord = TryCast(tr.GetObject(SourceLayer.LinetypeObjectId, OpenMode.ForRead), LinetypeTableRecord)
  47.                             If LineTypeRec.Name <> "Continuous" Then
  48.                                 NewLay.LineTypeName = LineTypeRec.Name
  49.                                 NewLay.LinetypeObjectID = SourceLayer.LinetypeObjectId
  50.                             End If
  51.  
  52.                             'Add to Class List
  53.                             LDets.Add(NewLay)
  54.  
  55.                         End If
  56.  
  57.                     Next
  58.  
  59.                     'Make the original database the working database
  60.                     HostApplicationServices.WorkingDatabase = CurrentDB
  61.                     Using tr2 As Transaction = CurrentDB.TransactionManager.StartTransaction()
  62.  
  63.                         'Get existing Layer and Linetype Tables
  64.                         Dim CurrentLayerTable As LayerTable = TryCast(tr2.GetObject(CurrentDB.LayerTableId, OpenMode.ForWrite), LayerTable)
  65.                         Dim CurrentLineTypeTable As LinetypeTable = TryCast(tr2.GetObject(CurrentDB.LinetypeTableId, OpenMode.ForWrite), LinetypeTable)
  66.  
  67.                         'Step thru each Layer to copy over
  68.                         For Each Det As LayerDets In LDets
  69.  
  70.                             'Set Replace / Ignore based on Check Box in Dialog
  71.                             Dim ReplaceOrIgnore As DuplicateRecordCloning = If(chkOverWriteLayer.Checked <> False, DuplicateRecordCloning.Replace, DuplicateRecordCloning.Ignore)
  72.  
  73.                             If Det.LinetypeObjectID <> ObjectId.Null Then
  74.  
  75.                                 Dim CloneLTOIDS As New ObjectIdCollection
  76.                                 CloneLTOIDS.Add(Det.LinetypeObjectID)
  77.  
  78.                                 Dim idMapLT As IdMapping = New IdMapping()
  79.                                 SourceDB.WblockCloneObjects(CloneLTOIDS, CurrentLineTypeTable.ObjectId, idMapLT, ReplaceOrIgnore, False)
  80.  
  81.                             End If
  82.  
  83.                             Dim CloneLayOIDS As New ObjectIdCollection
  84.                             CloneLayOIDS.Add(Det.LayerObjectID)
  85.  
  86.                             Dim idMapLay As IdMapping = New IdMapping()
  87.                             SourceDB.WblockCloneObjects(CloneLayOIDS, CurrentLayerTable.ObjectId, idMapLay, ReplaceOrIgnore, False)  '<- Crash  eOutOfRange
  88.  
  89.                         Next
  90.  
  91.                         Result = "Layers Imported from " & SourceFileName & vbCrLf
  92.  
  93.                         tr2.Commit()
  94.  
  95.                     End Using
  96.  
  97.                     tr.Commit()
  98.  
  99.                 End Using
  100.  
  101.             End Using
  102.  
  103.         Catch ex As Exception
  104.  
  105.             Result = ex.ToString
  106.  
  107.         End Try
  108.  
  109.         Return Result
  110.  
  111.     End Function
  112.  


Class Code
Code - vb.net: [Select]
  1.     Private Class LayerDets
  2.  
  3.         Private mLayerName As String = ""
  4.         Public Property LayerName() As String
  5.             Get
  6.                 Return mLayerName
  7.             End Get
  8.             Set(ByVal value As String)
  9.                 mLayerName = value
  10.             End Set
  11.         End Property
  12.  
  13.         Public LayerObjectID As ObjectId = ObjectId.Null
  14.         Private mLineTypeName As String = ""
  15.         Public Property LineTypeName() As String
  16.             Get
  17.                 Return mLineTypeName
  18.             End Get
  19.             Set(ByVal value As String)
  20.                 mLineTypeName = value
  21.             End Set
  22.         End Property
  23.  
  24.         Public LinetypeObjectID As ObjectId = ObjectId.Null
  25.  
  26.         Private mLayerColor As Autodesk.AutoCAD.Colors.Color
  27.         Public WriteOnly Property LayerColor() As Autodesk.AutoCAD.Colors.Color
  28.             Set(ByVal value As Autodesk.AutoCAD.Colors.Color)
  29.                 mLayerColor = value
  30.             End Set
  31.         End Property
  32.         Public ReadOnly Property LayerColorObj() As Autodesk.AutoCAD.Colors.Color
  33.             Get
  34.                 Return mLayerColor
  35.             End Get
  36.         End Property
  37.         Public ReadOnly Property LayerColorName() As String
  38.             Get
  39.                 Return mLayerColor.ColorIndex.ToString
  40.             End Get
  41.         End Property
  42.  
  43.         Private mDescription As String
  44.         Public Property Description() As String
  45.             Get
  46.                 Return mDescription
  47.             End Get
  48.             Set(ByVal value As String)
  49.                 mDescription = value
  50.             End Set
  51.         End Property
  52.     End Class
  53.  

edit:kdub -> formatting code=vbnet
« Last Edit: April 08, 2014, 06:47:02 PM by Kerry »

Locke

  • Guest
Re: Import Layer from External File
« Reply #1 on: April 08, 2014, 08:52:59 AM »
Gumby, thanks for posting your attempt here.  You're clearly comfortable with the language, yet in this instance I think you tried to reinvent the wheel a little (LayerDets class), which ultimately may be causing frustration.

I think the full approach should be split into two separate routines:
1.  Getting layers out of an existing drawing/database.
2.  Setting layers in the current drawing from a list of layers.

This way your code doesn't have to be plagued with trying to do two things at once, and it adds some extensibility down the line.
Here is some proof-of-concept code I tapped out (likely to need optimization):

Getting the layers:
Code - C#: [Select]
  1.  
  2. private static IList<LayerTableRecord> GetLayersFromDrawing(string sourceFile, IList<string> layernames)
  3. {
  4.     if (string.IsNullOrEmpty(sourceFile))
  5.         throw new ArgumentNullException("sourceFile");
  6.  
  7.     if (layernames.Count == 0)
  8.         throw new ArgumentOutOfRangeException("layerNames");
  9.  
  10.     if (!File.Exists(sourceFile))
  11.         throw new FileNotFoundException(sourceFile);
  12.  
  13.     var curDoc = Application.DocumentManager.MdiActiveDocument;
  14.     if (curDoc == null)
  15.         throw new ArgumentNullException("MdiActiveDocument");
  16.  
  17.     var sourceLayers = new List<LayerTableRecord>();
  18.  
  19.     try
  20.     {
  21.         var sourceDb = new Database(true, false);
  22.         sourceDb.ReadDwgFile(sourceFile, FileOpenMode.OpenForReadAndAllShare, false, null);
  23.  
  24.         using (var trans = sourceDb.TransactionManager.StartOpenCloseTransaction())
  25.         {
  26.             var layerTable = (LayerTable)trans.GetObject(sourceDb.LayerTableId, OpenMode.ForRead);
  27.             foreach (var layerId in layerTable)
  28.             {
  29.                 var layer = (LayerTableRecord)trans.GetObject(layerId, OpenMode.ForRead);
  30.                 if (layernames.Any(l => l.Equals(layer.Name, StringComparison.InvariantCultureIgnoreCase)))
  31.                     sourceLayers.Add(layer);
  32.             }
  33.  
  34.             trans.Commit();
  35.         }
  36.     }
  37.     catch (Autodesk.AutoCAD.Runtime.Exception ex)
  38.     {
  39.         System.Diagnostics.Debug.Write(ex.Message);
  40.         curDoc.Editor.WriteMessage(ex.Message);
  41.     }
  42.  
  43.     return sourceLayers;
  44. }
  45.  

Setting the layers:
Code - C#: [Select]
  1.  
  2. private static void AddLayersToCurrentDrawing(IList<LayerTableRecord> layerList)
  3. {
  4.     if (layerList == null)
  5.         throw new ArgumentNullException("layerList");
  6.  
  7.     if (layerList.Count == 0)
  8.         throw new ArgumentOutOfRangeException("layerList");
  9.  
  10.     var curDoc = Application.DocumentManager.MdiActiveDocument;
  11.     if (curDoc == null)
  12.         throw new ArgumentNullException("MdiActiveDocument");
  13.  
  14.     var curDb = curDoc.Database;
  15.  
  16.     try
  17.     {
  18.         using (var trans = curDb.TransactionManager.StartOpenCloseTransaction())
  19.         {
  20.             var layerTable = (LayerTable)trans.GetObject(curDb.LayerTableId, OpenMode.ForWrite);
  21.             foreach(var layer in layerList)
  22.             {
  23.                 if (layerTable.Has(layer.Name))
  24.                     continue;
  25.  
  26.                 layerTable.Add(layer);
  27.                 trans.AddNewlyCreatedDBObject(layer, true);    
  28.             }
  29.  
  30.             trans.Commit();
  31.         }
  32.     }
  33.     catch (Autodesk.AutoCAD.Runtime.Exception ex)
  34.     {
  35.         System.Diagnostics.Debug.Write(ex.Message);
  36.         curDoc.Editor.WriteMessage(ex.Message);
  37.     }
  38. }
  39.  

So these would then be called from a routine like this:
Code - C#: [Select]
  1. var layers = GetLayersFromDrawing(@"C:\Example.dwg", new[] { "Layer1", "Layer2", "Layer3" });
  2. AddLayersToCurrentDrawing(layers);
  3.  

Obviously it would make sense to extend this to linetypes in your case, however you can see the approach.  Maybe it can even be approached more generically so you wouldn't have to keep opening the same database for different kinds of data, where you've got a method for retrieving SymbolTableRecords from an external drawing, and you specify what you want (layer, linetypes, blockdefs, etc.);

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Import Layer from External File
« Reply #2 on: April 08, 2014, 06:29:35 PM »
Layers must have a linetype to survive so they will have a hardpointer to its Linetype which cloning across databases will follow and clone and translate for you.

DuplicateRecordCloning only will work for blocks if trying to overwrite and not layers.

You can use SymbolTable Has method to check if it contains the SymbolTableRecord and use its indexer to get its Objectid for cloning.
So Layertable["LayerName"] or LayerTable("Layername")-VB, instead of opening all the layers and just looping through the names.

For Cloning across databases SymbolTable and SymbolTableRecord have all the methods you need.





fixo

  • Guest
Re: Import Layer from External File
« Reply #3 on: April 11, 2014, 07:01:34 AM »
Also would be good to check measureinit system variable
before using / load linetype
Just a thoughts, friend

GumbyCAD

  • Newt
  • Posts: 84
Re: Import Layer from External File
« Reply #4 on: April 14, 2014, 12:51:43 AM »
I thougvht it was only Far to share the finished solution.

So I ended up with 2 options for this fix:

http://www.theswamp.org/index.php?topic=42539.msg477455#msg477455

and

Class Details:
Code: [Select]
    Private Class LayerDets

        Private mLayerName As String = ""
        Public Property LayerName() As String
            Get
                Return mLayerName
            End Get
            Set(ByVal value As String)
                mLayerName = value
            End Set
        End Property

        Public LayerObjectID As ObjectId = ObjectId.Null
        Private mLineTypeName As String = ""
        Public Property LineTypeName() As String
            Get
                Return mLineTypeName
            End Get
            Set(ByVal value As String)
                mLineTypeName = value
            End Set
        End Property

        Public LinetypeObjectID As ObjectId = ObjectId.Null
        Public LineWeightOBJ As LineWeight = LineWeight.ByLayer
        Public Transparency As Autodesk.AutoCAD.Colors.Transparency

        Private mLayerColor As Autodesk.AutoCAD.Colors.Color
        Public WriteOnly Property LayerColor() As Autodesk.AutoCAD.Colors.Color
            Set(ByVal value As Autodesk.AutoCAD.Colors.Color)
                mLayerColor = value
            End Set
        End Property
        Public ReadOnly Property LayerColorObj() As Autodesk.AutoCAD.Colors.Color
            Get
                Return mLayerColor
            End Get
        End Property
        Public ReadOnly Property LayerColorName() As String
            Get
                Return mLayerColor.ColorIndex.ToString
            End Get
        End Property

        Private mDescription As String
        Public Property Description() As String
            Get
                Return mDescription
            End Get
            Set(ByVal value As String)
                mDescription = value
            End Set
        End Property

        Private mIsPlotable As Boolean = False
        Private mIsFrozen As Boolean = False
        Private mIsOff As Boolean = False
        Private mIsLocked As Boolean = False
        Public Property IsPlotAble() As Boolean
            Get
                Return mIsPlotable
            End Get
            Set(ByVal value As Boolean)
                mIsPlotable = value
            End Set
        End Property

        Public Property IsLocked() As Boolean
            Get
                Return mIsLocked
            End Get
            Set(ByVal value As Boolean)
                mIsLocked = value
            End Set
        End Property

        Public Property IsOff() As Boolean
            Get
                Return mIsOff
            End Get
            Set(ByVal value As Boolean)
                mIsOff = value
            End Set
        End Property

        Public Property IsFrozen() As Boolean
            Get
                Return mIsFrozen
            End Get
            Set(ByVal value As Boolean)
                mIsFrozen = value
            End Set
        End Property
    End Class

Code: [Select]
Private Function ImportLayersFromFile(ByVal SourceFileName As String, ByVal LayerNames As List(Of String)) As String

        Dim CurrentDoc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
        Dim ed As Editor = CurrentDoc.Editor()

        'Get orignal drawing
        Dim CurrentDB As Database = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database
        Dim Result As String = ""

        'Create List Of class to store data about layers
        Dim LDets As List(Of LayerDets) = New List(Of LayerDets)

        Try

            'lock the current drawing
            Using DokLock As DocumentLock = CurrentDoc.LockDocument

                'Read source Drawing
                Dim SourceDB As Database = New Database(True, False)
                SourceDB.ReadDwgFile(SourceFileName, System.IO.FileShare.Read, False, "")

                'start Transaction
                Using tr As Transaction = SourceDB.TransactionManager.StartTransaction()

                    'Make the working database the new database
                    HostApplicationServices.WorkingDatabase = SourceDB

                    'Get Layer Table
                    Dim SourceLayerTable As LayerTable = TryCast(tr.GetObject(SourceDB.LayerTableId, OpenMode.ForRead), LayerTable)
                    Dim SourceLineTypeTable As LinetypeTable = TryCast(tr.GetObject(SourceDB.LinetypeTableId, OpenMode.ForRead), LinetypeTable)

                    'Get Each layer from Layer Table
                    For Each LayerObjectID As ObjectId In SourceLayerTable

                        'set Layer Infomation
                        Dim SourceLayer As LayerTableRecord = TryCast(tr.GetObject(LayerObjectID, OpenMode.ForRead, False), LayerTableRecord)

                        'ignore Layer '0' and also check to make sure that this is one of the layers selected in the dialog box
                        If SourceLayer.Name <> "0" AndAlso LayerNames.Contains(SourceLayer.Name.ToUpper) Then

                            'Initaliase CLass
                            Dim NewLay As New LayerDets

                            'set layer name
                            NewLay.LayerName = SourceLayer.Name

                            'Get LayerObjectOID - Not really needed
                            NewLay.LayerObjectID = SourceLayer.ObjectId

                            'Get Color Object
                            NewLay.LayerColor = SourceLayer.Color

                            'Get LineWeight - Need to test is this need WBObjectCloning
                            NewLay.LineWeightOBJ = SourceLayer.LineWeight

                            'Set LineType Information
                            Dim LineTypeRec As LinetypeTableRecord = TryCast(tr.GetObject(SourceLayer.LinetypeObjectId, OpenMode.ForRead), LinetypeTableRecord)

                            NewLay.LineTypeName = LineTypeRec.Name
                            NewLay.LinetypeObjectID = SourceLayer.LinetypeObjectId

                            NewLay.IsOff = SourceLayer.IsOff
                            NewLay.IsFrozen = SourceLayer.IsFrozen
                            NewLay.IsPlotAble = SourceLayer.IsPlottable
                            NewLay.IsLocked = SourceLayer.IsLocked

                            NewLay.Transparency = SourceLayer.Transparency

                            'Add to Class List
                            LDets.Add(NewLay)

                        End If

                    Next

                    'Make the original database the working database
                    HostApplicationServices.WorkingDatabase = CurrentDB
                    Using tr2 As Transaction = CurrentDB.TransactionManager.StartTransaction()

                        'Get existing Layer and Linetype Tables
                        Dim CurrentLayerTable As LayerTable = TryCast(tr2.GetObject(CurrentDB.LayerTableId, OpenMode.ForWrite), LayerTable)
                        Dim CurrentLineTypeTable As LinetypeTable = TryCast(tr2.GetObject(CurrentDB.LinetypeTableId, OpenMode.ForWrite), LinetypeTable)

                        'Step thru each Layer to copy over
                        For Each Det As LayerDets In LDets

                            'Set Replace / Ignore based on Check Box in Dialog
                            Dim ReplaceOrIgnore As DuplicateRecordCloning = If(chkOverWriteLayer.Checked <> False, DuplicateRecordCloning.Replace, DuplicateRecordCloning.Ignore)

                            'If LineTye object ID is not Null (As in Continuous)
                            If Det.LinetypeObjectID <> ObjectId.Null AndAlso Det.LineTypeName <> "Continuous" Then

                                'Add it for Cloning anyway
                                Dim CloneLTOIDS As New ObjectIdCollection
                                CloneLTOIDS.Add(Det.LinetypeObjectID)

                                Dim idMapLT As IdMapping = New IdMapping()
                                SourceDB.WblockCloneObjects(CloneLTOIDS, CurrentLineTypeTable.ObjectId, idMapLT, ReplaceOrIgnore, False)

                                Det.LinetypeObjectID = CurrentLineTypeTable(Det.LineTypeName)

                            End If

                            'Check to see if current layer exists
                            If CurrentLayerTable.Has(Det.LayerName) = True Then

                                'It exists now Overright only of the CheckBox is tick in Form
                                If chkOverWriteLayer.Checked = True Then
                                    'Over write properties

                                    Dim layerTableRec As LayerTableRecord = DirectCast(tr2.GetObject(CurrentLayerTable(Det.LayerName), OpenMode.ForWrite), LayerTableRecord)

                                    If Det.LayerColorObj IsNot Nothing Then
                                        layerTableRec.Color = Det.LayerColorObj
                                    End If

                                    If Det.LinetypeObjectID <> ObjectId.Null Then
                                        layerTableRec.LinetypeObjectId = Det.LinetypeObjectID
                                    End If

                                    layerTableRec.Description = Det.Description
                                    layerTableRec.LineWeight = Det.LineWeightOBJ

                                    layerTableRec.IsOff = Det.IsOff
                                    layerTableRec.IsFrozen = Det.IsFrozen
                                    layerTableRec.IsPlottable = Det.IsPlotAble
                                    layerTableRec.IsLocked = Det.IsLocked
                                    layerTableRec.Transparency = Det.Transparency

                                End If

                            Else

                                Dim NewLayer As New LayerTableRecord

                                NewLayer.Name = Det.LayerName
                                CurrentLayerTable.Add(NewLayer)
                                tr2.AddNewlyCreatedDBObject(NewLayer, True)

                                If Det.LayerColorObj IsNot Nothing Then
                                    NewLayer.Color = Det.LayerColorObj
                                End If

                                If Det.LinetypeObjectID <> ObjectId.Null Then
                                    NewLayer.LinetypeObjectId = Det.LinetypeObjectID
                                End If

                                NewLayer.Description = Det.Description
                                NewLayer.LineWeight = Det.LineWeightOBJ

                                NewLayer.IsOff = Det.IsOff
                                NewLayer.IsFrozen = Det.IsFrozen
                                NewLayer.IsPlottable = Det.IsPlotAble
                                NewLayer.IsLocked = Det.IsLocked
                                NewLayer.Transparency = Det.Transparency

                            End If

                        Next

                        Result = "Layers Imported from " & SourceFileName & vbCrLf

                        tr2.Commit()

                    End Using

                    tr.Commit()

                End Using

            End Using

        Catch ex As Exception

            Result = ex.ToString

        End Try

        Return Result

    End Function