The errors you're seeing are due to a mismatch with the second argument in the GetElements method. In FEMAP, when arrays are passed back via the API, almost always (check the documentation to be sure or look at what Intellisense is telling you), the variable that's passed in needs to be a variant, not any sort of typed array, especially if it's been pre-dimensioned. The following API will show you how to get all the elements in all freebody objects (will work for nodes as well if you use GetNodes() ):
Code:
Sub Main
Dim App As femap.model
Set App = feFemap()
' Declare FEMAP variables for freebody object and set object to hold freebody IDs
Dim ffb As femap.Freebody
Dim fsfb As femap.Set
' Declare variables for number of elements and variant array
Dim nElem As Long
Dim vnIDs As Variant
' Only initialize the set
Set fsfb = App.feSet
' Add all freebody IDs to the set object
fsfb.AddAll( FT_FREEBODY )
' Go BEFORE the first ID in the set
fsfb.Reset()
' Use while loop to loop through all IDs in set containing entity IDs
While( fsfb.Next() )
' Initialize freebody object within loop
Set ffb = App.feFreebody
ffb.Get( fsfb.CurrentID )
ffb.GetElements( n, nid )
Wend
End Sub
The first thing I'll point out here is that while this code works, it's not what I'd consider "standard." While writing this up I discovered a bug in certain versions of FEMAP that may not clear out variants before returning them if the freebody object is used before. That's why the "Set xxx = App.feFreebody" instruction is nested inside the loop; it effectively forces everything inside the object to be reset. This is fixed for the upcoming 11.3 release, however the code presented above works for all versions. Because everything in the object is reset this way, it's not usable inside of a loop where you're looking for Next() as a fail condition to exit your loop.
This is the type of code I would recommend in most circumstances:
Code:
Sub Main
Dim App As femap.model
Set App = feFemap()
' Declare / set variable for freebody and element set
Dim ffb As femap.Freebody
Dim fsE As femap.Set
Set ffb = App.feFreebody
Set fsE = App.feSet()
' Declare long for element count and variant for array of element ids
Dim nCount As Long
Dim vnIDs As Variant
' Move pointer BEFORE start of first entity....
' Next() will move the pointer to the first entity
' No further Get() is required with this method
ffb.Reset()
While( ffb.Next() )
If ffb.GetElements( nCount, vnIDs ) = FE_OK Then
fsE.Clear()
fsE.AddArray( nCount, vnIDs )
App.feViewShow( FT_ELEM, fsE.ID )
App.feAppMessage( FCM_NORMAL, "First 2 elements in freebody " + Str$( ffb.ID ) )
App.feAppMessage( FCM_NORMAL, Str$( vnIDs(0) ) + ", " + Str$( vnIDs(1) ) + ", " + Str$( vnIDs(2) ) )
MsgBox( "Showing elements in freebody " + Str$( ffb.ID ) )
App.feViewRegenerate( 0 )
End If
Wend
End Sub
As you can see in both examples, a variant is passed in for the return array, rather than a dynamic long array or a pre-dimensioned long array. As I mentioned before, retrieving arrays of data from FEMAP works this way in the majority of circumstances.
One other thing I'll point out is that when dealing with Set objects or Entity objects, I like to recommend calling Reset() prior to any looping if the intent is to walk through all the IDs in the model. Calling Reset() will move the pointer BEFORE the first ID (sets) / entity (entity objects) and the CurrentID (set) or ID (entity) property is set to -1, indicating that you're before the start of any entities. Calling Next() will move the pointer to the next available ID / entity, and for entity objects, it effectively "Gets" that entity from the database as well. First(), on the other hand, will move the pointer TO the first ID in a set of the first entity in a database. Just like Next(), First() will also retrieve the entity from the database, eliminating the need for an additional Get(). The big difference in how you walk the entities, however, lie in the loops.
Lets assume that we have a node object and there are nodes 1 through 5 in the database
** Using First() **
Code:
fn.First()
Do
Debug.Print Str$( fn.ID )
Loop Until Not fn.Next()
** Using Next() **
Code:
fn.Reset()
While( fn.Next() )
Debug.Print Str$( fn.ID )
Wend
The difference between the two is where the conditional check lies... With First(), you need to perform the conditional check after you handle the data within the first entity, whereas with Next(), you do it after the conditional check because nothing has been retrieved from the database yet. In both of these cases, the debug window will print out:
If you were to use the While/Wend structure with First(), you'd actually get this:
You would effectively be skipping the first ID/entity in the database.
While both are perfectly acceptable, I almost always recommend Reset() followed by a While/Wend, because of minor differences between what Next() actually returns for entities and sets (the differences lie in how each object works), both for IDs within a range or when you get to the final ID or the maximum label in a model.
Hope that helps; please post back if you have any further trouble getting going.
Patrick