MicroStation® is Bentley Systems flagship product for 3D computer-aided-design (CAD). Questions similar to this appear on the Be Community Forums. This problem appeared in the MicroStation Programming Forum.

Q How do I find elements on a specific level using MicroStation VBA?

Q How do I find elements of a particular type (e.g. text elements) using MicroStation VBA?

A MicroStation includes a scanning engine that is used for many purposes. It's available to you in VBA as the ModelReference.Scan method. You specify what you want to search for (e.g. elements on a named level) through the ElementScanCriteria object.

The methodology of scanning a model is straightforward …

Enumeration provides you with a list of elements, each of which has already passed the test you imposed with your scan criteria. So, if you specified a level filter, you know that each element received from the enumerator belongs to one of the levels specified. If your scan criteria requested only text elements, then each element returned by the enumerator will be a TextElement.

Example 1: Scan by Level

There are a number of scanning examples provided in the VBA help. Search help for scan criteria or scan to find them. Here's an example that searches for elements on a named level: copy this code into a module in the VBA editor, supply a valid level name, and vba run Main …

Main entry point 
Sub Main()
    Dim nElements   As Long
    Const levelName As String = "Level 11"
    nElements = ScanByLevel(levelName)
    MsgBox "Found " & CStr(nElements) & " elements on level '" & levelName & "'", vbInformation Or vbOKOnly, "Scanned Elements"
End Sub
' -------------------------------------------------------------- 
' Process any element that meets the scan criteria: named level 
' -------------------------------------------------------------- 
Function ScanByLevel(levelName As String) As Long

    Dim nElements       As Long
    nElements = 0
	'	Find named level
    Dim oLevel          As Level
    Set oLevel = ActiveModelReference.Levels(levelName)
    If (oLevel Is Nothing) Then
        MsgBox "Level '" & levelName & "' does not exist", vbCritical Or vbOKOnly, "Nonexistent Level"
        Exit Function
    End If
	'	Set up scan criteria
    Dim oScanCriteria   As ElementScanCriteria
    Set oScanCriteria = New ElementScanCriteria
    oScanCriteria.ExcludeAllLevels
    oScanCriteria.IncludeLevel oLevel
	'	Perform the scan
    Dim oEnumerator     As ElementEnumerator
    Set oEnumerator = ActiveModelReference.Scan(oScanCriteria)
    Do While oEnumerator.MoveNext
        oEnumerator.Current.Redraw msdDrawingModeHilite
        nElements = nElements + 1
    Loop
    ScanByLevel = nElements
End Function

Example 2: Scan for Text Elements

There are a number of scanning examples provided in the VBA help. Search help for scan criteria or scan to find them. Here's an example that searches for text elements and processes only those text elements of a certain size: copy this code into a module in the VBA editor and vba run Main …

Main entry point 
Sub Main()
    Dim nWords   As Long
    nWords = ScanForText()
    MsgBox "Found " & CStr(nWords) & " text elements", vbInformation Or vbOKOnly, "Text Elements"
End Sub
' -------------------------------------------------------------- 
' Process text elements                                          
' -------------------------------------------------------------- 
Function ScanForText() As Long
    Dim nElements       As Long
    nElements = 0

    '	Set up scan criteria
    Dim oScanCriteria   As ElementScanCriteria
    Set oScanCriteria = New ElementScanCriteria
    oScanCriteria.ExcludeAllTypes
    oScanCriteria.IncludeType msdElementTypeText
    '	Perform the scan
    Dim oEnumerator     As ElementEnumerator
    Set oEnumerator = ActiveModelReference.Scan(oScanCriteria)
    Do While oEnumerator.MoveNext
        oEnumerator.Current.Redraw msdDrawingModeHilite

        If MatchTextParams (oEnumerator.Current.AsTextElement) Then
            nElements = 1 + nElements
        End If
        oEnumerator.Current.Redraw msdDrawingModeNormal
    Loop
    ScanTextElements = nElements
End Function

Here's the function that does the work of analysing each text element to determine whether it matches our requirements …

Function MatchTextParams (ByVal oText As TextElement) As Boolean
    MatchTextParams = False
    '	Metrics used for examining the size of a text element
    Const MatchHeight As Double = 0.0035
    Const MatchWidth As Double = 0.0025
    Const Epsilon As Double = 0.00001
    Dim width   As Double, _
        height  As Double
    width = oText.TextStyle.width
    height = oText.TextStyle.height
    Debug.Print "Found text '" & oText.Text & "' width=" & FormatNumber(width, 6, True) & " height=" & FormatNumber(height, 6, True)
    If (Epsilon > Abs(MatchWidth - width)) Then
        Debug.Print "Matched width " & FormatNumber(width, 6, True)
    End If

    If (Epsilon > Abs(MatchHeight - height)) Then
        Debug.Print "Matched height " & FormatNumber(height, 6, True)
    End If

    If ((Epsilon > Abs(MatchWidth - width)) _
        And _
        (Epsilon > Abs(MatchHeight - height))) Then
        Debug.Print "Matched text '" & oText.Text & "'"
        ShowMessage "Matched Text Element!", "Matched Text Element!"
        MatchTextParams = True
    End If
End Function