2247x
001596
2019-05-13

Методы выбора элементов через COM-интерфейс

При обработке элементов через COM-интерфейс выбор элементов часто вызывает проблему, так как его невозможно осуществить визуально через рабочее окно. Особенно в моделях, которые были созданы через пользовательский интерфейс программы, а затем должны быть изменены с помощью собственной программы, выбор может быть сложным. Помимо исключения, когда выбор был произведен ранее через RFEM, существует несколько альтернатив для программирования.

Выбор по комментарию

Самым простым является назначение комментариев при создании элементов, которые затем могут быть целенаправленно найдены. Ниже приведена примерная функция, которая ищет балки по их комментарию и возвращает найденные номера балок:


Function getMemberNosByComment(members() As RFEM5.Member, comment As String) As Integer()
    Dim intArr() As Integer
    Dim i As Long
    Dim j As Long
    j = 0
    ReDim intArr(0 To 0)
    ' цикл по балкам
    For i = 0 To UBound(members, 1)
        If (members(i).comment = comment) Then
            ' размер массива увеличивается на 1
            ReDim Preserve intArr(0 To j)
            intArr(j) = members(i).no
            j = j + 1
        End If
    Next i
    ' возвращает массив целых чисел
    getMemberNosByComment = intArr
End Function

Функция осуществляет цикл по переданным балкам, и если происходит совпадение строки в "comment" и комментария балки, номер балки добавляется в массив целых чисел. В конце массив чисел с номерами балок возвращается.

Выбор конечных узлов балки

Выбор элементов в программе, а также через интерфейс COM осуществляется с помощью строк. Например, для линии связанные узлы передаются как строка, где номера узлов разделены запятыми. Использование строк требует их преобразования в числовые значения и обратно при программировании. Далее представлена функция, которая может преобразовать номера балок, полученные из предыдущей функции, в строку. Номера балок с помощью функции CStr по одному преобразуются в символы, и после каждого числа к строке добавляется запятая. RFEM/RSTAB игнорирует избыточную запятую в конце строки и она может остаться.


Function intArrToStr(intArr() As Integer) As String
    Dim str As String
    Dim i As Long
    
    For i = 0 To UBound(intArr, 1)
        str = str + CStr(intArr(i)) + ","
    Next i
    
    intArrToStr = str
End Function

С помощью этой функции теперь можно выбрать балки, отфильтрованные по комментарию, через интерфейс COM.


    ' выбрать балки по комментарию
    Dim mems() As RFEM5.Member
    Dim mem_nos() As Integer
    Dim str As String
    
    str = "тестовый комментарий"
    mem_nos = getMemberNosByComment(mems, str)
    
    iModelData.EnableSelections (True)
    
    str = intArrToStr(mem_nos)
    iModelData.SelectObjects MemberObject, str

Часто требуется не только выбор определенных элементов, но и получение зависимых элементов. Примерно показано, как можно найти начальные узлы балки. Поскольку в RFEM это труднее, чем в RSTAB, так как каждой балке соответствует еще и линия, был выбран данный путь.

Сначала необходимо найти номера линий для балок. Следующая функция предполагает наличие номеров балок и ищет соответствующие номера линий.


Function getLineNosByMemberNos(members() As RFEM5.Member, member_nos() As Integer) As Integer()
    
    Dim intArr() As Integer
    Dim i As Long
    Dim j As Long
    Dim k As Long
    
    k = 0
    ReDim intArr(0 To 0)
    
    For i = 0 To UBound(members, 1)
        For j = 0 To UBound(member_nos, 1)
            If (members(i).no = member_nos(j)) Then
                ' увеличить размер массива на 1
                ReDim Preserve intArr(0 To k)
                intArr(k) = members(i).LineNo
                k = k + 1
                ' выйти из цикла по member_nos
                Exit For
            End If
        
        Next j
    Next i
    
    getLineNosByMemberNos = intArr
    
End Function

Функция содержит два вложенных цикла. Главный цикл проходит по балкам, а вложенный цикл - по номерам балок. Для каждой балки массив с номерами балок полностью проходит. Чтобы ускорить этот процесс, подцикл завершается, как только происходит совпадение номеров балок. При совпадении массив с номерами линий каждый раз продлевается на элемент и новая строка добавляется (k - индекс для найденных номеров линий).

Для того, чтобы найти стартовый узел линии или балки, требуется еще одна функция. Эта функция должна пройти по линиям и при совпадении с заданными номерами линий прочитать стартовый узел. Поскольку номера узлов хранятся в строке, теперь потребуется еще одна функция, которая преобразует строку в массив чисел.


