1022x
001825
2023-08-09

Веб-сервис и API для расчёта стадий строительства

При расчёте обычных конструкций, ввод данных зачастую не сложен, но занимает много времени. Экономьте своё драгоценное время с помощью автоматизированного ввода данных. В данном случае стоит задача рассмотреть этажи дома как отдельные стадии строительства. Ввод данных должен осуществляться с помощью программы на C #, чтобы пользователю не приходилось вводить элементы отдельных этажей вручную.

Предпосылка

Следующая программа работает при следующих условиях:

  • Плоскости этажа параллельны плоскости xy.
  • Модель не должна содержать элементов, занимающих несколько этажей (например, поверхность фасада, занимающая два или более этажа).
  • Фундамент и цокольный этаж относятся к нулевому этажу,
  • Тела не учитываются.
  • Используются только плоские поверхности.
  • Ось z направлена в направлении ускорения свободного падения (вниз).

Теоретические основы

Согласно требованиям ' ясно, что должна быть указана только высота этажа, при этом элемент, например узел, координата z которого находится выше высоты нижнего этажа и не превышает соответствующую высоту этажа.
Потому пользователь должен выбрать последовательность узлов, репрезентативных для высоты этажа. Координаты z и, следовательно, высоты этажа можно задать с помощью цикла.
Далее с помощью высот присваиваются всем узлам этажи.
Для линий можно вернуться к этажам узлов. Если линия начинается на потолке и заканчивается на потолке, который находится выше, то она должна быть придана верхнему потолку. Таким образом, линия присваивается самому высокому этажу, который можно найти в ваших узлах.
Поскольку стержни лежат на линиях и их можно присвоить заранее, стержень имеет то же перекрытие, что и его линия.
То же самое относится к поверхностям. Определяется самый высокий этаж соответствующих узлов.
После придания всех элементов этажа, стадии строительства можно создать прямо из списка этажей.

Интегратор

В качестве основы программа использует шаблон из пакета Dlubal.RFEMWebServiceLibrary NuGet. Здесь вы можете узнать, как его установить:

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

Сначала активная модель подключается следующим образом:


            

...
#region Application Settings
try
{
    application_information ApplicationInfo;
    try
    {
        // connects to RFEM6 or RSTAB9 application
        application = new ApplicationClient(Binding, Address);

    }
    catch (Exception exception)
    {
        if (application != null)
        {
            if (application.State != CommunicationState.Faulted)
            {
                application.Close();
            }
            else
            {
                application.Abort();
            }

            application = null;
        }
    }
    finally
    {
        ApplicationInfo = application.get_information();
        Console.WriteLine("Name: {0}, Version:{1}, Type: {2}, language: {3} ", ApplicationInfo.name, ApplicationInfo.version, ApplicationInfo.type, ApplicationInfo.language_name);
    }
    #endregion

    // get active model
    string modelUrl = application.get_active_model();

    // connects to RFEM6/RSTAB9 model
    ModelClient model = new ModelClient(Binding, new EndpointAddress(modelUrl));
...


Для лучшей обработки ошибок, в исходном коде используется блок try-catch. Внутри этого блока приложение сначала подключается, что также выполняется в блоке try-catch. После успешного подключения приложения, текущая активная модель (на переднем плане в RFEM 6) подключается с помощью метода get_active_model. Если возникают какие-либо проблемы, вступает в силу внешний блок try-catch.
Поскольку необходимо рассчитать все узлы, линии, стержни и поверхности, имеет смысл взять все элементы из программы RFEM. Чтобы получить количество соответствующих элементов, сначала считываются номера объектов всех категорий. Далее соответствующие объекты могут быть переданы с помощью их номеров:


            

...
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[] surface_nums = model.get_all_object_numbers(object_types.E_OBJECT_TYPE_SURFACE, 0);

//  get all nodes
Console.WriteLine("1. Get all nodes:");
node[] nds = new node[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("");
...


Для того, чтобы пользователь мог получить представление о продолжительности процесса, в консоли записывается «+» после каждых 10 элементов.
Перед передачей других элементов, в следующем шаге задаются высоты этажа. Сначала необходимо считать выбранные объекты. Переданный массив (поле/вектор, включая элементы) имеет тип объект_локация и содержит все выбранные объекты с их типом и количеством. Таким образом, узлы можно отфильтровать в цикле. Поскольку все узлы уже доступны, можно определить z-координаты этих узлов в том же цикле. Выбранные объекты циклически просматриваются, и, как только элемент относится к типу узлов, выполняется поиск данного узла среди всех остальных узлов, а затем его координата z вводится в массив surface_heights. Для каждой найденной координаты массив будет расширен элементом:


            

...
Console.WriteLine("2. Get selected nodes");
//  get all selected objects
object_location[] obj_locs = model.get_all_selected_objects();

//  get all selected node numbers
double[] floor_heights = new double[1];
foreach (object_location obj in obj_locs)
{
	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);
				break;
			}
		}
	}
}
Array.Resize(ref floor_heights, floor_heights.Length - 1);

