Найти тему
Хроники Георга

Renga API & Dynamo Core. Часть 2 - интерфейсы, константы, свойства, чтение свойств; выборка объектов модели и их свойства

Оглавление

Продолжаем серию статей посвященных погружению в Renga API и сегодня поговорим про свойства проекта, возможность их чтения и изменения, а также затронем подробнее техническую часть про интерфейсы и константы (они же Enum).

Статья будет продолжать логику инструкции по передаче координат и рельефа в Renga в рамках курса по BIM-менеджменту.

Оригинальное руководство см. здесь.

Начнем, по традиции, с бутылки красного вина для понимания логики Dynamo с создания базовых классов, где будет реализована логика методов.

Начало и части "после" смотри по ссылкам ниже:

«Renga API & Dynamo Core. Часть 1 - понятие документа, пакетные операции экспорта в IFC и вывод чертежей».

Дальше:

«Renga API & Dynamo Core. Часть 3 - создание новых свойств, присвоение объектам, транзакции».

«Renga API & Dynamo Core. Часть 4 - объекты, уровни, стили отображения и COM-типизация данных».

«Renga API & Dynamo Core. Часть 5 - геометрия объектов, общие выводы»

1. О передаче интерфейсов между методами

В первой части я говорил, что Dynamo не любит интерфейсы, передаваемые в явном виде. Да, это так - но это не значит, что передавать их совсем-совсем нельзя. Можно, но в качестве object. И в другом методе (в который мы передаем этот объект), его необходимо будет явно типизировать как объект нужного интерфейса например, как ниже:

Renga.IProperty property = com_property as IProperty;

Этой задаче стоит уделить внимание по той простой причине, что в Renga в качестве интерфейсов задается много разных параметров.

В качестве показательного примера возьмем набор свойств "проекта" (IProject). Определим структуру возвращаемых данных нода как словарь вида "string,object" и реализуем его в виде:

Фффффух, вот например такой монструозный метод-словарь на 35 позиций!
Фффффух, вот например такой монструозный метод-словарь на 35 позиций!
Также в начале я добавил механику присвоения всех типов внутренних "менеджеров" отдельным созданным общим статическим переменным (чтобы пользователь не передавал их вручную и не мучился с типизацией) -- внутренний метод, запускаемый после открытия проекта
Также в начале я добавил механику присвоения всех типов внутренних "менеджеров" отдельным созданным общим статическим переменным (чтобы пользователь не передавал их вручную и не мучился с типизацией) -- внутренний метод, запускаемый после открытия проекта
Визуально мы ничего интересного не увидим, так как все объекты будут иметь тип com-объектов
Визуально мы ничего интересного не увидим, так как все объекты будут иметь тип com-объектов
Обратим внимание, что и даже такая типизация бессмысленна!
Обратим внимание, что и даже такая типизация бессмысленна!

Собственно говоря, а чего мы ожидаем увидеть :d. Интерфейсы неосзязаемы.

Реализуем отдельные методы, которые извлекают свойства из отдельных интерфейсов -- начнем с ProjectInfo, BuildingInfo и LandPlotInfo (да, я их уже реализовал в виде внутренних статических объектов) - но для визуальности можно и "повторно" их извлечь.

Получаем вот такой вариант
Получаем вот такой вариант
В то время как в самих методах происходит инициация com-объекта как объекта нужно категории
В то время как в самих методах происходит инициация com-объекта как объекта нужно категории

2. Чтение свойств классов. IProperty, IPropertyManager

Механика добавления/чтения свойств реализована через класс (интерфейс) IPropertyManager. Он является наследником IProject (то, что мы определили заранее). Ввиду наличия для интерфейса большого числа методов и связанных понятий, я создам под него отдельный класс "DynProperty".

Любое свойство имеет тип - это PropertyType (тип параметров):

Параметры (виды значений)
Параметры (виды значений)

Что нам понадобится ещё? Для чтения свойств нам понадобится так называемый PropertyContainer -- набор свойств для объекта модели/класса проекта.

Также обратим внимание, что многие методы Renga API работающие с идентификаторами имеют дублирующий метод заканчивающийся на "S", который позволяет работать с Guid как со строкой. При наличии таких методов -- я работал с ними в таком виде. Да, Guid можно сериализовать как Guid.Parse (string guid), но я предпочитаю всё же работать в среде Dynamo именно со строковыми формами Guid'ов.

