Найти в Дзене
Хроники Георга

Nwcreate-lib на примере работы с Renga API

Оглавление

1. Небольшое вступление

Интерес к библиотеке nwcreate возник на этапе выгрузки информационной модели из Renga в Navisworks в виде, максимально приближенном к самой модели в Renga (то есть с идентичной геометрией и свойствами). Ввиду отсутствия базовой поддержки в Navisworks IFC-спецификации, единственным вариантом передать "гарантированно верно" был STEP, однако свойства он не поддерживал.

При этом была потребность экспортировать в Navisworks в пакетном режиме для нескольких файлов (да, в Renga есть API для экспорта в IFC но по причине низкой поддержки их в Navis'е, этот способ не подходил).

Интерес к C/C++ возник у меня почти сразу с началом познания C# (где-то с августа 2020г), но по-настоящему начать в нем разбираться я начал где-то с января текущего года (всё-таки не было конкретной боевой задачи, а логика в C/C++ очень отличается от C# особенно в части поддержки библиотек).

Для заголовка
Для заголовка

2. Об исходных данных для работы

Я использовал библиотеку nwcreate под задачу экспорта данных о геометрии и свойствах из Renga - там через API геометрия представляет собой триангуляцию для любых типов объектов (а вот "родными" средствами можно получать и BRep-структуры, но к ним API-доступа нет).

Цвет и материал не являются прямыми свойствами объекта, а связаны с ним через интерфейсы в зависимости от типа объекта (Renga::ObjectTypes).

Свойства объекта (их 3 типа - это расчетные параметры Quantify, параметрические свойства и пользовательские свойства Property) доступны через интерфейс "объекта модели".

Вообще, в Renga есть 2 параллельных интерфейса для доступа к данным - это коллекция объектов с геометрией из 3D-сцены (Renga::IExportedObject3DCollection) и в целом набор объектов модели (Renga::IModelObjectCollection), не обязательно имеющих геометрическое представление (уровни, оси и пр.).

Любой объект "на экспорт" из группы Renga::IExportedObject3DCollection имеет соответствующий ему "объект модели" через своё свойство GetModelObjectId().

С цветом и материалом, как я сказал выше, ситуация сложнее. Часть объектов, например балки, крыша, фундамент имеют интерфейс Renga::IObjectWithMaterial, через который получается назначенный им материал.

Часть объектов, имеющих многослойные пироги, например, стены имеют интерфейс Renga::IObjectWithLayeredMaterial с доступом к набору материалов (но вот связи отдельной IGrid с материалов нет).

Часть объектов типа трасс сетей имеют связку со стилем, где прописан цвет объекта.

Часть объектов модели, имеющих вариативность GridTypes (окна, двери, колонны, полный список тут - https://help.rengabim.com/api/group___grid_types.html) имеют свой тип материала (тут я не особо разобрался и сделал постоянный материал для таких GridTypes для дверей/окон как наиболее часто-встречаемый вид геометрии).

Подробней про цвета и материалы см. в методах renga_data::get_material и renga_data::get_material_grid отсюда.

Доступ к геометрии осуществляется по-видимому через последовательный контейнер типа std::array/std::vector (без функции добавления), что приводит к некоторому ожиданию результата для полигональных/протяженных/гладких объектов (трубы, трассы сетей, лепнины и пр.).

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

3. Nwcreate - логика использования

Библиотека на самом деле довольно простая (если в части геометрии не лезть в BRep, там полная *** по причине полного отсутствия расширенной справки к классу LiNwcTopology.h).

3.1 Инициализация API

Здесь у нас стандартная конструкция (она не жесткая, можно видоизменять - но логика такова, чтобы проверить доступность API библиотеки и если всё хорошо (LI_NWC_API_OK) сделать некое действие (foo_void()).

P.S. За вставку кода через gist.github огромное спасибо Анатолию Краснову в его блоге "Тонкости Renga".

3.2 Путь для сохранения и сцена

Далее, пусть в условном новом методе foo_void() нам надо подготовить сцену (пространство для объектов) и сразу определиться с именем файла, куда сохранится результат.

Особенностью используемых методов является то, что по факту это C++ wrapper над оригинальной С-библиотекой, по причине чего некоторые методы будут ожидать С-шных типов данных (особенно актуально для строк).

Зависимость ЯП (C/C++) от используемых методов можно проследить по наименованию внутренних методов: всё прямо относящееся к C начинается с Li*** и Lt***, а вот для C++ с Lc*** (но не уверен, ко всему ли это относится).

Итак, сцена - вызывается следующей простой конструкцией:

Файловый путь для сохранения представлен типом LtWideString, который есть "const wchar_t*", к чему можно перейти из std::wstring через операцию c_str(); А вот перейти от классической строки std::string к std::wstring можно такой простой операцией:

3.3 Геометрия, потоки и объекты

Итак, у нас есть сцена (LcNwcScene), куда надо записать объекты модели. В своем творчестве я пошел по пути выгрузки объектов с привязкой к группе "Уровень".

Если говорить про выгрузку объектов прямо в сцену, это делается путем простой операции LcNwcScene.AddNode(foo), где foo - может быть как геометрией (LcNwcGeometry), так и объектом (LcNwcGroup).

Положим, что объект у нас - это элемент LcNwcGroup.

К объекту можно присоединить как другой объект, так и геометрию (AddNode())/свойства (AddAttributes()).

Отталкиваясь от логики представления геометрии в Renga реализуем функцию для формирования элемента LcNwcGeometry, который будет отвечать за геометрическое представление в NWC-файле.

Ниже представлен код для этой операции:

Здесь стоит обратить внимание на несколько вложенных элементов LcNwcGroup, где LcNwcGeometry есть лишь у представления IGrid (набор граней триангуляции), формирующий отдельную. плоскость в составе mesh-структуры.

Триангуляция у нас добавляется вот такой процедурой:

Интересная особенность в API nwcreate, что геометрия у нас записывается в рамках "потока" на запись (аналог к примеру - поток для чтения файла в базовых методах языков).

Иными словами, чтобы записать любой объект геометрии, мы должны сделать (и объявить) следующие элементы: LcNwcGeometry, LcNwcGeometryStream и, собственно, выбрать подходящую геометрическую структуру (я делал наборами граней) stream.TriFanVertex(x,y,z);

Экспериментально было установлено, что открытие и закрытие потока для каждой отдельной грани (Renga::Triangle) приводило к полной и красивой геометрии. Если закрывать и открывать поток на формирование геометрии на уровне структуры IGrid, то на кривых поверхностях будут такие баги в конечном NWC:

Пример обработки геометрии (в конечном файле), если LcNwcGeometryStream открывать и закрывать единожды на уровне структуры IGrid
Пример обработки геометрии (в конечном файле), если LcNwcGeometryStream открывать и закрывать единожды на уровне структуры IGrid
Пример обработки геометрии (в конечном файле), если LcNwcGeometryStream открывать и закрывать на уровне составляющей IGrid - Triangle
Пример обработки геометрии (в конечном файле), если LcNwcGeometryStream открывать и закрывать на уровне составляющей IGrid - Triangle

Стоит отметить негативный фактор-следствие доступа к интерфейсам Renga через COM - это низкая скорость доступа к данным, особенно геометрическим.

Ниже приведен график скорости (время в мс, замерялось с помощью библиотеки std::chrono) чтения параметров объектов:

Диаграмма распределения скорости получения интерфейсов данных для цвета, свойств и самого объекта (IModelObjectPtr)
Диаграмма распределения скорости получения интерфейсов данных для цвета, свойств и самого объекта (IModelObjectPtr)
Диаграмма распределения скорости получения интерфейсов данных для геометрии и цвета, свойств, самого объекта (IModelObjectPtr)
Диаграмма распределения скорости получения интерфейсов данных для геометрии и цвета, свойств, самого объекта (IModelObjectPtr)

На базе рисунков выше видно, что запрос геометрии занимает на порядок больше времени чем прочие данные. Я попытался этой обойти первичным чтением геометрии модели и сведением ее в структуры

std::vector<std::vector<std::vector<double>>> grid_geometry;

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

3.4 Свойства, цвет, текстуры

К уже упомянутому LcNwcGroup мы можем привязывать также свойства, цвет, текстуру.

Цвет назначается следующей операцией:

Ввиду того, что в Renga единицей цельной геометрии выступает IGrid, то я привязывал свойство цвета к этому объекту геометрии.

Здесь у нас фигурируют 2 цвета - DiffuseColor и AmbientColor. Это отсылка к режимам освещения сцены в Navisworks:

Настройки освещения
Настройки освещения

Прозрачность (свойство SetTransparency()) назначается через число от 0.0 до 1.0, где 1.0 - 100% прозрачность. Я ставил 0,6 для стекла; остальные в 0.

С текстурами я не баловался, где-то кажется встречал но уже потерял 😂.

Свойства назначаются через отдельный класс LcNwcPropertyAttribute, где может содержаться от одного до нескольких (максимум не знаю) отдельных свойств в виде LcNwcData.

Выглядит всё примерно как на скрине выше.

3.5 Запись в файл

Здесь всё донельзя просто:

4. Реализация и принцип работы

Для того, чтобы воспользоваться библиотекой, она должна быть скопирована в один каталог с исполняемым файлом библиотеки/консольного приложения вместе с вспомогательной папочкой "nwcreate_data" и файликами внутри из Navisworks SDK. Я это реализовал через PostBuild events в настройках проекта в VS.

Чисто мое поверхностное наблюдение - "lcodyplugin.name" содержатся расшифровки для событий Невиса; в "session.nwlic" - какой-то скрипт для программы; в "lcodapi.name" описание API-интерфейсов nwcreate.

В моем случае, я не теряю надежды встроить свой плагин в Renga как библиотеку классов .. но пока не выходит из-за краша программы без логов при её запуске. Поэтому вынужден использовать свой экспортер через консольное приложение, подключаемое к библиотеке через статическую библиотеку и extern-метод (на открытие экземпляра Renga, файла проекта и типа преобразования).

Само приложение доступно на моем профиле GitHub (который я надеюсь мне не заблокируют ...):

GitHub - GeorgGrebenyuk/renga_3d-export: [In progress now!] Plugin to convert renga's model to other formats (such as NWC data format (for Autodesk Navisworks) and etc in future)

Буду рад вашему тестированию утилиты, а в отношении библиотеки nwcreate, надеюсь, я кому-то помог вникнуть в неё (но BRep по-прежнему для меня загадка).

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

#nwcreate #navisworks #autodesk #renga #renga api #nwd #bim #rengabim