2242x
001596
13-05-2019

Métodos para selección de elementos a través de la interfaz COM

Al editar elementos a través de la interfaz COM, la selección de elementos a menudo representa un problema, ya que no se puede realizar visualmente a través de la ventana de trabajo. Especialmente en modelos que fueron generados a través de la interfaz del programa y luego deben ser modificados por un programa propio, la selección puede ser complicada. Además de la excepción de que la selección haya sido realizada previamente a través de RFEM, existen varias alternativas para la programación.

Selección por comentario

La más sencilla es que al crear elementos se asignan comentarios, que luego se pueden buscar específicamente. A continuación se muestra un ejemplo de una función que busca barras según su comentario y devuelve los números de barra encontrados:

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)
    ' recorrer los miembros
    For i = 0 To UBound(members, 1)
        If (members(i).comment = comment) Then
            ' aumentar el tamaño del array entero en 1
            ReDim Preserve intArr(0 To j)
            intArr(j) = members(i).no
            j = j + 1
        End If
    Next i
    ' devolver array de enteros
    getMemberNosByComment = intArr
End Function

La función tiene un bucle sobre las barras pasadas y, cuando hay una coincidencia entre la cadena "comment" y el comentario de la barra, el número de barra se agrega al campo de enteros. Al final, el campo de enteros con todos los números de barra se devuelve.

Selección de nodos finales de barra

La selección de elementos en el programa y, por lo tanto, también a través de la interfaz COM, se realiza mediante el uso de cadenas. Por ejemplo, en una línea, los nodos asociados se pasan a través de una cadena en la que los números de nodo se almacenan separados por comas. El uso de cadenas requiere conversión a valores numéricos y viceversa en la programación. A continuación se presenta la función que puede convertir los números de barra obtenidos de la función anterior en una cadena. Los números de barra se convierten individualmente en caracteres mediante la función CStr y después de cada número se agrega una coma a la cadena. La coma innecesaria al final de la cadena es ignorada por RFEM/RSTAB y, por lo tanto, puede permanecer.

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

Con esta función ahora es posible seleccionar las barras filtradas por comentario a través de la interfaz COM.

    ' seleccionar barras por comentario
    Dim mems() As RFEM5.Member
    Dim mem_nos() As Integer
    Dim str As String
    
    str = "comentario de prueba"
    mem_nos = getMemberNosByComment(mems, str)
    
    iModelData.EnableSelections (True)
    
    str = intArrToStr(mem_nos)
    iModelData.SelectObjects MemberObject, str

A menudo no basta con la selección de ciertos elementos, sino que se necesitan elementos subordinados. A continuación, se muestra un ejemplo de cómo se puede encontrar los nodos iniciales de una barra. Como el proceso en RFEM es algo más complicado que en RSTAB, ya que aquí cada barra también pertenece a una línea, se ha elegido este camino.

Primero se deben encontrar los números de línea para las barras. La siguiente función asume que ya se tienen los números de barra y busca los números de línea correspondientes.

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
                ' aumentar tamaño del array en 1
                ReDim Preserve intArr(0 To k)
                intArr(k) = members(i).LineNo
                k = k + 1
                ' salir del bucle sobre member_nos
                Exit For
                        End If
        
        Next j
        Next i
    
    getLineNosByMemberNos = intArr
    
End Function

Esta función tiene dos bucles anidados. La bucle principal recorre las barras y la bucle secundaria recorre los números de barra. En cada barra, el campo con los números de barra se recorre completamente. Para acelerar este proceso, se abandona el bucle secundario tan pronto como se encuentra una coincidencia de números de barra. En caso de coincidencia, el campo con los números de línea se alarga cada vez un elemento y se agrega el nuevo número (k es el índice para los números de línea encontrados).

Para encontrar el nodo inicial de la línea o barra, se necesita otra función. Esta función debe recorrer las líneas y, en caso de coincidencia con los números de línea dados, leer el nodo inicial. Dado que los números de nodo se almacenan en una cadena, ahora se necesita una función que convierta la cadena en un campo de números.

Function strToIntArr(intList As String) As Integer()
    '  caracteres posibles "1-9 ; - ,"
    '  ejemplo: 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)
        
        ' si la cadena contiene "-" se nota un rango
        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 = ""
        ' si se alcanza el último carácter o la siguiente es una coma o punto y coma
        ElseIf ((curChar = ",") Or (curChar = ";") Or (i = Len(intList) - 1)) Then
        
            ' se alcanza el último carácter, se termina entero o rango
            If (i = Len(intList) - 1) Then
                curInt = curInt & curChar
            End If
            
            ' tratar el rango
            If span Then
                ' crear todos los enteros entre el rango
                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
                
                ' extender ints y agregar nuevos números al array
                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
            
            ' añadir nuevo dígito
            Else
                'extender ints y agregar nuevo número a int
                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
    
    ' el array es un elemento demasiado largo y se reduce
    ReDim Preserve ints(0 To UBound(ints, 1) - 1)
    
    strToIntArr = ints
End Function

Esta función recorre la cadena y examina cada carácter. Si es un número o varios, estos se recogen hasta que se alcanza el final o se encuentra otro carácter. Cuando se alcanza un guion, se reconoce una serie/rango de números y los números intermedios se generan automáticamente.

La función real para extraer el punto de inicio de una línea se puede crear ahora y resulta así muy clara.

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
                ' añadir número de línea encontrado al array
                ReDim Preserve intArr(0 To k)
                str = lines(j).NodeList
                tmpIntArr = strToIntArr(str)
                intArr(k) = tmpIntArr(0)
                k = k + 1
                ' salir del bucle sobre line_nos_cpy
                Exit For
            End If
        
        Next j
    Next i
    
    getLineStartNodeNosByLineNos = intArr
End Function

Aquí también hay dos bucles anidados, como en la función getLineNosByMemberNos. Esta vez, el orden es de gran importancia, ya que de otro modo se perdería la asignación de nodos a líneas. El bucle exterior recorre los números de línea y, cuando en el bucle interior se encuentra una coincidencia con una línea, los números de nodo se extraen usando la función strToIntArr, usando aquí el primero.

El flujo completo para encontrar los nodos de inicio se ve entonces como sigue. Primero se obtienen los números de línea de las barras con los números de barra correspondientes y luego los nodos iniciales de línea.

    ' seleccionar nodos iniciales de las barras
    '   obtener números de línea de todas las barras
    Dim line_nos() As Integer
    line_nos = getLineNosByMemberNos(mems, mem_nos)
    '   obtener números de inicio de todas las líneas
    Dim stNodes_nos() As Integer
    stNodes_nos = getLineStartNodeNosByLineNos(lines, line_nos)

Resumen y perspectiva

La función getLineNosByMemberNos forma la base para otras funciones de selección así como para la función getLineStartNodeNosByLineNos. Usando este patrón, es posible, por ejemplo, encontrar también cargas relacionadas con barras. Se dispone de las funciones strToIntArr e intArrToStr como herramientas que permiten convertir la selección basada en cadenas de RFEM en campos numéricos.

Otra posibilidad es la selección por coordenadas. Por ejemplo, se puede definir un espacio y todos los elementos dentro de este espacio son seleccionados. Esta forma de selección se describirá en un artículo posterior.


Autor

El Sr. Günthel proporciona soporte técnico para los clientes de Dlubal Software y se ocupa de sus solicitudes.

Enlaces
Descargas


;