//  sort array
//  z-axis is negative, most positive value is ground
Array.Sort(floor_heights);
Array.Reverse(floor_heights);
//  ground and first level are one, remove first entry
double[] tmp_arr = new double[floor_heights.Length - 1];
Array.Copy(floor_heights, 1, tmp_arr, 0, floor_heights.Length - 1);

floor_heights = null;
floor_heights = tmp_arr;
...


Поскольку координаты z расположены не в правильном порядке, то массив сначала сортируется по размеру. Однако координата z находится в отрицательном направлении, и поэтому сортировку нужно обратить с помощью функции Обратный. Изначально было задано, что фундамент и цокольный этаж составляют один этаж, поэтому в высоте этажа был удален первый элемент.
Затем будут переданы оставшиеся элементы, такие как линии, стержни и поверхности:


            

...
//  get all lines
Console.WriteLine("3. Get all lines:");
line[] lns = new line[line_nums.Length];
for (int i = 0; i < line_nums.Length; ++i)
{
	lns[i] = model.get_line(line_nums[i]);
	if ((i % 10) == 0)
		Console.Write("+");
}
Console.WriteLine("");


//  get all members
Console.WriteLine("4. Get all members:");
member[] mems = new member[member_nums.Length];
for (int i = 0; i < member_nums.Length; ++i)
{
	mems[i] = model.get_member(member_nums[i]);
	if ((i % 10) == 0)
		Console.Write("+");
}
Console.WriteLine("");

//  get all surfaces
Console.WriteLine("5. Get all surfaces:");
surface[] srfs = new surface[surface_nums.Length];
for (int i = 0; i < surface_nums.Length; ++i)
{
	srfs[i] = model.get_surface(surface_nums[i]);
	if ((i % 10) == 0)
		Console.Write("+");
}
Console.WriteLine("");
...


Чтобы отсортировать элементы по отдельным этажам, сначала создаются двумерные списки. В списке nds_этаж_numbers в качестве первого измерения указаны этажи, а во втором - номера узлов этажа. Прежде всего, следующий цикл проходит по всем узлам и имеет подчиненный цикл, который проходит по всем высотам этажа. Таким образом, для каждого узла здания снизу вверх проверяется, лежит ли координата Z в пределах высоты этажа. Из-за численных неточностей был вычтен допуск 1 мм:


            

...
//  loop through nodes and set their floor
Console.WriteLine("6. Loop through nodes and get their floor");
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]);
			break;
		}
	}
}
...


Как только узел лежит в указанной области, номер этажа вводится в качестве комментария к нему, а номер узла добавляется в список. На данном этапе мы можем перенести также данный комментарий в программу RFEM (т.е. закомментировать его). Причина, по которой используется комментарий, заключается в том, что в дальнейшем будут оцениваться не координаты z, а номер этажа. Это очевидно, если посмотреть на цикл по линиям:


            

...
//  loop through lines, get their nodes and set their floor
Console.WriteLine("7. Loop through lines and get their floor");
for (int i = 0; i < lns.Length; ++i)
{
	//  get nodes of line
	int[] ln_node_nums = lns[i].definition_nodes;
	Int32 floor_max = 0;
	//  loop through nodes of line
	for (int j = 0; j SMALLERTHAN ln_node_nums.Length; ++j)
	{
		//  loop through nodes
		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 = floor;
					break;
				}
			}
		}

	}
	
	lns[i].comment = floor_max.ToString();
	lns_floor_numbers[floor_max].Add(lns[i].no);
	//model.set_line(lns[i]);

}
...


