1181x
001825
2024-09-04

用于施工阶段分析的网络服务和应用程序编程接口

在计算常规结构时,数据输入往往并不复杂,但比较耗时。 自动化输入可以节省宝贵的时间。 本文介绍的任务是将房屋各楼层视为一个单独的施工阶段。 数据是使用 C#程序输入的,这样用户就不必手动输入单个楼层的元素。

要求

下面的程序运行的条件如下:

  • 楼层平面平行于 xy 平面。
  • 模型中不能包含任何跨楼层的单元(例如,跨两层的幕墙面)
  • 基础及上一层为零楼层。
  • 不考虑实体。
  • 仅使用平面。
  • 坐标轴 z 轴与重力加速度的方向一致(向下)。

理论背景

从上面的要求可以得出,只需要指定楼层高度,并且一个元素(例如节点)必须位于较低楼层高度以上的位置,到当前楼层高度的最大值等于或等于当前楼层高度。 [SCHOOL.INSTITUTION]

因此用户需要选择能够代表楼层高度的节点节点。 使用循环功能可以计算出 z 坐标,从而计算出楼层的高度。

下面将根据高度将楼板分配给所有节点。

对于线,可以使用节点的楼层。 如果一条线起始于天花板,终止于上方的天花板,则应归入上部天花板。 该线将被分配到在你的节点中可以找到的最高的楼层。

由于杆件位于线上,并且可以先于线进行分配,因此杆件与其线具有相同的楼层。

这同样适用于面。 选择相应节点最高的楼层后,

如果分配了楼层的所有元素,则可以从楼层列表中创建施工阶段。

比例

软件以 Dlubal.RFEMWebServiceLibrary NuGet 包中的一个模板为基础。 你可以在这里找到如何安装它:

https://github.com/Dlubal-Software/Dlubal_CSharp_Client

首先激活模型的连接如下:

  1. code.csharp#

...

  1. region 应用程序设置

