VB.NET reading in level IDs from multiple design files.

Anyone know a more efficient way of reading the level IDs from a design file?  Here's what I have:

#############CODE#############

        Dim msAppCon As MicroStationDGN.ApplicationObjectConnector
        Dim msApp As MicroStationDGN.Application
        Dim msDF As MicroStationDGN.DesignFile
        Dim mslvl As MicroStationDGN.Level
        Dim stemp() As String
        Dim i As Integer = 0
        Dim swTimer As New Stopwatch
        Dim ii As Integer = 0

        msAppCon = CType(CreateObject("MicroStationDGN.ApplicationObjectConnector"), MicroStationDGN.ApplicationObjectConnector)
        msApp = msAppCon.Application

        swTimer.Start()

        For ii = 1 To 80
            sslStatus.Text = CStr(ii)

            msDF = msApp.OpenDesignFileForProgram( DGNFilePath , True)

            For Each mslvl In msDF.DefaultModelReference.Levels
                If Not mslvl.IsFromLevelLibrary Then
                    ReDim Preserve stemp(i)
                    stemp(i) = mslvl.Name & " , " & mslvl.ID.ToString
                    i += 1
                End If
            Next

        Next

        swTimer.Stop()

        MsgBox("Average time = " & swTimer.ElapsedMilliseconds / 80)

#############CODE#############

That gives me an average time of 588ms.  It also isnt very stable.  I'm constantly getting errors where it cant reference the COM object because the reference timed out, so i try again and it works fine.  So i tried somthing a little different:

#############CODE#############

        Dim msApp As New MicroStationDGN.Application
        Dim msDF As MicroStationDGN.DesignFile
        Dim mslvl As MicroStationDGN.Level
        Dim stemp() As String
        Dim i As Integer = 0
        Dim swTimer As New Stopwatch
        Dim ii As Integer = 0

        swTimer.Start()

        For ii = 1 To 80
            sslStatus.Text = CStr(ii)

            msDF = msApp.OpenDesignFileForProgram( DGNFilePath , True)

            For Each mslvl In msDF.DefaultModelReference.Levels
                If Not mslvl.IsFromLevelLibrary Then
                    ReDim Preserve stemp(i)
                    stemp(i) = mslvl.Name & " , " & mslvl.ID.ToString
                    i += 1
                End If
            Next

        Next

        swTimer.Stop()

        MsgBox("Average time = " & swTimer.ElapsedMilliseconds / 80)

#############CODE#############

Basically i removed the msAppCon (i'm not entire sure why it's needed since the above is actually more stable...)  The average time is about 591ms, so an irrevelant increase time.

The problem i have is that this is a small example, i need to read in more files, and they are potentially bigger...  So, it can take a significant amount of time to process 120+ files.  Especially if you process the files, then noticed that you forgot somthing and need to make a change and process again...

I looked into exporting the levels to a csv file and reading that in (i tried somthing similar with excel and reduced my times from 1 minute to 345ms!!!) but it doesnt export the level ID...

I could do multi-threading, but its annoying and i'd perfer not to if possible...

