we are trying to create instances of columns, slabs, beams, piles, etc. programmatically with the help of the Bentley.Building.Api.
So far i successfully created walls with TFLoadableWallList. There is also an c# example for TFLoadableSlabList shipped with the SDK.The documentation hints that with a TFLoadableList I should be able to create other types of objects than walls and slabs:
"TFloadable stands for anything that can be "loaded" from a catalog. Basically if there's a placement tool that allows you to place an item from a catalog, there might be a loadable for these items. the workflow to place a loadable goes as following:
1. pick a TFCatalogItem 2. initialize loadable with the picked catalog item 3. fill in other item-specific geometry data (endpoints for wall, origin for cells, brep for slabs) 4. place the item (_getElmDscr)"
Somehow I am struggling with picking the TFCatalogItems for anything else than slabs and walls. I have the corresponding catalog items I am looking for present in my model.
TFCatalogList datagroup = new TFCatalogList();
ITFCatalog catalog = datagroup as ITFCatalog;
catalog.GetAllCatalogTypesList(0, out typeList);
catalog.GetCatalogItemByNames(catalogTypeName, catalogInstanceName, 0, out itemList);
// catalog.GetCatalogItemsByTypeName(catalogTypeName, 0, out itemList);
The same code works for walls.
Can someone clear that up and point me in the right direction (further documentation, etc.)?Is it possible to place beams programmatically?Is it worth looking into more recent updates of OBD?
Thank you for the response. We have filed an bug so that the developer to have a look at the forum post and that way they can suggest an workflow or workaround. Bug number:792728.
Hi Alifur,thanks for your reply.A small update on the post above: I can successfully pick catalog items (other than slabs and walls) now, but I am still struggling with step 2: "initialize loadable with the picked catalog item"..Best regards,Tilman
unfortunately the TFLoadable API is not available for placement of these structural components. However you can do it using the API proveded in Bentley.Interop.STFCom module STFStructuralMemberList class
as I've said, unfortunately structural elements are not available for placement as TFLoadable. However there are ways to place beams programmatically: using native stfc.lib or either through COM or .Net Structural interface.
Here is a code example using .Net interface that will loop through all available datagroup catalog types, find the ones that implement StructuralFramingCommon interface and add a beam to the model for every catalog item in that type, with a different Wide Flange section for each.
Edit: the .net API is available through Bentley.Building.Api namespace from Bentley.Building.Structural.Api.dll
Please let me know if this helps
private static void placeStructuralMember(ITFCatalogItem catalogItem, ISTFSection section, DPoint3d start)
var linearMemberList = new STFLinearMemberList();
var linearMember = linearMemberList.AsSTFLinearMember;
section.GetName(0, out sectionName);
DPoint3d end = start;
end.Z = end.Z + 10;
linearMember.SetPQPoints(ref start, ref end, 0);
linearMember.AddToDgnExt(Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnModelRef(), false, 0);
private static void create()
ITFCatalogList tfCatalog = new TFCatalogList();
ITFCatalogTypeList catalogTypes = null;
tfCatalog.AsTFCatalog.GetAllCatalogTypesList(0, out catalogTypes);
ISTFSectionList sectionList = new STFSectionList();
DPoint3d start = new DPoint3d(0, 0, 0);
while (catalogTypes != null)
catalogTypes.AsTFCatalogType.ImplementsInterface("StructuralFramingCommon", 0, out isStructuralCatalog);
catalogTypes.AsTFCatalogType.GetName(0, out catalogTypeName);
tfCatalog.AsTFCatalog.GetCatalogItemsByTypeName(catalogTypeName, 0, out catalogItemList);
while (catalogItemList != null)
placeStructuralMember(catalogItemList.AsTFCatalogItem, sectionList.AsSTFSection, start);
start.Y = start.Y + 1;
sectionList.GetNext("", out nextSection);
if (nextSection != null)
sectionList = nextSection;
catalogItemList.GetNext("", out catalogItemList);
start.X = start.X + 1;
start.Y = 0;
catalogTypes.GetNext("", out catalogTypes);