Author Topic: Import SymbolTableRecords  (Read 656 times)

0 Members and 1 Guest are viewing this topic.

Offline (gile)

  • C#
  • *
  • Posts: 87
  • Karma: +8/-0
  • Gender: Male
    • prefered language: F
    • Prog expertise: Good
    • View Profile
Import SymbolTableRecords
« on: August 21, 2012, 08:59:35 PM »
Hi,

A generic extension method to import SymbolTableRecord objects from a dwg (or dwt) file into a Database.

The ImportSymbolTableRecords() method extends the Database type, that's to say it can be called with the dot(.) operator from a Database instance.
It is generic because it can target any SymbolTable using a Type parameter.
The requiered arguments are the source file full path and ParamArray of strings (one or more SymbolTableRecord names).
The function returns an ObjectIdCollection containing the ObjectId of the cloned SymbolTableRecords (null/Nothing if none have been imported).

C#
Extension methods have to be defined within a static class, they have to be static and their first argument must use the 'this' keyword and be the same type as the extended one.

Code: [Select]
    public static class Extension
    {
        public static ObjectIdCollection ImportSymbolTableRecords<T>(
            this Database targetDb,
            string sourceFile,
            params string[] recordNames)
            where T : SymbolTable
        {
            using (Database sourceDb = new Database())
            {
                sourceDb.ReadDwgFile(sourceFile, System.IO.FileShare.Read, false, "");
                ObjectId sourceTableId, targetTableId;
                switch (typeof(T).Name)
                {
                    case "BlockTable":
                        sourceTableId = sourceDb.BlockTableId;
                        targetTableId = targetDb.BlockTableId;
                        break;
                    case "DimStyleTable":
                        sourceTableId = sourceDb.DimStyleTableId;
                        targetTableId = targetDb.DimStyleTableId;
                        break;
                    case "LayerTable":
                        sourceTableId = sourceDb.LayerTableId;
                        targetTableId = targetDb.LayerTableId;
                        break;
                    case "LinetypeTable":
                        sourceTableId = sourceDb.LinetypeTableId;
                        targetTableId = targetDb.LinetypeTableId;
                        break;
                    case "RegAppTable":
                        sourceTableId = sourceDb.RegAppTableId;
                        targetTableId = targetDb.RegAppTableId;
                        break;
                    case "TextStyleTable":
                        sourceTableId = sourceDb.TextStyleTableId;
                        targetTableId = targetDb.TextStyleTableId;
                        break;
                    case "UcsTable":
                        sourceTableId = sourceDb.UcsTableId;
                        targetTableId = targetDb.UcsTableId;
                        break;
                    case "ViewTable":
                        sourceTableId = sourceDb.ViewportTableId;
                        targetTableId = targetDb.ViewportTableId;
                        break;
                    case "ViewportTable":
                        sourceTableId = sourceDb.ViewportTableId;
                        targetTableId = targetDb.ViewportTableId;
                        break;
                    default:
                        throw new ArgumentException("Requires a concrete type derived from SymbolTable");
                }

                using (Transaction tr = sourceDb.TransactionManager.StartTransaction())
                {
                    T sourceTable = (T)tr.GetObject(sourceTableId, OpenMode.ForRead);
                    ObjectIdCollection idCol = new ObjectIdCollection();
                    foreach (string name in recordNames)
                    {
                        if (sourceTable.Has(name))
                        {
                            idCol.Add(sourceTable[name]);
                        }
                    }
                    if (idCol.Count == 0)
                        return null;
                    IdMapping idMap = new IdMapping();
                    sourceDb.WblockCloneObjects(
                        idCol, targetTableId, idMap, DuplicateRecordCloning.Replace, false);
                    tr.Commit();
                    ObjectIdCollection retVal = new ObjectIdCollection();
                    foreach (ObjectId id in idCol)
                    {
                        if (idMap[id].IsCloned)
                        {
                            retVal.Add(idMap[id].Value);
                        }
                    }
                    return retVal.Count == 0 ? null : retVal;
                }
            }
        }
    }

Using example:
Code: [Select]
ObjectIdCollection result =
    db.ImportSymbolTableRecords<TextStyleTable>(@"F:\gile\Templates\Standard2010.dwt", "Arial_Std", "Romans_Std");

VB
Extension methods have to be defined within a module with the System.Runtime.CompilerServices.Extension() attribute. The first argument have to be the same type as the extended one.