Function strToIntArr(intList As String) As Integer()
    ' возможные символы "1-9 ; - ,"
    ' пример: 1-4,5;100 > 1,2,3,4,5,100
    Dim ints() As Integer
    Dim tmpInts() As Integer
    ReDim ints(0)
    
    Dim span As Boolean
    Dim curInt As String
    curInt = ""
    Dim i As Integer
    i = 0
    Dim j As Integer
    Dim curChar As String
    
    Do While (i > Len(intList))
        curChar = Mid(intList, i + 1, 1)
        
        ' если строка содержит "-", отмечается диапазон
        If (curChar = "-") Then
        
            span = True
            tmpInts = ints
            ReDim Preserve tmpInts(0 To UBound(tmpInts, 1) + 1)
            tmpInts(UBound(tmpInts, 1) - 1) = CInt(curInt)
            ints = tmpInts
            curInt = ""
        ' если достигнут последний символ или запятая, или следующая точка с запятой
        ElseIf ((curChar = ",") Or (curChar = ";") Or (i = Len(intList) - 1)) Then
        
            ' последний символ достигнут, или диапазон завершается
            If (i = Len(intList) - 1) Then
                curInt = curInt & curChar
            End If
            
            ' обработать диапазон
            If span Then
                ' создать все числа между диапазоном
                Dim firstNum As Integer
                Dim lastNum As Integer
                firstNum = ints(UBound(ints, 1) - 1)
                lastNum = CInt(curInt)
                curInt = ""
                
                If (firstNum > lastNum) Then
                    Dim tmp1 As Integer
                    tmp1 = lastNum
                    lastNum = firstNum
                    firstNum = tmp1
                    ints(UBound(ints, 1) - 1) = firstNum
                    
                End If
                
                ' расширить ints и добавить новые числа в массив
                tmpInts = ints
                ReDim Preserve tmpInts(0 To UBound(tmpInts, 1) + (lastNum - firstNum))
                
                For j = 0 To (lastNum - firstNum) - 1
                    tmpInts(UBound(ints, 1) + j) = j + firstNum + 1
                Next j
                
                ints = tmpInts
                span = False
            
            ' добавить новую цифру
            Else
                'расширить ints и добавить новое число в ints
                tmpInts = ints
                ReDim Preserve tmpInts(0 To UBound(tmpInts, 1) + 1)
                tmpInts(UBound(tmpInts, 1) - 1) = CInt(curInt)
                ints = tmpInts
                curInt = ""
            End If
        
        Else
        
            curInt = curInt & curChar
        End If
    
        i = i + 1
    Loop
    
    ' массив на один элемент слишком длинный и уменьшается
    ReDim Preserve ints(0 To UBound(ints, 1) - 1)
    
    strToIntArr = ints
End Function

Эта функция проходит по строке и проверяет каждый символ. Если это число или числа, они собираются, пока не будет достигнут конец или другой символ. Если достигается дефис, то определяется диапазон чисел и числа между ними автоматически генерируются.

Теперь можно создать функцию для извлечения начальной точки линии, которая будет очень рациональной.


Function getLineStartNodeNosByLineNos(lines() As RFEM5.RfLine, line_nos() As Integer) As Integer()
    Dim intArr() As Integer
    Dim tmpIntArr() As Integer
    Dim str As String
    Dim i As Long
    Dim j As Long
    Dim k As Long
    
    k = 0
    ReDim intArr(0 To 0)
    
    For i = 0 To UBound(line_nos, 1)
        For j = 0 To UBound(lines, 1)
            If (lines(j).no = line_nos(i)) Then
                ' добавить найденный номер линии в массив
                ReDim Preserve intArr(0 To k)
                str = lines(j).NodeList
                tmpIntArr = strToIntArr(str)
                intArr(k) = tmpIntArr(0)
                k = k + 1
                ' выйти из цикла по line_nos_cpy
                Exit For
            End If
        
        Next j
    Next i
    
    getLineStartNodeNosByLineNos = intArr
End Function

Здесь также два вложенных цикла, как в функции getLineNosByMemberNos. На этот раз порядок очень важен, иначе будет утеряно соответствие узлов линиям. Внешний цикл проходит по номерам линий, и когда во внутреннем цикле встречается совпадение с линией, с помощью функции strToIntArr извлекаются номера узлов, из которых здесь используется первый.

Весь процесс для получения стартовых узлов выглядит следующим образом. Сначала извлекаются номера линий балок с их правильными номерами, затем стартовые узлы линий.


    ' выбрать начальные узлы из балок
    ' получить номера линий любых балок
    Dim line_nos() As Integer
    line_nos = getLineNosByMemberNos(mems, mem_nos)
    ' получить начальные номера всех линий
    Dim stNodes_nos() As Integer
    stNodes_nos = getLineStartNodeNosByLineNos(lines, line_nos)

Резюме и перспективы

Функция getLineNosByMemberNos служит основой для дальнейших функций выбора, таких как getLineStartNodeNosByLineNos. По этому шаблону можно, например, также определить нагрузки для балок. В качестве инструментов еще доступны функции strToIntArr и intArrToStr, которые помогают преобразовать основанный на строках выбор RFEM в числовые массивы.

Еще один способ — выбор по координатам. Например, можно задать определенное пространство, и все элементы внутри этого пространства будут выбраны. Этот вид выбора будет описан в последующей статье.


Автор

Г-н Гюнтель осуществляет техническую поддержку пользователей Dlubal Software.

Ссылки
Скачивания


;