Под объектами модели я буду понимать собственно сами 2d/3d объекты типа уровней, стен, окон и пр., а под объектами класса - неосязаемые сущности/свойства в рамках BuildingInfo, LandInfo, ProjectInfo и подобных.

PropertyContainer (или, как корректнее говорить IPropertyContainer) - это коллекция отдельных свойств (объектов IProperty). Типичный объект IProperty содержит 3 свойства (имя, тип, идентификатор) и методы по запросу его значений. ПРИ ЭТОМ! В зависимости от определенного ТИПА свойства (PropertyType) значение может варьироваться в разных единицах, которые для конкретного PropertyType имеют уникальную нумерацию (Enum).

Вот так выглядит это дело
Вот так выглядит это дело

Правду молвить, выглядит крайне громоздко (как и реализация в Dynamo). Вместо по сути двух действий (Получение параметра и присвоение параметра) у нас по 11 методов того и другого каждый со своей нумерацией ... как мысли вслух, было бы оптимальным наличие сквозной по PropertyType нумерации (Enum) и указание единиц отдельным свойством, а занесение значения в строчном виде с программной десерриализацией до нужного типа в зависимости от выставленного Enum.

Вот процесс получения свойств здания (ориентации его в пространстве)
Вот процесс получения свойств здания (ориентации его в пространстве)

Сперва получается объект IBuildingInfo (сущность проекта), из неё получается набор свойств, из набора свойств сперва получаются все идентификаторы свойств, назначенные объекту (классу). После этого по идентифакоторам возвращаются отдельные IProperty, из которых получают словарь значений и величину параметра.

Хз уместно ли объединить значение со словарем ... наверное да.

Возвращаемые идентификаторы свойств годятся не только для получения IProperty. Вместе с тем, это отсылка в целом к свойствам проекта, которые могут встретиться где-то ещё. Для идентификации свойства как "общего/глобального параметра" получим объект типа IPropertyDescription по данному идентификатору из менеджера свойств GetPropertyDescription()

Тут у меня не получилось получить объект свойства, отправил в sd.askon запрос ... у меня выбивало какую-то COM-ошибку при идентификации Guid.
Что-то примерно такое
Что-то примерно такое

3. Объекты модели и их свойства. Выборка объектов

А что-же по поводу объектных свойств, спросите вы? С ними ситуация проще НАМНОГО ИНТЕРЕСНЕЕ - выбираем категория объекта и из пространства модели запрашиваются все свойства, которым обладают объекты модели.

Вообще говоря, у объектов 3 типа свойств - это собственно сами свойства, применимые к типу объекта, это расчетные характеристики - масса, длина, объем и пр, и параметры.

Ещё у объекта есть метод GetInterfaceByName, но я вообще не понял что он делает и что берет на вход. В примерах справки нет его.

Начнем мы с собственных свойств (для которых у нас есть база)

3.1 Собственные свойства и выборка объектов

Грубо это выглядит вот так (такой нод я уберу)
Грубо это выглядит вот так (такой нод я уберу)

Давайте немного структурируем выводимую информацию, тем более, что все интерфейсы у нас уже описаны.

Итак, для получения набора объектов всех типов у нас есть метод от IModel -- GetObjects(). К слову, базового метода API, который выбрал бы сразу нужного типа в программе нет* - мы его напишем тоже.

Итак, упомянутый метод выше возвращает коллекцию объектов - IModelObjectCollection. У неё довольно куцый интерфейс, будем считать что это структура типа IEnumerable <IModelObject>.

Сразу скажу, глубоко в объекты лезть я не буду, это тема следующих статей.

Далее можно перебирать свойства IModelObject для выборки объектов по типу, ограничивая выборку.

Каждый объект (IModelObject) имеет свойственные категории параметры (наименование типа категории, идентификаторы объекта и категории) и собственные свойства (Сопротивление теплопередаче, предел огнестойкости и т.д.) - как раз те 3 группы, которые нам и нужны!.

Свойства категории извлекаются как свойства IModelObject, а вот свойства экземпляра категории уже из получения отдельных IPropertyContainer и Iproperty из IModelObject::GetProperties.

Вид скрипта на извлечение собственных свойств объекта модели
Вид скрипта на извлечение собственных свойств объекта модели

3.2 Расчетные характеристики

