通过注释选择
最简单的方法可能是在创建元素时分配了注释,然后可以有针对性地进行搜索。下面展示了一个示例函数,用于根据注释搜索杆件并返回找到的杆件编号:
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)
' loop over members
For i = 0 To UBound(members, 1)
If (members(i).comment = comment) Then
' size if integer array is increased by 1
ReDim Preserve intArr(0 To j)
intArr(j) = members(i).no
j = j + 1
End If
Next i
' return integer array
getMemberNosByComment = intArr
End Function
该函数遍历传递的杆件,当杆件的注释与注释字符串匹配时,将杆件编号添加到整数数组中。最后,该整数数组包含所有杆件编号并被返回。
选择杆端节点
在程序中选择元素,以及通过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接口选择根据注释过滤的杆件。
' select members by comment
Dim mems() As RFEM5.Member
Dim mem_nos() As Integer
Dim str As String
str = "test comment"
mem_nos = getMemberNosByComment(mems, str)
iModelData.EnableSelections (True)
str = intArrToStr(mem_nos)
iModelData.SelectObjects MemberObject, str
往往不仅需要选择特定元素,还需要子元素。下面将示例展示,如何找到杆件的起始节点。与在RSTAB中不同,在RFEM中每个杆件属于一条线,因此路径稍微复杂,选择了这个方法。
首先需要找到杆件的线编号。以下函数假定杆件编号已知,并查找相应的线编号。
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
' increase array size by 1
ReDim Preserve intArr(0 To k)
intArr(k) = members(i).LineNo
k = k + 1
' exit loop over member_nos
Exit For
End If
Next j
Next i
getLineNosByMemberNos = intArr
End Function
这个函数有两个嵌套的循环。主循环遍历杆件,子循环遍历杆件编号。对于每个杆件,编号数组会被完全遍历。为了加速这个过程,只要编号匹配,子循环就会退出。每次匹配时,线编号数组会增加一个元素并添加新的编号(k是找到的线编号的索引)。
为了找到线或杆件的起始节点,还需要一个额外的函数。该函数需要遍历线,并在与给定线编号匹配时读取起始节点。由于节点编号存储在字符串中,因此还需要一个函数将字符串转换为数字数组。
Function strToIntArr(intList As String) As Integer()
' possible chars "1-9 ; - ,"
' example: 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 string contains "-" a span is noted
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 = ""
' if last char is reached or a comma or a semicolon is the next char
ElseIf ((curChar = ",") Or (curChar = ";") Or (i = Len(intList) - 1)) Then
' last char is reached, integer or span are terminated
If (i = Len(intList) - 1) Then
curInt = curInt & curChar
End If
' treat the span
If span Then
' create all integers between the span
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
' extend ints and add new numbers to 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
' add new digit
Else
'extend ints and add new number to 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
' array is one element too long and is decreased
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
' add found line number to array
ReDim Preserve intArr(0 To k)
str = lines(j).NodeList
tmpIntArr = strToIntArr(str)
intArr(k) = tmpIntArr(0)
k = k + 1
' exit loop over line_nos_cpy
Exit For
End If
Next j
Next i
getLineStartNodeNosByLineNos = intArr
End Function
这里同样使用两个嵌套的循环,如函数getLineNosByMemberNos中。这次顺序尤为重要,否则节点与线的对应关系会丢失。外层循环遍历线编号,当在内层循环中与一条线匹配时,使用函数strToIntArr提取节点编号并使用第一个。
获取起始节点的整个流程如下:首先获取杆件的线编号,然后获取线的起始节点。
' select start nodes from members
' get line numbers from all members
Dim line_nos() As Integer
line_nos = getLineNosByMemberNos(mems, mem_nos)
' get start numbers from all lines
Dim stNodes_nos() As Integer
stNodes_nos = getLineStartNodeNosByLineNos(lines, line_nos)
总结和展望
函数getLineNosByMemberNos为进一步的选择函数奠定了基础,例如函数getLineStartNodeNosByLineNos。通过这种模式,也可以找到杆件的载荷。而函数strToIntArr和intArrToStr可用于将RFEM中基于字符串的选择转换为数字数组。
另一种方法是通过坐标选择。例如,可以定义一个空间,并选择空间内的所有元素。这种选择形式将在后续的文章中描述。