Get to Text objects within Imported Dwg

Get to Text objects within Imported Dwg

grahamcook
Advocate Advocate
10,359 Views
28 Replies
Message 1 of 29

Get to Text objects within Imported Dwg

grahamcook
Advocate
Advocate

Hi
I am successfully importing a dwg and extracting a collection of blocks, their coordinates and rotation.

 

Problem is I also need to get to the Text objects within the imported DWG for which the only method I know is to Explode the DWG which then reveals the Text as TextNote objects.  This gives me what i need all be it with the expense of exploding the DWG (I remove the elements after) but the issue here is that the Explode command only supports up to 10000 elements meaning I can’t get to the Text objects within the dwg Import if this limit is exceeded.

 

If anyone out there knows how to get the Text objects from a single dwg ImportInstance without Exploding first I would be extremely graceful in finding out.  Interestingly you can get to a single Text object through the UI by selecting the Imported DWG and then clicking the Query Button under the Modify Tab.

 

The simplified code that loops looking for GeometryInstance (blocks) is listed below.

 

            string FileName = "";

            ElementId elementid = null;

            DWGImportOptions options = new DWGImportOptions();
            options.SetRefPoint(new XYZ(0, 0, 0));
            options.Placement = Autodesk.Revit.DB.ImportPlacement.Centered;
            options.OrientToView = true;

            doc.Import(FileName, options, doc.ActiveView, out elementid);

            // Get hold of the imported dwg object and drill down through the
//elements picking out the blocks ImportInstance dwg = doc.GetElement(elementid) as ImportInstance; if (dwg == null) return Result.Failed; foreach (GeometryObject geometryObj in dwg.get_Geometry(new Options())) { if (geometryObj is GeometryInstance) // This will be the whole thing { GeometryInstance dwgInstance = geometryObj as GeometryInstance; foreach (GeometryObject blockObject in dwgInstance.SymbolGeometry) { if (blockObject is GeometryInstance) // This could be a block { //get the object name and coordinates and rotation and
//load into my own class clsBlockInstance blockCls = new clsBlockInstance(); GeometryInstance blockInstance = blockObject as GeometryInstance; string name = blockInstance.Symbol.Name; Transform transform = blockInstance.Transform; XYZ origin = transform.Origin; XYZ vectorTran = transform.OfVector(transform.BasisX.Normalize()); double rot = transform.BasisX.AngleOnPlaneTo(vectorTran, transform.BasisZ.Normalize()); // radians rot = rot * (180 / Math.PI); // degrees blockCls.Name = name; blockCls.Origin = origin; blockCls.Rotation = rot; blockInstanceCollection.Add(blockCls); } } } }

 

0 Likes
10,360 Views
28 Replies
Replies (28)
Message 21 of 29

27925916
Advocate
Advocate

thanks a lot , U reallly do me a big favorSmiley Very Happy

 

my first question is how much time the Add-In cost to create dxf and reading text's content with position?Smiley Very Happy

0 Likes
Message 22 of 29

27925916
Advocate
Advocate

one another question,the GraphicsStyleId of text in dwg importance could be connected with text in dxf?Smiley Embarassed

because when I choose a text of dimension in importance to read its content ,I should use the  GraphicsStyleId to locate it in dxf?

0 Likes
Message 23 of 29

n_dull
Participant
Participant

Can you post all of your script that you are using to access individual block data?  The posting right now is not formatted the best.  Maybe a quick email of the script.  I really need to access individual block positions and rotation and do not want to use Excel to do so.

 

Thanks,

n.dull@emeraldmep.com

0 Likes
Message 24 of 29

grahamcook
Advocate
Advocate

Hi

If you are after the block position and rotation then this is exactly what the code in the first post will give you.

OK, its been taken out of its original context but simply add the code to a command, add a transaction, populate the FileName variable and its almost good to go.  Only thing missing here is the ClsBlockInstance but this is just a simple class that I used to store the data about the block instances found (Name, Origin, Rotation) with some additional methods that mapped these blocks to family equivalents.  I've archived this project now to don't have easy access.

This code does not however retrieve the text objects which was the reason for the original post.  If you are after these then maybe you can follow the dxf route suggested in the thread by Paul Collins.

 

Message 25 of 29

PaulCollins7972
Advocate
Advocate

Here is my code to read text from a dxf file. I used the Autodesk guide to dxf format which is now available here

 

