Руководство разработчика
Настоящее руководство посвящено разработке под российскую САПР архитектурно-инженерного назначения Renga (https://rengabim.com). У программы имеется SDK и справка к нему по API https://help.rengabim.com/api, но во-первых, она на английском языке, во-вторых не изобилует подробностями работы со многими объектами, и, самое важное, никак не затрагивает тему багов и ограничений в работе имеющихся методов.
В данном руководстве будут приводиться примеры, преимущественно, на C#, но также будут содержаться положения и для разработки на иных языках - Python, C++. Исходные материалы настоящего руководства расположены в https://github.com/GeorgGrebenyuk/acadDevDocsRu/tree/main/docs/renga/com.
Общие сведения
В данном разделе описывается принцип взаимодействия с приложением Renga и его объектами при помощи COM API.
О Renga COM API
Единственный вариант программного взаимодействия с Renga - это COM API; работать с COM могут различные языки программирования с динамической типизацией (C#, C++, Python, JavaScript и пр.)
Текущая версия COM API существует где-то с 2018 года, до этого у Renga было C++ API (вроде бы). Поэтому все номера редакций API начинаются с цифры "2".
Примечание: Сама по себе технология COM API является Windows-специфичной, то есть потенциальная версия Renga под иные операционные системы будет подразумевать отсутствие API или его существенное изменение его технологии.
Пользовательские приложения могут взаимодействовать с Renga двумя способами:
- в форме загруженного плагина, размещенного в папке приложения и загруженного при запуске программы;
- из стороннего процесса благодаря COM-технологии.
Несмотря на одинаковую технологию (COM API) пользовательские приложения, загруженные в Renga, будут показывать лучшую производительность, чем работающие с ней из стороннего процесса.
О Renga SDK
В составе Renga SDK поставляются необходимые для разработки компоненты:
- библиотека типов COM в формате
tlb(type library) в\tlb\RengaCOMAPI.tlb; - подключаемая вспомогательная библиотека на .NET в двух редакциях - для сборки под .NET Framework 4.8 и .NET 8.0 (с версии API 2.37 или Renga 8.3);
- подключаемые вспомогательные заголовочные файлы на C++ из
C++\Include\Renga; Также имеется справка, аналогичная приведенной на сайте. Справка собирается через Doxygen.
Примеры в SDK приводятся для C#, C++ одинаково и в значительно меньшей части для Python.
Все версии SDK имеют одинаковую структуру, она описывается в корневом файле ReadMeFirst.txt.
Об изменениях в SDK
Скажем честно, официальный Changelog (раздел справки, где должны писаться изменения) содержит далеко не все фактические изменения и обновления в API. Разработчик может столкнуться с неприятными последствиями недокументированных обновлений при разработке приложений.
Сценарий самостоятельного анализа SDK будет выглядеть следующим образом:
Для Renga.NET.PluginUtility.dll
- Создаём reference-версию библиотеки Renga.NET.PluginUtility.dll с помощью, например, утилиты JetBrains Refasmer ;
- Через любой декомпилятор, например, dnSpy экспортируем созданную reference-библиотеку в набор исходников;
- Загоняем исходники в любую систему контроля версий и сравниванием обновления с ранним SDK; Для C++ пункты 1 и 2 не нужны, так как в SDK они уже в виде "текстовых" файлов.
Для RengaCOMAPI.tlb
- С помощью утилиты
oleview.exeиз состава Windows SDK для C++ или аналога создаём IDL-файл, описывающие данную библиотеку типов; - По аналогии с предыдущим пунктом публикуем данный текстовый IDL-файл в систему контроля версий и сравниванием содержимое для другой версии библиотеки типов;
У автора нет возможности это делать самостоятельно, поэтому прикладываю ссылки на разные архивные версии Renga SDK, список будет пополняться
Подключение библиотек
Для разработки загружаемого приложения или для приложения, взаимодействующего с процессом Renga, создаваемого на языках программирования C# или C++ необходимо импортировать в проект библиотеку типов Renga. Это можно сделать несколькими способами:
C#
COMFileReference
В ваш csproj файл занесите инструкцию
<ItemGroup>
<COMFileReference Include="$(SolutionDir)external\RengaCOMAPI.tlb"></COMFileReference>
</ItemGroup>
где $(SomePath) - ваш путь к файлу tlb из Renga SDK.
Такой способ подключения не требует, чтобы Renga была установлена на вашем ПК
ComReference
В ваш csproj файл занесите инструкцию
<ItemGroup>
<COMReference Include="Renga">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>0</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>0ec5d324-8b9f-4d30-84ed-ab711618d1c1</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
</ItemGroup>
Этот вариант требует, чтобы на ПК была установлена Renga и зарегистрирована в системе её библиотека типов. Кроме того, библиотека типов устанавливается в единственном экземпляре, затирая другую библиотеку (если у вас несколько версий Renga на ПК).
Interop.Renga.dll
Подключите к проекту csproj библиотеку типов Interop.Renga.dll, которая формируется автоматически при сборке приложения в obj-папке при подключении библиотеки типов одним из способов выше.
<ItemGroup>
<Reference Include="Interop.Renga.dll">
<HintPath>$(SomePath)Interop.Renga.dll</HintPath>
<Private>True</Private>
<EmbedInteropTypes>False</EmbedInteropTypes>
</Reference>
</ItemGroup>
где $(SomePath) - путь к этой библиотеке
Такой путь фактически аналогичен первому, где идёт подключение к tlb. Некоторые авторы плагинов, например, Awada или ModPlus использует такой сценарий, в ModPlus и вовсе имеется возможность подключаться к конкретной версии Renga, если их установлено на ПК несколько.
C++
import tlb
- В свойствах
vcxprojпроекта вAdditionalIncludeDirectoriesдобавьте путь к папке, содержащей файлRengaCOMAPI.tlb. - В основном заголовочном файле приложения (если используются precompilated-headers в нем, если нет -- то в каком-то основном) напишите инструкцию
#import <RengaCOMAPI.tlb>
Примечание: данная конструкция сработает только для языка программирования Visual C++ (версия языка от Microsoft). Обычный C++ "не знает" такой команды, для него см. подключение ниже.
RengaCOMAPI tlh и tli
При подключении библиотеки типов способом выше в промежуточной папке проекта создаются файлы RengaCOMAPI.tli, RengaCOMAPI.tlh.
Подключите их в свой проект.
Ниже пример подключения для случая Qt в файле pro
HEADERS += \
rengacomapi.tlh
DISTFILES += \
rengacomapi.tlh
tlh файл (объявление функций) в конце сдержит инструкцию импорта tli-файла (реализация функций) с абсолютным путем. При размещении его у себя в проекте обязательно отредактируйте этот путь!
Python и прочие ЯП
Подключать что-либо нет необходимости, вы просто будете использовать динамическую типизацию объектов и методы согласно справке. О принципе подключения к приложению Renga см. статью Подключение к приложению Renga.
Подключение к приложению Renga
Получение приложение из загруженного плагина
Для внутренних приложений, загружаемых в Renga в виде плагинов, вопрос получения COM-интерфейса, описывающего приложение Renga не стоит - просто вызывается соответствующий метод: На C#:
Renga.Application rengaApp = new Renga.Application();
На C++:
Renga::IApplicationPtr rengaApp = Renga::CreateApplication();
Получение приложения из внешнего процесса
Сложнее обстоит вопрос с доступом к приложению Renga из стороннего процесса. Так или иначе, способы будут завязаны на COM-методы, так как само API реализовано на COM-технологии. Есть 2 сценария -- создать новый процесс Renga и подключиться к текущему процессу.
C++
Для запуска нового процесса Renga создайте экземпляр COM-оболочки приложения, выполните с ней действия и закройте приложение. Листинг далее со странички официальной документации.
CoInitialize(nullptr);
auto renga = Renga::CreateApplication(CLSCTX_LOCAL_SERVER);
renga->PutVisible(VARIANT_TRUE);
renga->OpenProject(bstr_t(argv[1]));
// use Renga someway
renga->CloseProject(VARIANT_TRUE);
// Quit explicitly:
renga->Quit();
CoUninitialize();
Как правило, пользовательские приложения на C++ существуют только в виде плагинов, для них не рационально делать логику работы с COM из стороннего процесса. Автору во всяком случае неизвестны плагины к Renga, написанные на C++ и обращающиеся к ней извне (возможно, только крупные СОД). Тем более, что работа с COM в C++ мягко говоря плохая и очень сильно отдает "legacy" . Автор не использовал в своей практике подобных обращений, если вам надо -- вы можете попросить ИИ-агента помочь с этой задачей, автор не имеет желания пробовать это сам и писать здесь километровые листинги 😬.
C#
Marshal.GetActiveObject
Наиболее простая реализация на C# (фактически, на .NET) - обратиться к методу Marshal.GetActiveObject из пространства имён System.Runtime.InteropServices и передать ему в аргумент идентификатор Renga-приложения Renga.Application.1. Если приложение не запущено, то оно будет создано
Примечание: начиная с .NET 5+ эта функциональность удалена из .NET, вместо этого можете воспользоваться вызовами нативного API через DllImport
//From https://stackoverflow.com/a/65496277
public static class Marshal2
{
internal const String OLEAUT32 = "oleaut32.dll";
internal const String OLE32 = "ole32.dll";
[System.Security.SecurityCritical] // auto-generated_required
public static Object GetActiveObject(String progID)
{
Object obj = null;
Guid clsid;
// Call CLSIDFromProgIDEx first then fall back on CLSIDFromProgID if
// CLSIDFromProgIDEx doesn't exist.
try
{
CLSIDFromProgIDEx(progID, out clsid);
}
// catch
catch (System.Exception)
{
CLSIDFromProgID(progID, out clsid);
}
GetActiveObject(ref clsid, IntPtr.Zero, out obj);
return obj;
}
//[DllImport(Microsoft.Win32.Win32Native.OLE32, PreserveSig = false)]
[DllImport(OLE32, PreserveSig = false)]
[System.Runtime.Versioning.ResourceExposure(System.Runtime.Versioning.ResourceScope.None)]
[System.Security.SuppressUnmanagedCodeSecurity]
[System.Security.SecurityCritical] // auto-generated
private static extern void CLSIDFromProgIDEx([MarshalAs(UnmanagedType.LPWStr)] String progId, out Guid clsid);
//[DllImport(Microsoft.Win32.Win32Native.OLE32, PreserveSig = false)]
[DllImport(OLE32, PreserveSig = false)]
[System.Runtime.Versioning.ResourceExposure(System.Runtime.Versioning.ResourceScope.None)]
[System.Security.SuppressUnmanagedCodeSecurity]
[System.Security.SecurityCritical] // auto-generated
private static extern void CLSIDFromProgID([MarshalAs(UnmanagedType.LPWStr)] String progId, out Guid clsid);
//[DllImport(Microsoft.Win32.Win32Native.OLEAUT32, PreserveSig = false)]
[DllImport(OLEAUT32, PreserveSig = false)]
[System.Runtime.Versioning.ResourceExposure(System.Runtime.Versioning.ResourceScope.None)]
[System.Security.SuppressUnmanagedCodeSecurity]
[System.Security.SecurityCritical] // auto-generated
private static extern void GetActiveObject(ref Guid rclsid, IntPtr reserved, [MarshalAs(UnmanagedType.Interface)] out Object ppunk);
[DllImport("ole32.dll")]
internal static extern void GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);
public static List<string> GetAppMonikers(string appName)
{
IRunningObjectTable rot;
GetRunningObjectTable(0, out rot);
IEnumMoniker monikerEnumerator = null;
rot.EnumRunning(out monikerEnumerator);
if (monikerEnumerator == null)
return null;
monikerEnumerator.Reset();
var registries = new List<IMoniker>();
var registries2 = new List<string>();
IntPtr pNumFetched = new IntPtr();
IMoniker[] monikers = new IMoniker[1];
while (monikerEnumerator.Next(1, monikers, pNumFetched) == 0)
{
IBindCtx bindCtx;
CreateBindCtx(0, out bindCtx);
if (bindCtx == null)
continue;
string displayName;
monikers[0].GetDisplayName(bindCtx, null, out displayName);
//registries2.Add(displayName);
if (displayName.Contains(appName)) registries.Add(monikers[0]);
}
return registries2;
}
}
После прекращения работы с приложением Renga извне, если оно более не нужно, закройте его и освободите COM-объект приложения (далее renga) с помощью стандартного метода:
System.Runtime.InteropServices.Marshal.ReleaseComObject(renga);
Running Object Table
Официальная справка предлагает также обратить внимание на Windows-специфичную технологию "Running Object Table". Переиначивая примеры со справки конструкция, позволяющая получить все запущенные в системе процессы Renga будет выглядеть так:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
public static Renga.IApplication[] GetRengaApps()
{
IRunningObjectTable rot;
GetRunningObjectTable(0, out rot);
List<Renga.IApplication> tmpApps = new List<Renga.IApplication>();
var rengaMonikers = GetRengaMonikers();
foreach (var moniker in rengaMonikers)
{
object comObject;
// Get first Renga moniker in list
rot.GetObject(moniker, out comObject);
Renga.IApplication rengaApp = comObject as Renga.IApplication;
if (rengaApp != null) tmpApps.Add(rengaApp);
}
return tmpApps.ToArray();
}
[DllImport("ole32.dll")]
private static extern void GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);
private static List<IMoniker> GetRengaMonikers()
{
IRunningObjectTable rot;
GetRunningObjectTable(0, out rot);
IEnumMoniker monikerEnumerator = null;
rot.EnumRunning(out monikerEnumerator);
if (monikerEnumerator == null)
return null;
monikerEnumerator.Reset();
var registries = new List<IMoniker>();
IntPtr pNumFetched = new IntPtr();
IMoniker[] monikers = new IMoniker[1];
while (monikerEnumerator.Next(1, monikers, pNumFetched) == 0)
{
IBindCtx bindCtx;
CreateBindCtx(0, out bindCtx);
if (bindCtx == null)
continue;
string displayName;
monikers[0].GetDisplayName(bindCtx, null, out displayName);
if (displayName.Contains("!Renga"))
registries.Add(monikers[0]);
}
return registries;
}
Pyhton
Необходимо установить вспомогательный пакет pywin32
import win32com.client
rengaApp = win32com.client.GetActiveObject("Renga.Application.1")
if rengaApp is not None:
print("Application received successfully!")
Powershell
Ниже пример, как создать новый процесс Renga, вывести в консоль номер версии программы и закрыть приложение.
# --- Вспомогательная функция для освобождения ресрусов от COM-объекта
function Release-ComObject([object]$obj) {
if ($null -ne $obj -and $obj -is [System.__ComObject]) {
[void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($obj)
}
}
# Создадим экземпляр приложения Renga
$rengaApp = $null
try {
$rengaApp = New-Object -ComObject "Renga.Application.1" -ErrorAction Stop
} catch {
Write-Warning "Не удалось создать COM-объект Renga.Application.1. Если Renga не зарегистрирована как COM-сервер, выполните из папки установки: RengaProfessional.exe /regserver"
Read-Host "Нажмите Enter для выхода"
exit
}
# Делаем приложение видимым
$rengaApp.Visible = $true
# Выполняем некоторые действия, например, получаем информацию о версии приложения
Write-Host $rengaApp.VersionS
try { $rengaApp.Quit() } catch {}
Release-ComObject $rengaApp
Примеры приложений и курсы
К сожалению, единой базы всех пользовательских плагинов и скриптов нет. Ниже предлагается перечень ссылок на материалы и пользовательские реализации плагинов и скриптов, актуальных на настоящую дату -- март 2026 года.
Курсы и методические материалы
Видеокурс от лета 2022 г. "Renga: Инструменты автоматизации API и Dynamo". На текущий момент сильно устарел, но для начала можно ориентироваться.
Официальные справка по API и SDK. Также автор прикладывает ссылки на ранние версии SDK.
Блог Renga на Habr, статьи по API:
- API BIM-системы Renga (декабрь 2017);
- Непоследний обзор Renga API (апрель 2020);
Блог Renga на официальном сайте, статьи по API.
Пользовательские блоги и каналы:
- TODO
Разработки с открытым исходным кодом
C++
- ModelExplorer - обозреватель модели от команды разработки Renga;
C#
- Renga Bri4ka - набор различных плагинов;
- VinnyRengaAdapter - экспорт объектов в обменные форматы;
- RengaInspector - оконный обозреватель проекта и объектов (свойств и методов по API); TODO
Ограничения API
В случае внешнего связывания с Renga некоторые функции могут быть не доступны. Нигде в официальной справке информации об этом нет, не известно, баг это или особенность поведения, но автор считает своим долгом поделиться этой информацией:
- невозможно получить IScreenshotService для активного вида;
Взаимодействие с приложением Renga
Приложение Renga, описываемое COM-интерфейсом Renga.IApplication позволяет:
- получить доступ к проекту (свойство Project);
- добавить в меню новые команды и панели;
- получить и задать некоторую общую информацию (локаль, видимость, версию, название);
- получить доступ к вспомогательному классу Math, с помощью которого можно создавать новые экземпляры кривых;
- открыть, закрыть, создать новый проект;
- осуществить выход из процесса Renga;
- получить доступ к активному виду проекта;
- получить доступ к чтению и заданию выбора объектов;
Разработчик плагинов из всего перечисленного по убыванию приоритета имеет дело с:
- изменением меню;
- выборкой объектов;
- взаимодействием с активным видом;
- работой с кривыми для создания новых объектов;
Работа с меню в настоящем руководстве будет рассмотрена по остаточному принципу, родная справка хорошо объясняет этот материал.
Приложение Renga фактически содержит инструменты работы с открытым в ней проектом -- механика выбора, доступ к активному виду.
Работа с видом
Свойство ActiveView COM-оболочки приложения возвращает активный вид текущего приложения, описываемый COM-оболочкой Renga.IView. Свойство последнего Type характеризует вид этого вида.
ВариантыViewType_ProjectExplorer или ViewType_Undefined описывают вид вне открытого проекта, остальные варианты перечислений ViewType характеризуют какую-то составляющую проекта.
У вида, свойство Type которого = ViewType_View3D, можно получить другую COM-оболочку, называемую Renga.IView3DParams, которая предоставляет доступ к камере (считывание параметров ее положения, установка положения), подробнее см. вложенную статью. Для заданного положения камеры можно создать снимок.
Также для вида, свойство Type которого = ViewType_View3D, ViewType_Level, ViewType_Assembly или ViewType_Drawing, можно получить COM-оболочку Renga.IModelView, предоставляющую доступ к чтению и редактированию параметров видимости объектов, заданию визуального стиля. Подробнее см. статью Управление видимостью объектов.
Работа с камерой
Функциональность камеры в Renga описывается COM-оболочкой Renga.ICamera3D. Получить её можно только для активного 3D-вида проекта приложения.
Ниже приводится метод расширения на C#, получающий камеру у объекта приложения:
public static Renga.ICamera3D? GetCamera(this Renga.IApplication application)
{
Renga.IView view = application.ActiveView as Renga.IView;
if (view.Type != Renga.ViewType.ViewType_View3D) return null;
Renga.IView3DParams? viewModelParams = viewModel as Renga.IView3DParams;
if (viewModelParams == null) return null;
return viewModelParams.Camera;
}
Механика работы камеры
Камера отражает текущую точку обзора для активного 3D-вида модели проекта.
Свойство Position задает точку обзора, свойство FocusPoint - точку на векторе, куда направлен взгляд, свойство UpVector - направление вверх, чтобы таким образом однозначно ориентировать правую декартову систему координат в пространстве.
Упомянутые выше свойства редактируемы - они могут быть изменены c помощью метода LookTo, и ориентация камеры также будет изменена.
Readonly-свойства FovHorizontal, FovVertical характеризуют соответственно горизонтальный и вертикальный сегмент обзора в радианах. Как кажется автору, это актуально для перспективного вида.
Для лучшего понимания механики работы параметров проведем сопоставлением с работой в Renga:
- при любых операциях вращения сцены будут меняться только параметры
PositionиUpVector; - при масштабировании сцены колесиком будет меняться
PositionиFocusPoint; Так как работа с информационной моделью в Renga ведется около нуля координат (более того, он обычно является точкой пересечения начала строительных осей), то можно говорить, чтоFocusPointв основном будет указывать на точку "0,0,0".
Параметры камеры являются зависимыми друг от друга. Например, переопределяя точку Position и FocusPoint, параметр UpVector будет меняться, несмотря на заданное ему другое значение.
Изменение положения камеры
Изменить положение камеры можно с помощью метода LookAt COM-оболочки камеры Renga.ICamera3D. Метод принимает на вход все 3 определяющих параметра камеры -- точку взгляда, вектор направления и вектор, задающий ось Z.
Покажем ниже несколько вариантов положения камеры для сторон видового куба, с расчетом, что точка обзора будет удалена на фиксированное расстояние от "нуля координат":
// Сдвиг координат, мм
double coordsOffsetView = 100000; // 100 м.
private void SetView(double[] position)
{
// Используется метод расширения из листинга выше
Renga.ICamera3D? camera = PluginData.rengaApplication.GetCamera();
if (camera == null) return;
// Конструктор FloatPoint3D условный, на самом деле его нет
// Сделано для наглядности. И да, он работает с float
camera.LookAt(
new FloatPoint3D(0,0,0),
new FloatPoint3D(position[0], position[1], position[2]),
new FloatPoint3D(0,0,1));
}
private void Button_SetOrientFix_Top_Click()
{
SetView(new double[] {0,0, coordsOffsetView });
}
private void Button_SetOrientFix_Down_Click()
{
SetView(new double[] { 0, 0, -coordsOffsetView });
}
private void Button_SetOrientFix_Right_Click()
{
SetView(new double[] { coordsOffsetView, 0, 0 });
}
private void Button_SetOrientFix_Left_Click()
{
SetView(new double[] { -coordsOffsetView, 0, 0 });
}
private void Button_SetOrientFix_Front_Click()
{
SetView(new double[] { 0, coordsOffsetView, 0 });
}
private void Button_SetOrientFix_Back_Click()
{
SetView(new double[] { 0, -coordsOffsetView, 0 });
}
Создание скриншотов сцены
Текущий вид можно сохранить в виде снимка. Виды, которые можно сохранять:
- 3D-вид модели (с версии 5.5);
- сборка (с какой версии неизвестно);
- чертеж (c версии 8.10);
Доступ к созданию снимка осуществляется через COM-оболочку Renga.IScreenshotService, которая получается вызовом метода GetInterfaceByName("IScreenshotService") для COM-оболочки вида IModelView, подробнее см. статью о нём.
[!CAUTION] Сохранять снимки можно только из-под загруженных плагинов. При попытке сделать получение COM-оболочки IScreenshotService извне, вернется
null.
Снимок (скриншот) формируется с помощью метода MakeScreenshot для заданных настроек IScreenshotSettings (экземпляр настроек создается через метод той же COM-оболочки CreateSettings).
Созданный снимок будет описываться COM-оболочкой Renga.IImage, который можно сохранить в файл с помощью метода SaveToFile в виде картинки BMP или PNG.
Настройки снимка IScreenshotSettings определяют только разрешение снимка по горизонтали и вертикали в пикселях (свойства Width и Height соответственно).
Renga.IApplication rengaApp;
// Получаем активный вид
Renga.IView rengaView = rengaApp.ActiveView;
// Приводим вид к интерфейсу Renga
Renga.IModelView? rengaViewModel = rengaView as Renga.IModelView;
if (rengaViewModel == null) return;
// Получаем вспомогательный сервис для создания снимков
Renga.IScreenshotService? screenServics;
screenServics = rengaViewModel.GetInterfaceByName("IScreenshotService")
as Renga.IScreenshotService;
//screenServics = rengaView as Renga.IScreenshotService;
if (screenServics == null) return;
// Создаем настройки для снимка
Renga.IScreenshotSettings settings = screenServics.CreateSettings();
settings.Width = 512;
settings.Height = 512;
//Создаем снимок
Renga.IImage createdScreen = screenServics.MakeScreenshot(settings);
// Сохраняем снимок в файл
createdScreen.SaveToFile("rengaScreen1.png",
Renga.ImageFormat.ImageFormat_PNG);
Управление видимостью объектов
Если текущий вид это 3D-пространство модели, план, сборка или чертёж, для него можно получить COM-оболочку Renga.IModelView, предоставляющую доступ к чтению и редактированию параметров видимости объектов, заданию визуального стиля.
Кроме того, у IModelView имеется метод GetInterfaceByName, позволяющий безопасно получить сервис для создания снимков.
Методы COM-оболочки Renga.IModelView можно разделить на 2 группы:
- управление видимостью объектов;
- управление визуальным стилем вида и отдельных объектов;
Видимость объектов
- GetHiddenObjects - возвращает массив int-идентификаторов скрытых объектов на данном виде;
- GetVisibleObjects - возвращает массив int-идентификаторов видимых объектов на данном виде;
- IsObjectVisible - возвращает признак, видим ли объект по заданному int-идентификатору на данном виде;
- SetObjectsVisibility - задает признак видимости (или невидимости) для заданной группы int-идентификаторов объектов на данном виде;
- ShowObjects - задает видимость объектов для заданной группы int-идентификаторов объектов на данном виде (только для 3D-вида); Ниже предлагается авторский метод расширения, задающий видимость объектов для 4 случаев:
public enum ObjectsVisibilityVariant
{
ShowAll, //показать все объекты
HideAll, // скрыть все
ShowOnlySelected, // скрыть все, кроме выбранных
HideOnlySelected // показать все, кроме выбранных
}
public static void SetObjectsVisibility2(this Renga.IModelView rengaModelView,
ObjectsVisibilityVariant mode, int[]? ids)
{
Renga.IApplication rengaApp;
Renga.IModel model = rengaApp.Project.Model;
Renga.IModelObjectCollection rengaObjectsCollection
= model.GetObjects();
List<int> idsAll = new List<int>();
for (int rengaObjectIndex = 0; rengaObjectIndex <
rengaObjectsCollection.Count; rengaObjectIndex++)
{
Renga.IModelObject rengaObject =
rengaObjectsCollection.GetByIndex(rengaObjectIndex);
idsAll.Add(rengaObject.Id);
}
if (mode == ObjectsVisibilityVariant.ShowAll)
rengaModelView.SetObjectsVisibility(idsAll.ToArray(), true);
else if (mode == ObjectsVisibilityVariant.HideAll)
rengaModelView.SetObjectsVisibility(idsAll.ToArray(), false);
else if (ids == null || !ids.Any()) return;
if (mode == ObjectsVisibilityVariant.ShowOnlySelected)
{
var idsToHide = idsAll.Except(ids);
rengaModelView.SetObjectsVisibility(ids, true);
if (idsToHide.Any()) rengaModelView.
SetObjectsVisibility(idsToHide.ToArray(), false);
}
else if (mode == ObjectsVisibilityVariant.HideOnlySelected)
{
var idsToShow = idsAll.Except(ids);
rengaModelView.SetObjectsVisibility(ids, false);
if (idsToShow.Any()) rengaModelView.
SetObjectsVisibility(idsToShow.ToArray(), true);
}
}
Визуальный стиль
- GetObjectVisualStyle - возвращает визуальный стиль объекта по его int-идентификатору;
- SetObjectsVisualStyle - задает объектам визуальный стиль по их int-идентификаторам; Свойство VisualStyle - возвращает или задает визуальный стиль для всего вида.
Как правило,
Работа с выборкой объектов
Свойство Selection COM-оболочки приложения Renga возвращает COM-оболочку Renga. ISelection для получения и задания пользовательского выбора объектов в текущем проекте.
COM-оболочка содержит 2 метода -- получить выбор GetSelectedObjects и сделать заданные объекты выбранными SetSelectedObjects.
Неочевидное на первый взгляд действие, сброс выбора, это передача методу SetSelectedObjects пустой коллекции объектов.
Событие выбора
Можно подписаться на событие выбора объектов в модели через механизм Renga.SelectionEventSource. Подписка на событие осуществляется, как правило, из процедуры плагина Initialize.
private Renga.IApplication m_application;
private Renga.SelectionEventSource m_selectionEventSource;
public bool Initialize(string pluginFolder)
{
m_application = new Renga.Application();
var selection = m_application.Selection;
m_selectionEventSource = new Renga.SelectionEventSource(selection);
m_selectionEventSource.ModelSelectionChanged += OnModelSelectionChanged;
return true;
}
private void OnModelSelectionChanged(object sender, EventArgs args)
{
var selection = m_application.Selection;
//Ваши действия ... с selection.GetSelectedObjects()
}
Взаимодействие с проектом Renga
Приложение Renga фактически работает с одним активным проектом в сессии.
Через сущность проекта, описываемого COM-оболочкой Renga.IProject осуществляются все действия по созданию свойств, объектов, получению информации о стилях и т.д.
Получить COM-оболочкуRenga.IProject можно с помощью свойства Project у COM-оболочки приложения Renga.IApplication.
Доступ почти ко всем коллекциям объектов и стилей, а также к специальным инструментам взаимодействия с моделью получается с помощью свойств у COM-оболочки проекта.
Свойства проекта
У каждого проекта имеется так называемая "Информация о проекте". Это модальное диалоговое окно, открывающееся из интерфейса Renga и состоящее из 3 вкладок: Проект, Участок и Здание. Каждая из вкладок, а также каждый из элементов вкладки описывается соответствующей COM-оболочкой и её свойством.
Информация о проекте
Описывается COM-оболочкой Renga.IProjectInfo. Получается через свойство ProjectInfo у COM-оболочки проекта Renga.IProject.
| Как в Renga | API | Примечание |
|---|---|---|
| Обозначение проекта | Code | |
| Наименование проекта | Name | |
| Стадия | Stage | |
| Описание проекта | Description |
Информация о здании
Описывается COM-оболочкой Renga.IBuildingInfo. Получается через свойство BuildingInfo у COM-оболочки проекта Renga.IProject.
| Как в Renga | API | Примечание |
|---|---|---|
| Номер здания | Number | |
| Наименование здания | Name | |
| Адрес здания | Stage | Прим. 1 |
| Описание здания | Description | |
Примечание 1: поле адреса составное, описывается COM-оболочкой Renga.IPostalAddress. Редактируется напрямую после получения данного адреса через свойство GetAddress. | ||
| Среди свойств здания располагаются параметры трансформации координат при экспорте в IFC. Ими можно пользоваться для выполнения операций импорта-экспорта данных в модель. |
Ниже предлагается метод расширения на C#, возвращающий параметры трансформации координат в виде класса ProjectTransformPararameters. Также там имеется перегрузку для участка, поскольку согласно справке к Renga он тоже может использоваться для задания сдвига координат.
using System;
using System.Linq;
public class ProjectTransformPararameters
{
public double X;
public double Y;
public double Z;
public double AngleRad;
public ProjectTransformPararameters()
{
X = 0;
Y = 0;
Z = 0;
AngleRad = 0;
}
}
internal static class BuildingSiteInfoExtension
{
private static ProjectTransformPararameters getTransformPararameters(Renga.IPropertyContainer props)
{
ProjectTransformPararameters trparams = new ProjectTransformPararameters();
if (PluginData.Project == null) return trparams;
// Резервируем имена целевых свойств
string propName_IfcLocationX = "IfcLocationX";
string propName_IfcLocationY = "IfcLocationY";
string propName_IfcLocationZ = "IfcLocationZ";
string propName_IfcDirectionPrecession = "IfcDirectionPrecession";
var propDefs = PluginData.Project.PropertyManager.GetPropertiesDef();
if (propDefs == null) return trparams;
// Находим определения свойств в проекте Renga
var propRes_IfcLocationX = propDefs.Where(p => p.Name == propName_IfcLocationX);
var propRes_IfcLocationY = propDefs.Where(p => p.Name == propName_IfcLocationY);
var propRes_IfcLocationZ = propDefs.Where(p => p.Name == propName_IfcLocationZ);
var propRes_IfcDirectionPrecession = propDefs.Where(p => p.Name == propName_IfcDirectionPrecession);
// Если хотя бы одного определения нет, завершаем
if (!propRes_IfcLocationX.Any() || !propRes_IfcLocationY.Any() || !propRes_IfcLocationZ.Any() || !propRes_IfcDirectionPrecession.Any()) return trparams;
// Идентификаторы свойств
RengaPropertyDefinition propDef_IfcLocationX = propRes_IfcLocationX.First();
RengaPropertyDefinition propDef_IfcLocationY = propRes_IfcLocationY.First();
RengaPropertyDefinition propDef_IfcLocationZ = propRes_IfcLocationZ.First();
RengaPropertyDefinition propDef_IfcDirectionPrecession = propRes_IfcDirectionPrecession.First();
Renga.IProperty? propInstance_IfcLocationX = null;
Renga.IProperty? propInstance_IfcLocationY = null;
Renga.IProperty? propInstance_IfcLocationZ = null;
Renga.IProperty? propInstance_IfcDirectionPrecession = null;
if (props.Contains(propDef_IfcLocationX.Id)) propInstance_IfcLocationX = props.Get(propDef_IfcLocationX.Id);
if (props.Contains(propDef_IfcLocationY.Id)) propInstance_IfcLocationY = props.Get(propDef_IfcLocationY.Id);
if (props.Contains(propDef_IfcLocationZ.Id)) propInstance_IfcLocationZ = props.Get(propDef_IfcLocationZ.Id);
if (props.Contains(propDef_IfcDirectionPrecession.Id)) propInstance_IfcDirectionPrecession = props.Get(propDef_IfcDirectionPrecession.Id);
if (propInstance_IfcLocationX == null || propInstance_IfcLocationY == null || propInstance_IfcLocationZ == null || propInstance_IfcDirectionPrecession == null) return trparams;
// поверяем типы свойств
if (propDef_IfcLocationX.PType != Renga.PropertyType.PropertyType_Length |
propDef_IfcLocationY.PType != Renga.PropertyType.PropertyType_Length |
propDef_IfcLocationZ.PType != Renga.PropertyType.PropertyType_Length |
propDef_IfcDirectionPrecession.PType != Renga.PropertyType.PropertyType_Angle) return trparams;
trparams.X = propInstance_IfcLocationX.GetLengthValue(Renga.LengthUnit.LengthUnit_Meters);
trparams.Y = propInstance_IfcLocationY.GetLengthValue(Renga.LengthUnit.LengthUnit_Meters);
trparams.Z = propInstance_IfcLocationZ.GetLengthValue(Renga.LengthUnit.LengthUnit_Meters);
var angle = propInstance_IfcDirectionPrecession.GetAngleValue(Renga.AngleUnit.AngleUnit_Degrees);
if (angle < 0) angle = 360.0 + angle;
trparams.AngleRad = Math.PI * propInstance_IfcDirectionPrecession.GetAngleValue(Renga.AngleUnit.AngleUnit_Degrees) / 180.0;
return trparams;
}
/// <summary>
/// Возвращает параметры трансформации координат из свойств здания. Сдвиг XYZ в метрах, угол поворота вокруг оси Z в градусах, наименование СК
/// </summary>
/// <param name="buildingInfo"></param>
/// <returns></returns>
public static ProjectTransformPararameters GetTransformPararameters(this Renga.IBuildingInfo buildingInfo)
{
return getTransformPararameters(buildingInfo.GetProperties());
}
/// <summary>
/// Возвращает параметры трансформации координат из свойств участка. Сдвиг XYZ в метрах, угол поворота вокруг оси Z в градусах, WKT-код СК
/// </summary>
/// <param name="buildingInfo"></param>
/// <returns></returns>
public static ProjectTransformPararameters GetTransformPararameters(this Renga.ISiteInfo siteInfo)
{
return getTransformPararameters(siteInfo.GetProperties());
}
}
Информация об участке
Описывается COM-оболочкой Renga.ISiteInfo. Получается через свойство SiteInfo у COM-оболочки проекта Renga.IProject.
| Как в Renga | API | Примечание |
|---|---|---|
| Номер участка | Number | |
| Наименование участка | Name | |
| Адрес участка | Stage | см. Прим.1 для здания |
| Описание участка | Description |
Информация о здании
Информация об участке
Информация о проекте
Прочие свойства
К числу прочих свойств, имеющихся у COM-оболочки проекта IProject, можно отнести:
- FilePath - абсолютный путь к текущему проекту или его имя, если проект не был сохранен;
- JournalPath - абсолютный путь к файлу журнала действий с моделью, он же лог при серверной работе;
Вспомогательные методы
Также у COM-оболочки проекта имеются некоторые методы, которые можно позиционировать как вспомогательные:
- ExportDrawingsToPdf - экспорт набора чертежей в PDF;
- ExportObjectsToIFC - экспорт группы объектов в IFC;
- ExportToCsv - экспорт информации о свойствах и стиля проекта в набор CSV;
- HasUnsavedChanges - возвращает признак, есть ли в проекте несохраненные изменения;
- HasFile - возвращает признак, был ли проект когда-либо сохранен;
- Save - сохраняет данный проект проект, включая перегрузку SaveAs - сохранение с параметрами;
Категории
Категории в Renga - это объекты инженерных систем, называемые также "категориями", сгруппированные по видам инженерных систем (перечень ограничен). На базе категории может быть создан 1 или несколько стилей (см. о них следующий раздел).
В таблице ниже приведен перечень всех возможных категорий в Renga, информация - каким перечислением EntityTypes описывается категория группы, через какое свойство COM-оболочки проекта Renga.IProject данная категория доступна:
| Название группы в Renga | EntityType | Свойство в IProject |
|---|---|---|
| Санитарно-техническое оборудование | PlumbingFixtureCategory | PlumbingFixtureCategories |
| Оборудование | EquipmentCategory | EquipmentCategories |
| Деталь трубопровода | PipeFittingCategory | PipeFittingCategories |
| Аксессуар трубопровода | PipeAccessoryCategory | PipeAccessoryCategories |
| Вентиляционное оборудование | MechanicalEquipmentCategory | MechanicalEquipmentCategories |
| Деталь воздуховода | DuctFittingCategory | DuctFittingCategories |
| Аксессуар воздуховода | DuctAccessoryCategory | DuctAccessoryCategories |
| Электроустановочное изделие | WiringAccessoryCategory | WiringAccessoryCategories |
| Осветительный прибор | LightingFixtureCategory | LightingFixtureCategories |
| Электрический распределительный щит | ElectricDistributionBoardCategory | ElectricDistributionBoardCategories |
Создание категорий
С помощью API начиная с версии Renga 8.3 возможен импорт в проект новой категории из RST-файла (создаваемого с помощью STDL). За это отвечает метод ImportCategory у COM-оболочки проекта Renga.IProject. Метод принимает на вход идентификатор импортируемой категории объектов (см. таблицу выше) и абсолютный путь к RST-файлу, возвращаемый объект описывается стандартной COM-оболочкой Renga.IEntity. Далее на основе идентификатора импортированной категории можно создать стиль. Ниже обобщенный пример подобной операции:
[!ATTENTION] Для программного импорта стиля в модель необходимо иметь лицензию на редакцию Professional.
Renga.IProject project;
Guid categoryType = Renga.EntityTypes.MechanicalEquipmentCategory;
Guid typeId = Renga.EntityTypes.MechanicalEquipmentStyle;
string categoryRstPath;
var operation = project.CreateOperation();
operation.Start();
var category = project.ImportCategory(categoryType, categoryRstPath);
operation.Apply();
operation.Start();
var argsUnits = project.MechanicalEquipmentStyles.CreateNewEntityArgs();
argsUnits.TypeId = typeId;
argsUnits.CategoryId = category.Id;
var style = project.MechanicalEquipmentStyles.Create(argsUnits);
Стили
Стили в Renga - это варианты описания объектов и различных настроек. Не все стили, называемые "Styles" в API в самой программе также называются "стилями", например, тип ReinforcementGrade (класс арматуры) называется "Reinforcement grade style", хотя в самой Renga называется только как "класс"
Стили для объектов
Стили в Renga, относящиеся к объектам, подразделяются на ряд "тематических групп", каждый стиль описывает один или несколько типоразмеров объекта (обычно, параметрического). На базе конкретного стиля создается объект соответствующего типа модели Renga. Типовой стиль имеет некоторый профиль (геометрию) и набор свойств. По умолчанию все стили создаются вручную во встроенном редакторе Renga, некоторые стили могут также создаваться на основе категорий (импортированных из STDL).
Стили для настроек
В основном, это перечень различных настроек из меню "Оформление" меню проекта в Renga и другие.
Перечень стилей
В таблице ниже приводится перечень категорий стилей, информация, с какой версии API возможно их создание, каким свойством описывается коллекция стилей в составе свойств проекта, какие категории связаны с данными стилями, возможность создать объект данной категории. Для версии API Renga 2.46 (8.12). В скобках приведена информация, с какой версии появилась возможность создания, там где эта информация известна. Если стиль описывает неграфический объект, то для него не будут заполнены ячейки в колонках "Можно создать объект". Пустые поля означают, что в API это не реализовано.
| Имя в API (EntityTypes) | Имя в Renga на русском | Где в меню Renga | Свойство в IProject | Категории | Можно создать стиль | Можно создать объект В модели |
|---|---|---|---|---|---|---|
| Assembly | Сборка | Assemblies | ❌ | ✅ (8.6) | ||
| BeamStyle | Стиль балки | Стили балки | BeamStyles | ✅ | ✅ (8.9) | |
| BuildingElementModel | ❓ (связи?) | ❓ | ||||
| ColumnStyle | Стиль колонны | Стили колонны | ColumnStyles | ✅ | ✅ (8.6) | |
| DisplayStyle | Стиль отображения | Оформление - Стили отображения | ❓ | |||
| DoorStyle | Стиль двери | Стили двери | DoorStyles | ✅ | ✅ (8.6) | |
| DuctAccessoryStyle | Стиль аксессуара воздуховода | Воздуховодные системы - Стили аксессуара воздуховода | DuctAccessoryStyles | DuctAccessoryCategories | ✅ | ❌ |
| DuctFittingStyles | Стиль детали воздуховода | Воздуховодные системы - Стили детали воздуховода | DuctAccessoryStyles | DuctFittingCategories | ✅ | ❌ |
| DuctStyle | Стиль воздуховода | Воздуховодные системы - Стили воздуховода | DuctStyles | ✅ | ❌ | |
| ElectricCircuitLineStyle | Стиль электрической линии | Электрические системы - Стили электрической линии | ElectricalCircuitLineStyles | ✅ | ❌ | |
| ElectricalConductorStyle | Стиль проводника | Электрические системы - Стили проводника | ElectricalConductorStyles | ✅ | ❌ | |
| ElectricDistributionBoardStyle | Стиль электрического распределительного щита | Электрические системы - Стили электрического распределительного щита | ElectricDistributionBoardStyles | ElectricDistributionBoardCategories | ✅ | ✅ (8.12) |
| ElementStyle | Стиль элемента | Стили элемента | ElementStyles | ✅ | ✅ (8.6) | |
| EquipmentStyle | Стиль оборудования | Трубопроводные системы - Стили оборудования | EquipmentStyles | EquipmentCategories | ✅ | ✅ (8.9) |
| HatchPatternStyle | Стиль штриховки | Оформление - Штриховки | ❌ | ✅ (8.7) | ||
| HoleStyle | Стиль отверстия | Стили отверстия | HoleStyles | ✅ | ✅ (8.7) | |
| LayoutStyle | Стиль оформления | Оформление - Стили оформления | LayoutStyles | ✅ | ||
| LightingFixtureStyle | Стиль осветительного прибора | Электрические системы - Стили осветительного прибора | LightingFixtureStyles | LightingFixtureCategories | ✅ | ✅ (8.12) |
| Material | Материал (стиль материала) | Материалы | Materials | ❌ | ||
| MechanicalEquipmentStyle | Стиль вентиляционного оборудования | Воздуховодные системы - Стили вентиляционного оборудования | MechanicalEquipmentStyles | MechanicalEquipmentCategories | ✅ | ✅ (8.9) |
| PageFormat | Стиль формы страницы ❓ | ❓ | PageFormatStyles | ✅ | ||
| PipeAccessoryStyle | Стиль аксессуара трубопровода | Трубопроводные системы - Стили аксессуара трубопровода | PipeAccessoryStyles | PipeAccessoryCategories | ✅ | ❌ |
| PipeFittingStyle | Стиль детали трубопровода | Трубопроводные системы - Стили детали трубопровода | PipeFittingStyles | PipeFittingCategories | ✅ | ❌ |
| PipeStyle | Стиль трубы | Трубопроводные системы - Стили трубы | PipeStyles | ✅ | ❌ | |
| PlateStyle | Стиль пластины | Стили пластины | PlateStyles | ✅ | ✅ (8.6) | |
| PlumbingFixtureStyle | Стиль санитарно- технического оборудования | Трубопроводные системы - Стили санитарно- технического оборудования | PlumbingFixtureStyles | PlumbingFixtureCategories | ✅ | ✅ (8.9) |
| RebarStyle | Стиль арматурного стержня | Армирование - Стили арматурного стержня | RebarStyles | ✅ | ❌ | |
| ReinforcementGrade | Класс арматуры | Армирование - Классы арматуры | ReinforcementGrades | ✅ | ❌ | |
| ReinforcementStyle | Стиль армирования | Армирование - Стили армирования | ReinforcementStyles | ❌ | ||
| ReinforcementUnitStyle | Стиль арматурного изделия | Армирование - Стили арматурных изделий | ReinforcementUnitStyles | ❌ | ||
| SystemStyle | Стиль системы | Стили системы | SystemStyles | ❌ | ||
| TagStyle | Стиль маркера | Оформление - Стили маркера | ||||
| TextStyle | Стиль текста | Оформление - Стили текста | ||||
| Topic | Раздел | Оформление - Разделы | ||||
| WindowStyle | Стиль окна | Стили окна | WindowStyles | ✅ | ✅ (8.6) | |
| WiringAccessoryStyle | Стиль электроустановочного изделия | Электрические системы - Стили электроустановочного изделия | WiringAccessoryStyles | WiringAccessoryCategories | ✅ | ✅ (8.12) |
Создание стилей
Создание новых стилей, как и создание объектов в модели, осуществляется с помощью сходного подхода через CreateNewEntityArgs и Create. Доступны с версии Renga 8.4.
Стили создаются для одного из фиксированных набора стилей, каждый набор стилей описывается COM-оболочкой Renga.IEntityCollection.
У COM-оболочки целевой коллекции стилей, например, стилей вентиляционного оборудования (доступных через свойство MechanicalEquipmentStyles у COM-оболочки проекта) вызывается метод CreateNewEntityArgs, возвращающий экземпляр настроек для создания стиля (описывается COM-оболочкой Renga.INewEntityArgs).
У него обязательно заполняются 2 параметра:
- TypeId (равен идентификатору стиля для заданной группы из перечисления
Renga.StyleTypeIds, в данном случае для вентиляционного оборудования -MechanicalEquipmentStyle); - CategoryId (равен свойству Id у COM-оболочки категории оборудования из набора категорий для заданной группы стилей, если таковая есть, в данном случае для вентиляционного оборудования это
MechanicalEquipmentCategories); Для созданного экземпляра настроек у той же COM-оболочки целевой коллекции стилей вызывается методCreate, возвращающий объект стиля, доступный через COM-оболочкуRenga.IEntity.
Ниже обобщенный пример, показывающий подобный сценарий импорта. Сперва создается определение категории из RST-файла, затем создается стиль на базе созданной категории.
Renga.IProject project;
Guid categoryType = Renga.EntityTypes.MechanicalEquipmentCategory;
Guid typeId = Renga.EntityTypes.MechanicalEquipmentStyle;
string categoryRstPath;
var operation = project.CreateOperation();
operation.Start();
var category = project.ImportCategory(categoryType, categoryRstPath);
operation.Apply();
operation.Start();
var argsUnits = project.MechanicalEquipmentStyles.CreateNewEntityArgs();
argsUnits.TypeId = typeId;
argsUnits.CategoryId = category.Id;
var style = project.MechanicalEquipmentStyles.Create(argsUnits);
Для коллекций стилей, не имеющих категорий, свойство CategoryId соответственно не указывается.
Примечание: Автору настоящей справки не понятно, зачем разработчики добавили возможность создания стиля, если ему нельзя назначить геометрию и задать имя 😐. Это относится ко всем стилям, не только к тем, что создаются на основе категорий. Фактически, это мёртворожденная затея без всякого смысла....
Чтение стилей
Получить информацию о любом стиле в Renga можно с помощью COM-оболочки Renga.IEntity. Каких-либо специальных COM-оболочек для какого-либо стиля в настоящем API (для Renga 8.12) не существует.
Процесс перебора COM-оболочки коллекции стилей, представленной Renga.IEntityCollection также не представляет каких-либо трудностей. Используйте цикл для количества стилей в коллекции Count и метод GetByIndex, возвращающий определение стиля, описываемое COM-оболочкой Renga.IEntity. Полученный стиль можно привести к COM-оболочке набора свойств или параметров, характерный для стиля данного типа.
В примере ниже у проекте получается коллекция стилей дверей, она перебирается, если приведением стиля к COM-оболочке набора параметров Renga.IParameterContainer было успешным, то для каждое приведенного к строке непустое значение запоминается и после перебора всех параметров выводится в диалоговое окно.
Renga.IApplication rengaApp;
StringBuilder tmpText = new StringBuilder();
// Получаем набор стилей дверей
Renga.IEntityCollection doorStyles = rengaApp.Project.DoorStyles;
for (int styleIndex = 0; styleIndex < doorStyles.Count; styleIndex++)
{
Renga.IEntity doorStyle = doorStyles.GetByIndex(styleIndex);
Renga.IParameterContainer? doorStyleParams =
doorStyle.GetInterfaceByName("IParameterContainer") as Renga.IParameterContainer;
if (doorStyleParams == null) continue;
tmpText.AppendLine("Door parameters for style " + doorStyle.Name);
Renga.IGuidCollection doorStyleParams_Ids = doorStyleParams.GetIds();
for (int paramIndex = 0; paramIndex < doorStyleParams_Ids.Count; paramIndex++)
{
Renga.IParameter doorParam = doorStyleParams.Get(doorStyleParams_Ids.Get(paramIndex));
bool isNeed = (doorParam.HasValue && !string.IsNullOrEmpty(doorParam.GetStringValue())) ? true :false;
if (!isNeed) continue;
tmpText.AppendLine($"Name: {doorParam.Definition.Name}; Value: {doorParam.GetStringValue()}");
}
}
rengaApp.UI.ShowMessageBox(Renga.MessageIcon.MessageIcon_Info, "Result", tmpText.ToString());
Работа со свойствами
Свойства в Renga представлены 3 отдельными группами, каждая со своей логикой:
- классические свойства нескольких типов, можно свободно создавать, редактировать и назначать типам объектов;
- расчетные свойства, перечень ограничен, характерны объектам определенных типов. Доступны только для чтения. Страница официальной справки с "матрицей" расчетных свойств для объектов;
- параметры, как и расчетные свойства ограничены и специфичны типам объектов, таблицы с их сопоставлением с объектами, как для расчетных свойств, нет. Параметры можно редактировать для различных типов значений;
Каждая из "групп" свойств выше описывается своими идентификаторами, COM-оболочками.
Получение доступа к свойствам осуществляется через методы у COM-оболочек объектов модели и\или чертежа, некоторых неграфических элементов; также некоторые элементы могут приводиться к COM-оболочке "набора свойств", например, стиль описываемый COM-оболочкой
Renga.IEntityможно привести к набору параметров (COM-оболочкаRenga.IParameterContainer).
Обычные свойства
Свойство PropertyManager COM-оболочки проекта IProject возвращает менеджер обычных свойств, описываемый COM-оболочкой Renga.IPropertyManager.
С помощью данного менеджера можно создавать новые определения свойств, проверять наличие свойства в проекте и получать их, назначать свойство типам объектов, удалять свойства.
Специфика свойств в Renga состоит в наличии у свойства уникального идентификатора типа Guid. Все действия со свойствами через данный менеджер осуществляются через идентификатор свойства. Имеются перегрузки методов, работающие с идентификатором как со строкой (с суффиксом S) и как с Guid.
Общие методы менеджера свойств
К числу общих и специальных методов у COM-оболочки менеджера свойств Renga.IPropertyManager можно отнести:
GetCSVExportFlag- возвращает признак, будет ли свойство экспортировано в CSV. Флажок может поставить Пользователь в самой программе или через API, методSetCSVExportFlag;SetCSVExportFlag- задает признак, будет ли свойство экспортировано в CSV;GetExpression- возвращает выражение (формулу) для данного определения свойства и типа объекта;SetExpression- задает выражение (формулу) для данного определения свойства и типа объекта. (Примечание: не понимаю, зачем ещё и тип объекта. В линейке программ ModelStudioCS формула едина на всё определение свойства);
Информацию о прочих методах менеджера свойств смотрите в статьях раздела.
Процесс создания нового определения свойств через API аналогичен процессу через пользовательский интерфейс Renga с той разницей, что через API имеется возможно задать идентификатор свойства, а через UI - нет.
Шаг 1 - Создать определение свойства
Здесь мы вынуждены прибегнуть к тавтологии.
Необходимо создать вспомогательный объект, описываемый COM-оболочкой Renga.IPropertyDescription, который будет содержать информацию о новом определении свойства -- его имени и типе. Тип описывается стандартным перечислением Renga.PropertyType из состава библиотеки типов. Альтернативный сценарий - создать экземпляр структуры Renga.PropertyDescription и задать ей поля Name и Type аналогично аргументам метода CreatePropertyDescription.
Renga.IPropertyManager manager;
// Вариант 1
Renga.IPropertyDescription propDef = manager.CreatePropertyDescription("DeveloperName",
Renga.PropertyType.PropertyType_String);
// Вариант 2
Renga.PropertyDescription propDef2 = new Renga.PropertyDescription(){Name = "DeveloperName",
Type = Renga.PropertyType.PropertyType_String};
Шаг 2 - Зарегистрировать свойство
Далее, в зависимости от того, чем представлено определение свойства -- COM-оболочкой Renga.IPropertyDescription или структурой Renga.PropertyDescription необходимо зарегистрировать определение свойства с указанным идентификатором в проекте Renga. В первом случае -- через метод RegisterProperty2, во второй -- через метод RegisterProperty.
Проверить, занят ли данный идентификатор для нового определения свойства перед его добавлением можно через метод IsPropertyRegistered.
Renga.IPropertyManager manager;
Guid newPropDefId = Guid.Parse("06f8a29e-c932-4432-961c-8a61e5a9c8b8");
if (manager.IsPropertyRegistered(newPropDefId)) return;
// Вариант 1
manager.RegisterProperty2(newPropDefId, propDef);
// Вариант 2
manager.RegisterProperty(newPropDefId, propDef2);
Пока свойство не будет зарегистрировано, оно не появится в проекте. Можно считать данный процесс аналогичным созданию.
Обратная процедура -- UnregisterProperty фактически означает удаление свойства из проекта.
Шаг 3 - Связывание свойства с типами объектов
Далее необходимо добавить определение свойства к одному или нескольким типам объектов. Типы объектов - это Guid из класса Renga.EntityTypes.
Проверить, назначено ли свойство объекту можно с помощью метода IsPropertyAssignedToType.
Связать свойство с объектом можно через метод AssignPropertyToType.
Прочие действия
Можно задать формулу SetExpression для расчета значения свойства (формула назначается для заданного типа объекта), перед добавлением свойство должно быть добавлено к типу объекта (шаг 3).
Для определения свойства можно задать флаг, что оно будет выгружаться в CSV через метод SetCSVExportFlag.