Code: [Select]
    Module Extension
        <System.Runtime.CompilerServices.Extension()> _
        Public Function ImportSymbolTableRecords(Of T As SymbolTable) _
        (targetDb As Database, sourceFile As String, ParamArray recordNames As String()) _
        As ObjectIdCollection
            Using sourceDb As New Database()
                sourceDb.ReadDwgFile(sourceFile, System.IO.FileShare.Read, False, "")
                Dim sourceTableId As ObjectId, targetTableId As ObjectId
                Select Case GetType(T).Name
                    Case "BlockTable"
                        sourceTableId = sourceDb.BlockTableId
                        targetTableId = targetDb.BlockTableId
                        Exit Select
                    Case "DimStyleTable"
                        sourceTableId = sourceDb.DimStyleTableId
                        targetTableId = targetDb.DimStyleTableId
                        Exit Select
                    Case "LayerTable"
                        sourceTableId = sourceDb.LayerTableId
                        targetTableId = targetDb.LayerTableId
                        Exit Select
                    Case "LinetypeTable"
                        sourceTableId = sourceDb.LinetypeTableId
                        targetTableId = targetDb.LinetypeTableId
                        Exit Select
                    Case "RegAppTable"
                        sourceTableId = sourceDb.RegAppTableId
                        targetTableId = targetDb.RegAppTableId
                        Exit Select
                    Case "TextStyleTable"
                        sourceTableId = sourceDb.TextStyleTableId
                        targetTableId = targetDb.TextStyleTableId
                        Exit Select
                    Case "UcsTable"
                        sourceTableId = sourceDb.UcsTableId
                        targetTableId = targetDb.UcsTableId
                        Exit Select
                    Case "ViewTable"
                        sourceTableId = sourceDb.ViewportTableId
                        targetTableId = targetDb.ViewportTableId
                        Exit Select
                    Case "ViewportTable"
                        sourceTableId = sourceDb.ViewportTableId
                        targetTableId = targetDb.ViewportTableId
                        Exit Select
                    Case Else
                        Throw New ArgumentException("Requires a concrete type derived from SymbolTable")
                End Select

                Using tr As Transaction = sourceDb.TransactionManager.StartTransaction()
                    Dim sourceTable As T = DirectCast(tr.GetObject(sourceTableId, OpenMode.ForRead), T)
                    Dim idCol As New ObjectIdCollection()
                    For Each name As String In recordNames
                        If sourceTable.Has(name) Then
                            idCol.Add(sourceTable(name))
                        End If
                    Next
                    If idCol.Count = 0 Then
                        Return Nothing
                    End If
                    Dim idMap As New IdMapping()
                    sourceDb.WblockCloneObjects(idCol, targetTableId, idMap, DuplicateRecordCloning.Ignore, False)
                    tr.Commit()
                    Dim retVal As New ObjectIdCollection()
                    For Each id As ObjectId In idCol
                        If idMap(id).IsCloned Then
                            retVal.Add(idMap(id).Value)
                        End If
                    Next
                    If retVal.Count = 0 Then
                        Return Nothing
                    Else
                        Return retVal
                    End If
                End Using
            End Using
        End Function
    End Module

Using example:
Code: [Select]
Dim result As ObjectIdCollection = _
    db.ImportSymbolTableRecords(Of TextStyleTable)("F:\gile\Templates\Standard2010.dwt", "Arial_Std", "Romans_Std")

F#
F# type extensions allows to easily add any member to an existing type. I let you appreciate how much more concise is the code due to some specific features as tuple let bindings, pattern matching, aggregate operators ...

Code: [Select]
type Database with
    member db.ImportSymbolTableRecords<'T when 'T :> SymbolTable>(sourceFile, ([<ParamArray>] recordNames: string array)) =
        use sourceDb = new Database()
        sourceDb.ReadDwgFile(sourceFile, System.IO.FileShare.Read, false, "")
        let  sourceTableId, targetTableId =
            match typeof<'T>.Name with
            | "BlockTable" -> sourceDb.BlockTableId, db.BlockTableId
            | "DimStyleTable" -> sourceDb.DimStyleTableId, db.DimStyleTableId
            | "LayerTable" -> sourceDb.LayerTableId, db.LayerTableId
            | "LinetypeTable" -> sourceDb.LinetypeTableId, db.LinetypeTableId
            | "RegAppTable" -> sourceDb.RegAppTableId, db.RegAppTableId
            | "TextStyleTable" -> sourceDb.TextStyleTableId, db.TextStyleTableId
            | "UcsTable" -> sourceDb.UcsTableId, db.UcsTableId
            | "ViewTable" -> sourceDb.ViewTableId, db.ViewTableId
            | "ViewportTable" -> sourceDb.ViewportTableId, db.ViewportTableId
            | _ -> invalidArg typeof<'T>.Name "Requires a concrete type derived from SymbolTable"

        use tr = sourceDb.TransactionManager.StartTransaction()
        let sourceTable = tr.GetObject(sourceTableId, OpenMode.ForRead) :?> 'T
        let sourceIds = recordNames |> Array.choose(function
            | n when sourceTable.Has(n) -> Some(sourceTable.[n])
            | _ -> None)
        if sourceIds.Length = 0 then
            null
        else
            let idCol = new ObjectIdCollection(sourceIds)
            let idMap = new IdMapping()
            sourceDb.WblockCloneObjects(idCol, targetTableId, idMap, DuplicateRecordCloning.Replace, false)
            tr.Commit()
            let ids = sourceIds |> Array.choose(function
                | id when idMap.[id].IsCloned -> Some(idMap.[id].Value)
                | _ -> None)
            if ids.Length = 0 then
                null
            else
                new ObjectIdCollection(ids)

Using example:
Code: [Select]
let result =
    db.ImportSymbolTableRecords<TextStyleTable>(@"F:\gile\Templates\Standard2010.dwt", "Arial_Std", "Romans_Std")
« Last Edit: September 02, 2012, 08:43:04 AM by (gile) »