Any help or ideas would be greatly appriciated!

  • I guess the ReDim statement wastes a more time. Could you try to declare a fixed size string array (it needs big enough) out of the two For loops and use it over and over.

    If you persue performance, I recommend you to use native code (e.g. C/C++ programming approach) to do this task.

    HTH, Yongan



  • Wow, i never knew how long the redim statement took!!! i set stemp to start with 10,000 and it only took 105ms on average!

    Thanks for the help!  +1 to awesomness for you sir.

    (anyone else have any awesome ideas?)

    Edit: Here's my updated code.  It takes about 100ms on average... I've highlighted the pertanent changes...

            Dim msApp As New MicroStationDGN.Application
            Dim msDF As MicroStationDGN.DesignFile
            Dim mslvl As MicroStationDGN.Level
            Dim stemp() As String
            Dim iMax As Integer = 0
            Dim i As Integer = 0
            Dim swTimer As New Stopwatch
            Dim ii As Integer = 0

            swTimer.Start()

            For ii = 1 To 80
                sslStatus.Text = CStr(ii)

                msDF = msApp.OpenDesignFileForProgram( FilePath , True)

                For Each mslvl In msDF.DefaultModelReference.Levels
                    If Not mslvl.IsFromLevelLibrary Then

                        If i >= iMax Then
                            iMax += 1000
                            ReDim Preserve stemp(iMax)
                        End If

                        stemp(i) = mslvl.Name & " , " & mslvl.ID.ToString
                        i += 1
                    End If
                Next

            Next

            swTimer.Stop()

            MsgBox("Average time = " & swTimer.ElapsedMilliseconds / 80 & "  " & UBound(stemp))

  • Unknown said:
    anyone else have any awesome ideas?

    Not very awesome, but the VBA Forum would have been a better place to post questions about MicroStaiton VBA.

    VBA Performance

    Unknown said:
    I never knew how long the redim statement took!

    Microsoft designed VBA to be a Rapid Application Development (RAD) tool, not a tool to create rapid applications.  Use VBA to prototype an application by all means, but if performance is an issue prefer a high-performance language such as C++.

    Level IDs

    By the way, why do you want to save the Level IDs from multiple files?  While level names don't change, level IDs (which are assigned by MicroStation) could change for a variety of reasons not under your control.  What you save today may not be valid  tomorrow.

     
    Regards, Jon Summers
    LA Solutions

  • This isnt in VBA, which is why i didnt post it in VBA... it's in VB.NET (well, more accurately Visual Studio), should i have posted in VBA anyway?

    I havent programmed in C++ in a long time... speed isnt the highest priority, but i'd like it to be acceptably fast...

    As for the Level ID's, aparently bentley thought it'd be a good idea to create Level ID's when you draw somthing on a level.  So the ID's for the levels have nothing to do with the level itself.  This is an issue when our plot files are keyed off of the level ID's.  So what i need to do is read in the DGN, get and new or changed levels and pull microstations arbitrarily assigned ID and update the plot file... (hope that made sence)

    Thanks for the input!

  • Unknown said:
     So the ID's for the levels have nothing to do with the level itself.  This is an issue when our plot files are keyed off of the level ID's

    The LevelID exposed by MicroStation development languages, including VBA, is the internal unique-per-DGN code assigned by MicroStation.  Two DGN files may contain the same level (by name) but each could have a different LevelID

    Please distinguish between the visible level code and the internal level ID.  The level code is — like the level name — user-assigned .  You can see the level code in the various level dialogs.   A user can never see a level ID.  Level codes are consistent from DGN to DGN.

    Unknown said:
    Apparently Bentley thought it'd be a good idea to create Level ID's when you draw somthing on a level

    When you create a new level MicroStation assigns it a level ID.  The internal level ID is the unambiguous identity of a level within a given DGN file.  The level name and level code are human-readable aliases for that internal ID.

     
    Regards, Jon Summers
    LA Solutions

  • Sorry if i wasnt clear, I'm talking about the Level ID that changes from file to file.  (We have 550 levels.  The User cannot create levels, we can only use levels created by the Design Resource Engineer.)  Those levels have unique names.

    In our plot file, the level display is controled by the Level ID.  I can actually omit the level name in the plot file and just have the ID in there since the ID is completely independent of the level name.  So, since these levels already exist, the Level ID is dependent on when somthing has been drawn.  Therefore, they change from DGN to DGN.

    This is why i'm creating a program.  If you create a plot file and then, for example, get sewer line info from the utility company, that level is not in the plot file since it was empty at the creation of the plot file.  I cant just add the level name into the plot file becuase i dont know its level ID...  So, i need to go into the DGN, pull its Level ID and add the level into the plot file with the correct ID.  

    I updated the main code with the modified Redim Preserve parts and it still takes a while... About 1.7 seconds per DGN (with a total of 55 DGN's to read through in one of the tests i'm running, it's annoying)

    I think i'm going to multi-thread this and see how much faster it is...