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 …
This could be, for example, elements on a certain level, elements of a certain type, or some combination of those criteria
ElementScanCriteria
object and specify your filter requirements ModelReference.Scan
method
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
.
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
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