Данный цикл проходит по всем линиям и имеет подчиненный цикл, который проходит через все узлы линии. Внутри этого подцикла есть другой цикл, проходящий по всем узлам и находящийся на линии с соответствующим номером. Из этого узла считывается номер этажа из комментария. Как уже упоминалось в теоретических основах, достаточно задать самый высокий номер этажа. Данный номер затем сохраняется как номер этажа в комментарии линии, а номер линии вставляется в список.
Стержням присваиваются те же номера этажей, что и линиям, на которых они лежат. Таким образом, требуется цикл по всем стержням с частичным циклом по всем линиям. Как только номер линии будет соответствовать номеру стержня, стержень получит в качестве комментария высоту этажа, а номер будет добавлен в список:


            

...
//  loop through members, get their line and set their floor
Console.WriteLine("8. Loop through members and get their floor");
for (int i = 0; i < mems.Length; ++i)
{
	//  get line number of member
	int mem_ln_num = mems[i].line;

	//  loop through lines
	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);
			break;
		}
	}

}
//  loop through surfaces, get their lines and set their floor
Console.WriteLine("9. Loop through surfaces and get their floor");
for (int i = 0; i < srfs.Length; ++i)
{
	//  get lines of surface
	int[] srf_line_nums = srfs[i].boundary_lines;
	Int32 floor_max = 0;
	//  loop through lines of surface
	for (int j = 0; j < srf_line_nums.Length; ++j)
	{
		//  loop through lines
		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 = floor;
					break;
				}
			}
		}

	}
	//  enter maxiumum floor in surface
	srfs[i].comment = floor_max.ToString();
	srfs_floor_numbers[floor_max].Add(srfs[i].no);

	//model.set_surface(srfs[i]);

}
...


Процедура для поверхностей аналогична для линий. Существует цикл по поверхностям с суб-контуром по их граничным линиям. Самый высокий этаж от граничной линии становится номером этажа поверхности.
После сортировки всех элементов по этажам, необходимо создать стадии строительства. Для каждого этажа создается стадия строительства, поэтому цикл выполняется по высоте этажа:


            

...
Console.WriteLine("10. Set construction stages");
try
{
	model.begin_modification("set construction stages");
	//  create construction stages
	for (int i = 0; i < floor_heights.Length; ++i)
	{
		construction_stage cstg = new construction_stage();

		cstg.no = i + 1;
		cstg.continue_on_construction_stage = i;
		cstg.continue_on_construction_stageSpecified = 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 = "floor " + i;
		cstg.user_defined_name_enabled = true;
		cstg.user_defined_name_enabledSpecified = true;

		model.set_construction_stage(cstg);

	}
}
catch (Exception exception)
{
	model.cancel_modification();
	Console.WriteLine("Something happen when creation of geometry" + exception.Message);
	throw;
}
finally
{
	try
	{
		model.finish_modification();
	}
	catch (Exception exception)
	{
		Console.WriteLine("Something happen when finishing creation of geometry" + exception.Message);
		throw;
	}
}
...


Für das Anlegen von Elementen in RFEM wird zusätzlich ein begin_modification/finish_modification Block genutzt, um die Übertragungsgeschwindigkeit zu maximieren. В случае возникновения проблем затем обеспечивает защиту дополнительный блок try-catch, который в случае разрыва вызывает функцию отмены, тем самым правильно завершая обработку. Важным примечанием относительно переноса является то, что подлежащие передаче элементы, такие как продолжить_на_construction_stage, могут быть переданы только в том случае, если соответствующее свойство «Заданный» было установлено на «true» (continue_on_construction_stageStecification). Не все элементы имеют такое свойство «Заданное», но там, где оно доступно, его необходимо учитывать.

Заключение

Благодаря универсальности интерфейса веб-сервис и API, можно автоматизировать ряд данных, которые при ручном вводе данных заняли бы много времени. В нашем примере автоматизирован ввод данных для аддона Расчёт стадий строительства, который также служит в качестве основы для многих других аддонов и опций. Таким образом, у вас есть лишь некоторые ограничения для вашей креативности в процессе поиска экономичных решений, и мы покажем и другие примеры.


Автор

Г-н Гюнтель осуществляет техническую поддержку пользователей Dlubal Software.

Скачивания