Окей, с "собственными" свойствами разобрались. Теперь перейдем к расчетным характеристикам, они же Quantity.

Их есть 2 типа - коллекция характеристик IQuantityContainer и отдельное свойство IQuantity. Для получения, собственно, этого отдельного Quantity необходимо знать глобальный идентификатор объекта.

Коды "глобального идентификатора", как и информация к каким категориям объектов что относится отображено в этой табличке. Разумеется, я не буду для каждой категории писать свои экспортеры, а попросту буду пользоваться проверочным методом Contains для свойств объекта, есть ли там нужное мне свойство.

Ну вы поняли как я делаю словари 😂😂😂
Ну вы поняли как я делаю словари 😂😂😂
2 минуты манипуляций с регулярными выражениями в Notepad ++ и готово)))))
2 минуты манипуляций с регулярными выражениями в Notepad ++ и готово)))))

Осталось что? Правильно, заставить пользователя страдать и с логикой Dynamo перебирать характеристики самому реализовать небольшой вспомогательный метод по перебору словаря для поиска расчетных характеристик.

Так, численные значения получили, теперь что же по именам свойств. А имена свойств нечто иное как строковое представление числовых параметров
Так, численные значения получили, теперь что же по именам свойств. А имена свойств нечто иное как строковое представление числовых параметров

То есть как таковых, наименований параметров в Renga нет вообще - есть фиксированные типы (латинские наименования), тип к которым подбирает сам пользователь, а имя параметра получается как транслитерация латинского термина + единицы измерения.

Надо вот только понять, эти все LrngthUnits и пр. пересчитывают параметры если пользовать указал в одном виде (например, в дюймах, а оно хранится в другом месте как метры)?
Ну ... хотя бы так
Ну ... хотя бы так

3.3 Параметры объекта

Ну что, остался последний тип свойств - это параметры объекта, то что характеризует объект геометрии (параметрические свойства).

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

Верхний объект - это IParameterContainer или группа параметров, состоящая из отдельных параметров (IParameter).

При этом в составе определения параметра (IParameter) есть ещё один вложенный интерфейс! Это так называемый IParameterDefinition, определяющий тип параметра и его наименование. Поэтому я реализовал "сложную" структуру для расшифровки IParameter, куда попали его стандартные свойства, + значение (метод) + значения от IParameterDefinition, который хранится ссылкой в параметре "Definition" нашего IParameter.

Также, конечно, я реализовал Enum-структуры для ParameterType и ParameterValueType, в виде словарей.

Вот собственно значения
Вот собственно значения

(Я уже пишу минимум, так как хочу закончится наконец на сегодня с этими свойствами! Не ожидал, что их реализация будет такой дико-долгой).

Общий вид сегодняшнего творчеств
Общий вид сегодняшнего творчеств

4. Резюмируя сказанное выше (они же Итоги)

https://i.playground.ru/p/qmCvByJF51MNPtJpT8g74g.jpeg
https://i.playground.ru/p/qmCvByJF51MNPtJpT8g74g.jpeg

Итак, в данной статья мы рассмотрели варианты работы (чтение) со свойствами Renga. Мы установили, что есть свойства "необъектные" - заложенные в свойствах проекта (типа информация об участке, здании) и отдельно - объектные свойства, которые подразделяются на 3 типа: параметры, расчетные характеристики и сами собственные (дополняемые) свойства.

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

К слову, необъектные свойства извлекаются сразу как IPropertyContainer.

Объектные свойства получают из элемента модели (IModelObject), который выбирается путем перебора всех объектов модели (IModelObjectCollection). Каждое из трех типов свойств имеет свои интерфейсы для выборки:

Параметры IParameterContainer - набор отдельных IParamater (свойства + IParameterDefinition).

Расчетные характеристики IQuantityContainer - набор отдельных фиксированных для данной категории модели параметров IQuantity с возможностью выбора единиц отображения.

Собственные свойства - IPropertyContainer - набор отдельных IProperty. Где-то там же IPropertyDescription для инициации свойства (при создании), но это уже в третьей части.

Все изменения (код) также выкладываю на GitHub-репозиторий этого пакета. Набор скриптом там же в папке DynScripts

Не пропускайте публикации, подписывайтесь на Telegram-канал с тизерами статей.

#dynamo core #renga #renga api #rengabim #dynamo