尝试
{

  1. application_information
  2. 尝试
  3. {
  4. //连接到 RFEM6 或 RSTAB9 的应用程序
  5. application = new ApplicationClient(Binding, Address);
  1. }
  2. catch(Exception异常)
  3. {
  4. if (应用程序 != 零)
  5. {
  6. if (application.State != CommunicationState.Faulted)
  7. {
  8. application.Close();
  9. }
  10. 其他
  11. {
  12. application.Abort();
  13. }
  1. 应用程序=空;
  2. }
  3. }
  4. 最终
  5. {
  6. ApplicationInfo = application.get_information();
  7. Console.WriteLine("名称: {0},版本:{1},类型: {2}, 语言: {3} ", ApplicationInfo.name, ApplicationInfo.version, ApplicationInfo.type, ApplicationInfo.language_name);
  8. }
  9. #结束区域
  1. //获取活动模型
  2. string modelUrl = application.get_active_model();
  1. //连接到 RFEM6/RSTAB9 模型
  2. ModelClient model = new ModelClient(Binding, new EndpointAddress(modelUrl));

...

  1. /代码#

为了更好地处理错误,在整个源代码中的 main 函数中使用了 ry-catch 块。 在该块中,应用程序首先被连接,然后在 ry-catch 块中进行连接。 成功连接应用程序后,将通过 get_active_model 方法连接当前活动的模型(在 RFEM 6 中)。 如果出现任何问题,则外部的 ry-catch 块才会生效。

因为必须要分析所有的节点、线、杆件和面,所以从 RFEM 中获取所有的单元是有意义的。 要获得相应元素的编号,请先读出所有类别的对象编号。 以下是可以通过对象编号分别导入对象:

  1. code.csharp#

...
int[] node_nums = model.get_all_object_numbers(object_types.E_OBJECT_TYPE_NODE, 0);
int[] line_nums = model.get_all_object_numbers(object_types.E_OBJECT_TYPE_LINE, 0);
int[] member_nums = model.get_all_object_numbers(object_types.E_OBJECT_TYPE_MEMBER, 0);
int[] surface_nums = model.get_all_object_numbers(object_types.E_OBJECT_TYPE_SURFACE, 0);

//得到所有的节点
Console.WriteLine("1. 获取所有节点:");
节点[] nds = 新建节点[node_nums.Length];
for (int i = 0; i < node_nums.Length; ++i)
{
nds[i] = model.get_node(node_nums[i]);
if ((i%10)==0)
Console.Write("+");

}
Console.WriteLine("");
...

  1. /代码#

在控制台中每隔 10 个单元旁会标注一个“+”号,以便让用户清楚地了解过程所需的时间。

在导入其他元素之前,需要先确定楼层高度。 首先,您必须读出所选对象。 调用的数组(字段/向量包含元素)的类型为object_location,包含了所有选定的对象及其类型和编号。 用户可以不勾选该节点,将节点过滤掉。 因为所有节点都已经可用,所以可以在同一个循环中确定这些节点的z坐标。 程序会循环选择所选对象,并为选定的节点类型提供节点, 每找到一个坐标点,数组就扩展一个元素:

  1. code.csharp#

...
Console.WriteLine("2. 获取选择的节点");
//获取所有被选择的对象
object_location[] obj_locs = model.get_all_selected_objects();

//得到所有选择的节点编号
double[] floor_heights = new double[1];
foreach(obj_location中的object_location obj)
{
if (obj.type == object_types.E_OBJECT_TYPE_NODE)
{
for (int i = 0; i < nds.Length; ++i)
{
if (nds[i].no == obj.no)
{
floor_heights[floor_heights.Length - 1] = nds[i].coordinate_3;
Array.Resize(ref floor_heights, floor_heights.Length + 1);
打断;
}
}
}
}
Array.Resize(ref floor_heights, floor_heights.Length - 1);

//排序数组
//z轴为负,最大的正值为地面
Array.Sort(floor_heights);
Array.Rverse(floor_heights);
//第一层和第一层是一个,删除第一个条目
double[] tmp_arr = new double[floor_heights.Length - 1];
Array.Copy(floor_heights, 1, tmp_arr, 0, floor_heights.Length - 1);

floor_heights = 0;
floor_heights = tmp_arr;
...

  1. /代码#

因为 z 坐标的顺序是错误的,所以首先按大小对数组进行排序。 但是z坐标是负方向,因此必须使用反转来反转排序。 最初的定义为基础和二楼为同一层;因此,层高中的第一个元素被删除。

接下来将传递其余的单元,例如线、杆件和面:

  1. code.csharp#

...
//得到所有的线
Console.WriteLine("3. 获取所有线:");
line[] lns = new line[line_nums.Length];
for (int i = 0; i < line_nums.Length; ++i)
{
lns[i] = model.get_line(line_nums[i]);
如果 ((i % 10) == 0)
Console.Write("+");
}
Console.WriteLine("");

//获取所有杆件
Console.WriteLine("4. 获取所有杆件:");
杆件[] mems = 新杆件[member_nums.Length];
for (int i = 0; i < member_nums.Length; ++i)
{
mems[i] = model.get_member(member_nums[i]);
如果 ((i % 10) == 0)
Console.Write("+");
}
Console.WriteLine("");

//得到所有的面
Console.WriteLine("5. 获取所有面:");
面[] srfs = 新建面[surface_nums.Length];
for (int i = 0; i < surface_nums.Length; ++i)
{
srfs[i] = model.get_surface(surface_nums[i]);
如果 ((i % 10) == 0)
Console.Write("+");
}
Console.WriteLine("");
...

  1. /代码#

首先需要创建二维列表, 在 nds_floor_numbers 列表中,楼层是第一维,楼层的节点编号是第二维。 首先,下面的循环遍历所有节点,还有一个子循环遍历所有楼层高度。 对于每个节点,程序从建筑物底部到顶部检查 Z 坐标是否位于楼层高度内。 由于数值不准确,程序中给出的数值减去1 mm的公差:

  1. code.csharp#

...
//循环通过节点并设置它们的地板
Console.WriteLine("6. 循环通过节点并获取它们的楼层");
for (int i = 0; i < nds.Length; ++i)
{
for (int j = 0; j < floor_heights.Length; ++j)
{
if (nds[i].coordinate_3 >= floor_heights[j] - 0.001)
{
nds[i].comment = j.ToString();
Console.WriteLine("node " + nds[i] + " floor " + j + ";" + nds[i].coordinate_3 + ";" + (floor_heights[j] - 0.001));
nds_floor_numbers[j].Add(nds[i].no);
model.set_node(nds[i]);
打断;
}
}
}
...

  1. /代码#

只要一个节点位于指定区域内,楼层编号就会被输入作为注释,然后该节点编号就会被添加到列表中。 这时,注释可以继续传递给 RFEM(注释掉)。 注释是因为下面要计算的是楼层编号,而不是 z 坐标。

当在线上查看循环时,这一点很明显:

  1. code.csharp#

...
//循环访问线,获取线的节点并设置线的楼层
Console.WriteLine("7. 循环线并得到它们的地板");
for (int i = 0; i < lns.Length; ++i)
{
//得到线的节点
int[] ln_node_nums = lns[i].definition_nodes;
Int32 floor_max = 0;
//循环通过线的节点
for (int j = 0; j SMALLERTHAN ln_node_nums.Length; ++j)
{
//循环通过节点
for (int l = 0; l SMALLERTHAN nds.Length; ++l)
{
if (nds[l].no == ln_node_nums[j])
{
Int32 floor = Int32. Parse(nds[l].comment);
if (floor > floor_max)
{
floor_max =楼板;
打断;
}
}
}

}
//输入线的最大楼层
lns[i].comment = floor_max.ToString();
lns_floor_numbers[floor_max].Add(lns[i].no);
model.set_line(lns[i]);

}
...

  1. /代码#

小环通过线的所有节点, 在这个子循环中,还有另一个循环通过所有节点查找在线上与节点编号匹配的节点。 该节点的楼层编号取自注释,

正如在理论基础中已经提到的,确定最高楼层的编号就足够了。 该编号将被保存为该线的备注中的楼层编号,该编号将被添加到列表中。

杆件的楼层编号与其所在线的楼层编号相同。 因此,需要一个覆盖所有杆件的大环,以及覆盖所有线的子环。 一旦线编号与杆件的编号相匹配,杆件将获取其楼层高度的注释,并将该编号添加到列表中:

  1. code.csharp#

...
//循环通过杆件,得到他们的线并设置他们的地板
Console.WriteLine("8. 循环遍历杆件并获取其楼层");
for (int i = 0; i < mems.Length; ++i)
{
//获取杆件的线编号
int mem_ln_num = mems[i].line;

//循环线
for (int j = 0; j < lns.Length; ++j)
{
if (lns[j].no == mem_ln_num)
{
mems[i].comment = lns[j].comment;
mems_floor_numbers[Int32.Parse(lns[j].comment)].Add(mems[i].no);
打断;
}
}

}
//循环通过面,得到它们的线并设置它们的地板
Console.WriteLine("9. 循环通过面并获取它们的地板");
for (int i = 0; i < srfs.Length; ++i)
{
//得到面的线
int[] srf_line_nums = srfs[i].boundary_lines;
Int32 floor_max = 0;
//循环通过面的线
for (int j = 0; j < srf_line_nums.Length; ++j)
{
//循环线
for (int l = 0; l SMALLERTHAN lns.Length; ++l)
{
if (lns[l].no == srf_line_nums[j])
{
Int32 floor = Int32.Parse(lns[l].comment);
if (floor > floor_max)
{
floor_max =楼板;
打断;
}
}
}

}
//输入面的最大楼层
srfs[i].comment = floor_max.ToString();
srfs_floor_numbers[floor_max].Add(srfs[i].no);

model.set_surface(srfs[i]);

}
...

  1. /代码#

使用方法与线相似。 面上方为子环,子环位于面的边界线上。 从边界线开始最高的楼层成为面的楼层编号。

在将所有元素分类到楼层中后,接下来要创建施工阶段。 每层都创建一个施工阶段,因此计算出的循环箭头如下:

  1. code.csharp#

...
Console.WriteLine("10. 设置施工阶段");
尝试
{
model.begin_modification("设置施工阶段");
//创建施工阶段
for (int i = 0; i < floor_heights.Length; ++i)
{
construction_stage cstg = new construction_stage();

cstg.编号 = i + 1;
cstg.continue_on_construction_stage = i;
cstg.continue_on_construction_specified = true;

cstg.are_members_enabled_to_modify = true;
cstg.are_members_enabled_to_modifySpecified = true;
cstg.added_members = mems_floor_numbers[i].ToArray();
cstg.active_members = cstg.added_members;

cstg.are_surfaces_enabled_to_modify = true;
cstg.are_surfaces_enabled_to_modifySpecified = true;
cstg.added_surfaces = srfs_floor_numbers[i].ToArray();
cstg.active_surfaces = cstg.added_surfaces;

cstg.name = "楼板 " + i;
cstg.user_defined_name_enabled = true;
cstg.user_defined_name_enabledSpecified = true;

model.set_construction_stage(cstg);

}
}
catch(Exception异常)
{
model.cancel_modification();
Console.WriteLine("创建几何图形时发生错误" + exception.Message);
抛出;
}
最终
{
尝试
{
model.finish_modification();
}
catch(Exception异常)
{
Console.WriteLine("当几何图形创建完成时发生错误" + exception.Message);
抛出;
}
}
...

  1. /代码#

在 RFEM 中创建单元时,额外使用 begin_modification/finish_modification 块,以便最大限度地提高传输速度。 如果出现问题,附加的 ry-catch 块会提供保护,在中断的情况下调用 cancel_modification,从而正确终止处理。

关于迁移需要注意的是,要迁移的单元(例如 continue_on_on_construction_stage)只有在相应的“特定”属性为“真”时 (continue_on_construction_stageSpecified)才会被迁移。 不是所有的单元都有这种 "特定的" 属性,但是如果有这种属性,那么必须加以考虑。

概述总结

通过网络服务和应用程序编程接口的多功能性,可以使一些复杂的手动输入工作变得自动化。 在本示例中,“施工阶段分析”模块的输入是自动进行的, 在这里您可以尽情发挥创意,寻找省时的解决方案,下面将介绍更多的示例。


作者

Günthel 先生为Dlubal 软件客户提供技术支持。

下载


;