Private Function ReadPointsFromDXF(ByVal Filename As String, ByVal Layers As List(Of String), ByVal SymbolOffset As XYZ) As IList(Of XYZ)
        Try
            Dim line As String
            Dim EntityType As String = vbNullString
            Dim LayerName As String
            Dim PosX As Double
            Dim PosY As Double
            Dim PosZ As Double
            Dim LevelText As String
            Dim EntityCount As Integer = 0
            Dim CoordList As New List(Of XYZ)
            ' Open file.txt with the Using statement.
            Using r As StreamReader = New StreamReader(Filename)
                ' Read first line.
                line = r.ReadLine
                ' Loop over each line in file until the end
                Do While (Not line Is Nothing)
                    If UCase(line) = "ACDBENTITY" Then
                        EntityCount = EntityCount + 1
                        ' "8" is the code for the layer name
                        LayerName = ReadCodeFromFile(r, "8")
                        For Each lay In Layers
                            If LayerName = lay Then
                                'the next line may be 62 if the entity is not color bylayer
                                'or 100 if color bylayer
                                ' "100" is the code for the subclass marker
                                EntityType = ReadCodeFromFile(r, "100")
                                'only get MTEXT entries
                                If UCase(EntityType) = "ACDBMTEXT" Then
                                    'load the relevant lines from the file into an array and use that to read values
                                    'because the order of the section codes should not be relied on
                                    DxfDef.Clear()
                                    Dim code As String = vbNullString
                                    Dim value As String = vbNullString
                                    'Do Until value = "ENDBLK" Or value = "ENDSEC"
                                    'code "1" is the Text Marker
                                    Do Until code = "1"
                                        code = Trim(r.ReadLine)
                                        value = Trim(r.ReadLine)
                                        DxfDef.Add(New KeyValuePair(Of String, String)(code, value))
                                    Loop
                                    ' "10" is the code for the insertion point x value
                                    PosX = CDbl(ReadCode("10"))
                                    ' "20" is the code for the insertion point y value
                                    PosY = CDbl(ReadCode("20"))
                                    ' "30" is the code for the insertion point z value
                                    PosZ = CDbl(ReadCode("30"))
                                    ' "1" is the code for the text string
                                    LevelText = ReadCode("1")
                                    'check if the level text is actually a pos or just descriptive text
                                    Dim Z As Double
                                    If Double.TryParse(LevelText, Z) Then
                                        PosX = PosX + SymbolOffset.X
                                        PosY = PosY + SymbolOffset.Y
                                        Dim p As New XYZ(PosX, PosY, Z)
                                        If ValidatePos(CoordList, p) Then
                                            CoordList.Add(p)
                                        End If
                                    End If
                                End If
                            End If
                        Next
                    End If
                    ' Read in the next line.
                    line = r.ReadLine
                Loop
            End Using
            Return CoordList
        Catch ex As Exception
            DisplayError(ex)
        End Try
    End Function
 
    Function ReadCode(ByVal Code As String) As String
        'read a pair of values, codes described in the DXF reference guide
        For Each pair As KeyValuePair(Of String, String) In DxfDef
            If pair.Key = Code Then
                Return pair.Value
            End If
        Next
    End Function
 
    Function ReadCodeFromFile(ByVal r As StreamReader, ByVal Code As String) As String
        'read a pair of values, codes described in the DXF reference guide
        Dim a As String = Trim(r.ReadLine())
        Dim value As String = r.ReadLine
        If a <> Code Then
            Do Until Trim(a) = Code
                a = Trim(r.ReadLine())
                value = r.ReadLine
            Loop
        End If
        Return value
    End Function
0 Likes
Message 26 of 29

birdtools
Participant
Participant

Good Approach...

 

One other way is to use the AutoCAD Interop API from within your add-in to open the original linked (or newly exported) DWG in AutoCAD and read/access the text objects.

0 Likes
Message 27 of 29

Dale.Bartlett
Collaborator
Collaborator

In the original posted code example, the following line (Symbol.Name) is obsolete in Revit 2023:

 GeometryInstance blockInstance = blockObject as GeometryInstance;
                            string name = blockInstance.Symbol.Name;

I have been unable to find what this should change to, despite reading all the updated documentation. Can anyone help with the new line:

string name = blockInstance.Symbol.Name;




______________
Yes, I'm Satoshi.
Message 28 of 29

RPTHOMAS108
Mentor
Mentor

Below is an extract from 'What's New' document.

 

"Geometry Instance

 

The property Element Symbol of the GeometryInstance was deprecated.

The replacement is

GeometryInstance.GetDocument().GetElement(GeometryInstance.GetSymbolGeometryId().SymbolId)"

 

Therefore: GeometryInstance.GetDocument().GetElement(GeometryInstance.GetSymbolGeometryId().SymbolId).Name

 

 

0 Likes
Message 29 of 29

Dale.Bartlett
Collaborator
Collaborator

Thank you very much. I simply could not put that together. For completeness, this is for the original code for Revit 2023+

#if (R2015 || R2016 || R2017 || R2018 || R2019 || R2020 || R2021 || R2022)
string name = blockInstance.Symbol.Name;
#else // 2023+
string name = blockInstance.GetDocument().GetElement(blockInstance.GetSymbolGeometryId().SymbolId).Name;
#endif




______________
Yes, I'm Satoshi.
0 Likes