Руководство COM-разработчика
Настоящее руководство является авторским переводом справки к Autodesk NavisWorks COM API COM\documentation из состава его SDK с дополнениями (статьи, примеры, примечания) с упором на работу с моделью.
Исходные материалы настоящего руководства расположены в https://github.com/GeorgGrebenyuk/acadDevDocsRu/tree/main/docs/navis/com
Вступление
С помощью настоящего API пользователи могу:
- связать объекты в Navisworks с таблицами Excel или базой данных MS Access;
- связать объекты Navisworks с временной шкалой в MS Project для создания календарного графика строительства;
- запустить приложение Navisworks для заданной модели с заданными положением камеры и параметрами анимации;
- создать видовой экран в AutoCAD на основе вида Navisworks (?);
- составить отчет о коллизиях - провести проверку на коллизии и сформировать HTML-отчеты с растровыми изображениями мест коллизий;
- создать внутренний скрипт с использованием Navisworks ActiveX, который будет доступен из-под Navisworks и выполнять некоторые действия;
COM API позволяет работать в трех различных режимах:
- Расширение возможностей API при разработке пользовательских плагинов для Navisworks;
- COM-автоматизация: программные сценарии с Navisworks (открыть, запустить, сделать ...);
- Создание "элементов управления" в сторонних приложениях (Power Point, Excel и пр.), которые как-то взаимодействуют с Navisworks;
Требования
Для работы с COM API необходимы языки программирования с поддержкой динамической типизации (C#, Visual C++, Python, JS и пр.). Оригинальная справка COM Interface.pdf от 2015г. из состава Navis SDK упоминала только Visual Basic 6.0.
Объектная модель Navisworks и его особенности
Введение - о Navisworks
Navisworks, как программа, предназначен для интерактивного отображения больших моделей со сложной геометрией и\или с большим числом полигонов. Производительность Navisworks зависит от доступного аппаратного обеспечения (ресурсы видеокарты, оперативной памяти, виртуальной памяти).
Традиционный подход к созданию моделей для СОД
В обычных сценариях, если аппаратные ресурсы нельзя повысить, то единственное решение добиться производительности при работе со сборками моделей - либо отображать их частично, либо моделировать объекты с меньшим уровнем детализации (LOD). Далее при просмотре сцены решать, объекты в какой детализации отображать - в слабой или детальной. Решение обычно основывается на статических правилах (расстояние от зрителя), иногда с элементами прогнозирования (попытаться заранее определить, сколько времени займет отображение, и рассчитать оптимальное расстояние видимости).
Процесс оптимизации для моделей сложен. Существуют инструментальные средства, которые автоматически формируют упрощенную модель в более низком LOD. Однако все ещё необходимо самостоятельно решать, какие части объектов упрощать, и сколько упрощенной графики включать в целевую модель. Как правило, улучшение идёт до того момента, пока модель не достигнет достаточной производительности на имеющемся оборудовании. Также необходимо будет пересоздавать модель, если она изменяется или разворачивается на менее производительном оборудовании.
Подход в Navisworks
Navisworks использует другой подход. Отрисовка модели упорядочена таким образом, что сперва отображаются наиболее важные (внешние) части модели. Гарантированная минимальная частота кадров легко достигается остановкой отрисовки графики при превышении временного интервала. Такой подход гарантирует, что всякий раз модель отображается с максимально-возможным качеством для доступных аппаратных характеристик ПК.
Механика графической подсистемы Navisworks устроена так, чтобы упрощать объекты при взаимодействии пользователя с моделью (вращение, перемещение, масштабирование). Как только взаимодействие завершается, подсистема начинает заполнять недостающие части геометрии в порядке их важности. Для пользователя это немного похоже на процесс проявления фотографии. Пользователь может прервать процесс в любой момент, осуществив следующую итерацию изменения положения вида.
Navisworks работает автоматически с исходными данными модели. Не требуется этап редактирования геометрии вручную. Не требуются уровни детализации (LOD). Navisworks автоматически определяет оптимальный состав сцены в соответствии со сложностью модели и доступными аппаратными средствами. Одну и ту же модель можно использовать как на графической рабочей станции, так и на ноутбуке.
Архитектура Navisworks
Navisworks отображает модель, используя логические и пространственные структуры данных.
Логическая структура данных соответствует тому, как пользователь представлял бы себе модель. Так, модель AutoCAD (dwg) будет разделена на слои, а Вхождения блоков обеспечат иерархическую структуру. Модель MicroStation разделена на уровни, а элементы сгруппированы в ячейки, обеспечивающие иерархическую структуру.
Логическая структура модели обычно не является оптимальным решением для быстрого отображения структуры данных, поэтому Navisworks поддерживает отдельную пространственно-организованную структуру данных для оптимальной производительности отображения. Пространственная структура данных автоматически перестраивается при изменении логической структуры.
Логическая структура Navisworks представляет собой граф сцены. Граф сцены описывает иерархически структурированные данные (любые данные могут быть иметь несколько вхождений). Топологически граф сцены представляет собой направленный ациклический граф (DAG). Navisworks поддерживает графы сцен с атрибутами (материалами, преобразованиями и т. д.), прикрепленными к узлам графа. Листовые узлы графа представляют геометрию. Совокупный набор атрибутов, применяемых к каждому геометрическому объекту, наследуется от родительских узлов в графе.
Логическая структура исходной модели преобразуется в эквивалентный граф сцены Navisworks. Каждому элементу SceneBase (то есть узлу или атрибуту) присваивается имя и тип, определенные в процессе преобразования модели. Это позволяет максимально точно связать логическую структуру в Navisworks с исходной САПР-системой. Тип элемента SceneBase определяется двумя строками:
- ClassUserName, которая отображается пользователю Navisworks для описания типа. Эта строка может быть локализована и различаться в разных версиях Navisworks. Ее не следует использовать для идентификации какого-либо конкретного типа элемента SceneBase при программировании;
- ClassName, которая никогда не отображается пользователю и одинакова во всех версиях Navisworks. Ее безопасно использовать для идентификации конкретного типа элемента SceneBase.
При преобразовании в пространственную структуру данных иерархический граф сцены логической структуры упрощается, при этом сохраняется вся информация о геометрии. Каждый экземпляр узла Geometry представляется одним или несколькими фрагментами в пространственной структуре данных. Каждый фрагмент содержит упрощенные версии атрибутов Geometry, Transform и Appearance из исходного графа сцены. Для экономии памяти исходные геометрические данные отбрасываются. ![[Pasted image 20260417132126.png]]
В графе сцены единственный способ идентифицировать конкретный экземпляр — это использовать путь через граф сцены от корневого узла (раздела) до данного узла геометрии. Путь можно рассматривать как набор узлов, где каждый узел является дочерним узлом предыдущего узла в наборе. Пути используются для поддержания связей между логическими и пространственными структурами данных. Каждый узел содержит список всех путей, в которых он используется. Каждый фрагмент поддерживает ссылку на путь, который он представляет. Пути используются во всей системе Navisworks для идентификации объектов внутри модели. Например, выделение представляет собой набор путей, как показано ниже. ![[Pasted image 20260417132230.png]]
Информация о некоторых объектах
Вся модель (документ) Navisworks доступна через COM-оболочку State. С её помощью можно получать доступ к:
- Раздел (Partition), образующий корень графа сцены модели. Если несколько файлов были объединены, корневой раздел будет иметь дочерние разделы, каждый из которых будет представлять один из загруженных файлов;
- Текущему виду AnonView;
- Текущему виду в плане AnonView (Вид - Окна - Вид в плане);
- Текущему виду в сечении AnonView (Вид - Окна - Вид в сечении);
- Текущим параметрам анимации модели;
- Текущему выбору объектов;
- Коллекции сохраненных видов (Вид - Окна - Сохраненные точки обзора);
- Коллекции источников освещения сцены (?);
A collection of scene Lights. - Коллекции наборов выбора объектов (Вид - Окна - Наборы);
- Прочим свойствам сцены;
- Коллекции плагинов, которые расширяют и изменяют интерфейс Navisworks;
Представлено COM-оболочкой nwOpState (наследует функции от 11 разных COM-оболочек с числовыми суффиксами и телом InwOpState);
Partition
Корневой узел графа сцены, созданного путем преобразования одного исходного файла или модели. Разделами описываются корень текущей модели Navisworks, каждый файл, добавленный в модель, внешние ссылки (xrefs), на которые ссылаются явно загруженные файлы. Исходное имя файла (если доступно) хранится в разделе (partition).
Node
Базовая COM-оболочка InwOaNode для различных типов узлов в графе сцены. Есть 3 типа узлов:
- Partition: корневой узел графа сцены (COM-оболочка
InwOaPartition); - Group: узел для группировки элементов. Используйте свойства IsLayer и IsInstance для определения, чем является данная группа (COM-оболочка
InwOaGroup); - Geometry: лист графа сцены, отражает геометрию объекта (COM-оболочка
InwOaGeometry);
Attribute
Представлен COM-оболочкой InwOaAttribute.
К каждому узлу может быть привязано произвольное количество атрибутов. Атрибуты могут использоваться для управления внешним видом узла или просто для связывания с ним дополнительной информации. Все атрибуты внешнего вида, за исключением Transform (COM-оболочка InwOaTansform), наследуются от родительских узлов, при этом используется атрибут, расположенный дальше всего по пути (т.е. ближайший к данному узлу, прим. автора). К атрибутам внешнего вида относятся:
-
Material: Информация о цвете. прозрачности, уровне блеска. Если для COM-оболочки узла
InwOaNode, с которым данный материал связан, методIsOverrideMaterial= true, то этот материал также наследуется вложенными в данный узел элементами (COM-оболочкаInwOaMatrial); -
SemanticPriority: отображение приоритета. Объекты с более высоким приоритетом с меньшей вероятностью будут отброшены при отрисовке геометрии сцены (прим. автора - я не понял, где в API это задаетcя. Возможно, это устаревшая механика);
-
Transform: параметры трансформации геометрии объекта. Параметры преобразований "суммируются" для вложенных объектов (по пути в дереве иерархии); К числу информационных атрибутов относится:
-
NameAttribute: произвольное имя, не строка с неограниченной длиной (COM-оболочка
InwOaNameAttribute); -
Nat64Attribute: 64-битное целое положительное число, диапазон значений -
[0, 18 446 744 073 709 551 615](COM-оболочкаInwOaNameAttribute); -
PropertyAttribute: список различных свойств, см. следующий раздел (COM-оболочка
InwOaPropertyAttribute); -
TextAttribute: текстовый блок, может содержать символы перевода на новую строку (COM-оболочка
InwOaTextAttribute); -
URLAttribute: именованная ссылка на некоторые внешние данные (COM-оболочка
InwOaURLAttribute);
Property
Представлено COM-оболочкой InwOaProperty.
Свойство — это именованное значение определённого типа. Имя задается дважды - отображаемое имя (aka Caption), которое будет видно пользователю - UserName; внутреннее имя name. Значение value может быть одного из пяти типов:
- Дробное
double; - 32-битное целое
int; bool;- Широкая строка -
string(C++std::wstring); - Время и дата - (C# -
DateTime.ToString());
Path
Path (путь) - это последовательность узлов, начинающаяся с раздела в корне графа сцены (Partition) и заканчивающаяся конкретным узлом внутри него, которая (последовательность, прим. автора) однозначно определяет конкретный экземпляр объекта.
Представлен COM-оболочкой `InwOaPath.
Selection и SelectionSet
Selection - набор путей, который определяет полный путь к выбранным объектам графа сцены. Представлен COM-оболочкой InwOpSelection.
SelectionSet - именованный набор Selection. Представлен COM-оболочкой InwOpSelectionSet. В дополнение к выбору Selection в нём содержится информация об отображаемом имени данного набора name, имени пользователя, под которым была создана данная выборка Author, время создания набора Date, комментарии к выборке (в виде COM-оболочки InwCommentsColl).
Fragment
Представлен COM-оболочкой InwOaFragment.
Фрагмент — это представление конкретного экземпляра узла Geometry (в том числе его части) в графе сцены. Большие геометрические объекты могут быть разбиты на несколько фрагментов для более эффективного отображения. Каждый фрагмент предоставляет доступ к:
- Матрице трансформации координат относительно мировых координат модели (метод
GetLocalToWorldMatrix()); - Путь в дереве модели (свойство
path) к данному фрагменту; - Геометрия, которой представлен данный фрагмент (свойство
Geometry); - Способ отображения фрагмента (свойство
Appearance). Из справки доступные значения: Ambient(3),Diffuse(3),Specular(3),Emissive(3),Shininess(1),Transparency(1) ;
AnonView
Представлен COM-оболочкой InwOpAnonView.
Предназначен для работы с видом. COM-оболочка InwOpAnonView предоставляет доступ к:
- Точке обзора (свойство
ViewPoint), представляется в виде COM-оболочкиInwNvViewPoint; - Набору применяемых секущих плоскостей (свойство
ClippingPlanes), представляется в виде COM-оболочкиInwClippingPlaneColl;
ViewPoint
Представлено COM-оболочкой InwNvViewPoint. Характеризует положение камеры и параметры обзора для неё. COM-оболочка InwNvViewPoint позволяет получить:
- Свойство
Camera- предоставляет доступ к камере - на что вы смотрите (описывается COM-оболочкойInwNvCamera); - Свойство
WorldUpVector- задает вектор направления вверх для системы координат просмотра (описывается COM-оболочкойInwLUnitVec3f); - Свойство
FocalDistance- расстояние от точки расположения камеры до целевого объекта (при навигации через Осмотр или Орбиту); - Свойство
LinearSpeed- определяет скорость движения вперед и назад (при навигации через Обход); - Свойство
AngularSpeed- определяет скорость движения (при навигации через Облёт); (❓) - Свойство
Paradigm- определяет формат навигации (Walk = Обход, Orbit = Орбита, Examine = Облёт и пр.); - Свойство
Lighting- определяет режим освещения (в виде одного из значений перечисленияnwELighting); - Свойство
RenderStyle- определяет, как отображается геометрия (каркас, текстуры и пр. в виде одного из значений перечисленияnwERenderStyle);
Camera
Представлена COM-оболочкой InwNvCamera. Хранит информацию, на Что направлен взгляд. COM-оболочка InwNvCamera позволяет получить:
- Свойство
Position- точка положения камеры в пространстве (описывается COM-оболочкойInwLPos3f); - Свойство
Rotation- поворот камеры, задаётся с помощью COM-оболочкиInwLRotation3f; - Свойство
Projection- какая проекция камеры, ортогональная или перспективная, задается в виде перечисленияnwEProjection; - Свойство
HeightField- поле зрения камеры в перспективном режиме, высота в ортогональном (прим. автора, я не понял как это в ортогональном);
SavedView
Представлено COM-оболочкой InwOpSavedView. Базовое представление для различных точек обзора:
- Вид: именованный AnonView (описывается COM-оболочкой
InwOpView); - Папка: коллекция разных точек обзора (описывается COM-оболочкой
InwOpGroupView); - Анимация: последовательность анимации;
- Кадр: отдельный монтажный кадр (описывается COM-оболочкой
InwOpCutView);
Animation
Анимация представляется в виде последовательности видов InwOpView и монтажных кадров InwOpCutView. Каждый Вид выступает в качестве "ключевого кадра" анимации. При воспроизведении анимации Navisworks выполняет переход между ключевыми кадрами. С помощью монтажных кадров можно сделать паузу, а затем перейти к следующему "ключевому кадру-виду"). Анимация представлена COM-оболочкой InwOpAnimView и характеризуется 2 свойствами:
- Свойство
Looped- анимация повторяется после конца, то есть зацикливается (true) или нет (false); - Свойство
Smoothing- задает тип интерполяции между видами, в виде перечисленияnwEAnimSmoothing;
Объекты из части линейной алгебры (...3f)
COM-оболочки с суффиксами "3f" описывают различные вспомогательные конструкции из состава линейной алгебры (прим. автора - название сохранено из оригинальной справки).
InwLVec3f- описывает произвольный вектор в трехмерном пространстве. Задает направление и длину в 3D. Представляется тремя координатами типа double;InwLUnitVec3f- описывает направление в трехмерном пространстве. Представляется вектором единичной длины;InwLPos3f- описывает точку в трехмерном пространстве. Представляется тремя координатами типа double;InwLRotation3f- описывает поворот в трехмерном пространстве. Задается какInwLUnitVec3f- ось Z и угол в радианах вокруг данной оси. Представляется в Navisworks виде кватерниона;InwLPlane3f2- описывает плоскость в трехмерном пространстве. Задается какInwLUnitVec3f- вектор нормали и расстояние от точки начала координат;InwLBox3f- описывает ориентированную по осям координат ограничивающую призму. Представляется в виде двух точекInwLPos3f- минимальной и максимальной;InwLTransform3f- описывает произвольную трансформацию координат в трехмерном пространстве. Представляется в виде матрицы 4х4. Все трансформации должны быть аффинными (см. вики).
Plugin
Navisworks поддерживает подключаемые объекты, расширяющие базовую функциональность. Все реализуют COM-интерфейс InwPlugin. Существует четыре типа таких объектов (плагинов):
- Работа с экспортом
InwExportPlugin- определяет новую команду, которая может быть добавлена в меню экспорта Navisworks, в число инструментов или в контекстное меню; - Работа со свойствами
InwPropertyPlugin- переопределяет порядок отображения и поиска Атрибутов объекта в диалоговых окнах "Свойства", "Поиск"; - Работа с проверками на коллизии
InwClashPlugin- добавляет правила поиска коллизий в Navisworks (прим. автора, не понимаю про что конкретно речь, например, среди методовInwOclClashTestимеетсяIgnoreRuleFlags); - Работа с визуализация
InwPresenterPlugin: Добавляет новые правила на вкладку "Presenter" (Визуализация), они используются для применения текстур к объектам модели;
Подробнее см. описательный раздел в другой статье.
О доступе через COM API
В Navisworks COM существует для 4 различных сценариев:
- Navisworks ActiveX controls;
- Navisworks Automation;
- COM Plug-ins for Navisworks;
- COM 'State' API for Navisworks and ActiveX controls;
Navisworks ActiveX Controls
Данный вид COM-API предназначен для вызова функциональности Navisworks извне (со стороны пользовательских приложений, веб-страниц, иные контейнеры). Можно получать доступ к содержимому моделей, управлять им, открывать в Navisworks файлы. Загрузка файлов осуществляется в отдельном потоке, чтобы предотвратить «зависание» программы, в которой эти файлы были созданы (прим. автора, тут непонятно, или программы, откуда этот скрипт вызывается) File download is done in a separate thread to prevent 'hanging' the containing program..
Используются 2 динамические библиотеки, содержащие COM API, где XX - номер версии Navisworks, для которого библиотеки есть (в оригинальном COM Interface.pdf из SDK они имели номер 14, для Navisworks 2021 номер = 18).
Navisworks Redistributable API Library XX (lcodieDX.dll)
# В csproj строка подключения COM-reference будет примерно такой с поправкой на версию XX
<COMReference Include="NavisworksRedistributableAPI18">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>0</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>1ae0ca20-712a-5761-b4a6-a891c594f278</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
- Этот компонент может быть доступен без установленного Navisworks (достаточно только иметь установленный модуль с этим API, возможно имеется в виду NW Freedom)
This control is supplied in a Windows Installer merge module and also a self-installing executable.; - Доступ к управлению моделью и внутренним данным модели (прим. автора
For control and internal state access) ; - Могут быть открыты только файлы проекта Navisworks (*.nwd);
- Поддержка без ограничений 32bit и 64bit версий ОС (прим. автора на 2026й год уже неактуально);
- Доступны только методы API, способные работать в "безлицензионном режиме", либо все, если лицензия как-то загружена в данное контейнерное приложение `Only certain methods in the API will works as the control runs in ‘unlicensed’ mode unless a special runtime license is embedded in the container application.;
Navisworks Integrated API Library XX (lcodieD.dll)
# В csproj строка подключения COM-reference будет примерно такой с поправкой на версию XX
<COMReference Include="NavisworksIntegratedAPI18">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>0</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>b55d0ec6-97ab-5ff0-b6e3-a62e2a2e2bf9</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
- Этот компонент поставляется вместе с устанавливаемым Navisworks;
- Доступ к управлению моделью и внутренним данным модели (прим. автора
For control and internal state access) ; - 32-битная библиотека будет работать только на 32-битной ОС, соответственно, 64-битная только на 64-битной ОС (прим. автора на 2026й год уже неактуально, всё ушло на 64-битные системы);
- Могут быть открыты различные файлы, не только файлы проекта Navisworks (*.nwd);
- Всё API доступно к вызову, если основной продукт (Navisworks) лицензирован;
Примечание: в оригинальном
COM Interface.pdfиз SDK имеется заметка, что при разработке на 32-битной Visual Studio под 64-битные библиотеки могут быть сложности, и надо вручную регистрировать 32-битные библиотеки черезregsvr32.exe lcodied.dll;
Таким образом, Navisworks Integrated API - это способ взаимодействия с Navisworks из другого процесса с полным доступом к имеющемуся API.
MDI / SDI Режимы
Для каждой из упомянутых выше библиотек управления (Redistributable и Integrated) имеются 2 режима работы с ограничениями:
MDI: Multiple Document Support
- В одном процессе может использоваться несколько элементов управления;
- Поддержка плагинов отсутствует. Поэтому плагины, расширяющие экспорт и работу с рецензированием недоступны;
SDI: Single Document Support
- В одном процессе может использоваться только один элемент управления;
- Поддержка плагинов имеется;
Встраивание в HTML
Возможно встроить в HTML-код страницы сценарий, обращающийся к COM API Navisworks. Для внедрения в страницу функциональности просмотра некоторой модели. В современной практике это не используется, в угоду WEB API различных систем (в отношении Autodesk -- Forge, Autodesk Docs и т.д.).
<object
id="NavisworksControl"
classid="CLSID:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" <!-- Тот самый CLSID -->
codebase="http://ваш_сайт/Installers/NavisworksActiveX.exe" <!-- Откуда качать, если нет -->
width="800"
height="600">
<param name="FileName" value="model.nwc"> <!-- Какой файл открыть -->
</object>
- CLSID (classid) - это Guid, характеризующий целевую библиотеку (см. примеры выше для cspoj)
- codebase - это путь для загрузки элемента управления, если в данной системе отсутствует компонент для указанного classid;
- данный подход работает только в Windows (т.к. вызывается внешний COM);
COM 'State' API for Navisworks and ActiveX controls
Элементы управления Navisworks и его ActiveX используют общий API для доступа к внутренним функциям Несмотря на сходство, некоторые интерфейсы и классы могут присутствовать только в одной DLL-библиотеке. Ниже основные особенности COM API и рекомендации по работе с ним.
Имена COM-интерфейсов
Каждый объект имеет только один соответствующий ему интерфейс, содержащий все методы. Имя интерфейса для конкретного объекта аналогично имени самого объекта. Например, объект "nwOpState" имеет интерфейс InwOpState.
Объект верхнего уровня
Объект "nwOpState" — это объект верхнего уровня, отвечающий за состояние модели Navisworks. Ниже него находится иерархия других объектов, доступных через свойства, методы и коллекции. Состояние ("nwOpState") также позволяет обрабатывать COM-события, когда происходят различные действия в пользовательском интерфейсе Navisworks.
Наследование методов интерфейсов
Интерфейс каждого объекта напрямую или косвенно наследуется от InwBase. Он содержит стандартные методы. Например, InwOpState наследуется от InwBase. Таким образом, он содержит все методы и свойства InwBase.
Коллекции
В практике COM все индексы начинаются с 1. Все коллекции имеют стандартный набор методов, но некоторые из них могут быть не реализованы для некоторых коллекций. Одна коллекция может содержать различные типы объектов. Обычно все они наследуются от одного общего типа объекта.
Идентификация объектов
Интерфейс InwBase содержит readonly-свойство ObjectName. Его можно использовать для идентификации неизвестных объектов вместо выполнения операций "QueryInterface" или "Set" в Visual Basic или as в .NET. Это единственный способ идентификации объектов в языках с динамической типизацией.
Создание новых объектов
Объекты Navisworks нельзя создать м помощью директивы new. Вместо этого используйте метод ObjectFactory у COM-оболочки состояния документа InwOpState.
Перечисления
В языках с динамической типизацией нельзя использовать встроенные перечисления (enum) из COM API. Для перехода к ним из строкового представления используйте метод GetEnum у у COM-оболочки состояния документа InwOpState, это позволит сделать код более читаемым.
При разработке на .NET такой проблемы нет, enum можно использовать без ограничений.
Сравнение объектов
Если вы хотите установить, ссылаются ли 2 ссылки на один и тот же объект, не сравнивайте их COM-оболочки, вместо этого вызывайте метод PtrEquals у COM-оболочки состояния документа InwOpState.
Navisworks Automation
В Navisworks реализована базовая поддержка автоматизации. Цель состоит в том, чтобы позволить пользователям программно запускать и управлять продуктом с помощью скриптовых языков (Visual Basic, VBA или VBScript прим. автора - из оригинальной справки). Пользователь также может получать доступ к внутреннему состоянию приложения и управлять им (т.е. работать с COM-оболочкой модели InwOpState).
Об установке нескольких версий Navisworks
С версий Navisworks 2017 каждый из продуктов (Manage и Simulate) может быть установлен параллельно. Для целей COM-автоматизации они идентичны, и фактически GUID'ы (CLSID) для каждого продукта идентичны. При запуске через COM запускается тот продукт, который был установлен или запущен последним. Например, если вы установили Navisworks Manage 2017, а затем установили Navisworks Simulate 2017, то при запуске продукта через COM запустится Navisworks Simulate. Но если пользователь впоследствии запустит Navisworks Manage, то при выполнении следующего скрипта с COM запустится именно он.
Navisworks Licensing
Какая-либо COM-автоматизация доступна только для лицензионных версий Navisworks.
Подключение к процессу
Осуществляется по идентификатору приложения "Navisworks.Document"
Типы COM-библиотек
- Navisworks Automation Library XX - для взаимодействия с приложением Navisworks;
- Navisworks Integrated API Library XX - для взаимодействия с моделью в Navisworks;
COM-Plugins
Для Navisworks можно создавать COM-плагины. Они расширяют базовую функциональность продукта и доступны на соответствующих вкладках ленты продукта. Прим. автора - имеется подозрение, что плагины ограничены языком Visual Basic (по документации).
Существует 4 типа плагинов, подробнее см. раздел про них. Каждый плагин должен реализовывать базовый COM-интерфейс для плагина InwPlugin. Указывается имя плагина, его настройки в зависимости от типа плагина. Плагины могут быть созданы в виде DLL-файлов или исполняемых файлов. Преимущество исполняемых файлов заключается в возможности отображения немодальных диалогов.
В процессе инициализации плагина в Navisworks вы передаете плагину набор флагов. Это будет влиять на его поведение. Для каждого плагина можно добавить страницу параметров. На ней можно отображать пользовательские свойства типов CLng (int 64), CDbl (double), CBool (bool), CDate (DateTime) и CStr (string).
Export-plugin
Плагины экспорта должны реализовывать интерфейс InwExportPlugin. Плагины экспорта позволяют осуществлять полностью настраиваемый экспорт данных путем добавления их в меню Navisworks. Основной метод, заслуживающий внимания, — это iExport, который будет вызываться при экспорте. Автор плагина может использовать API COM-оболочки приложения InwOpState и всю мощь VB для выполнения любых необходимых действий. Флаги позволяют добавлять пункты меню в меню «Вид», «Вывод» и «Надстройки». Также, в альтернативу добавления кнопок на ленты, вы можете использовать подписки на события InwOpState для отслеживания происходящих событий в модели.
Clash Detective Plug-ins (проверки на коллизии\пересечения)
Плагины, добавляющие исключения при обработке коллизий, должны реализовывать интерфейс InwClashPlugin. Плагины позволяют игнорировать определенные конфликты (для некоторых заданных условий). При обнаружении каждого конфликта в Navisworks у загруженных плагинов с данным типом будет вызываться метод iIgnore с целью оставить или отбросить обнаруженную коллизию.
Property Plug-ins (плагины, работающие со свойствами)
Плагины свойств должны реализовывать интерфейс InwPropertyPlugin. Плагины свойств позволяют переопределять то, что отображается при щелчке правой кнопкой мыши по объекту. Результат может представлять текстовую строку (реализация iContentsText) или список свойств (реализация iContentsProperties).
Presenter Plug-ins
Плагины для "Визуализации" должны реализовывать интерфейс InwPresenterPlugin. Плагины используются для применения текстур к модели. Загруженные плагины отображаются на вкладке «Правила» на вкладке "Визуализация".
Загрузка плагинов
В настоящее время (прим. автора - на 2017 версию как минимум) единственный способ заставить Navisworks загружать COM-плагины — это добавить их строку «ProgId» в реестр. Настроек в UI для этого не предусмотрено. Для загрузки плагинов необходимо перезапустить Navisworks.
Поскольку каждый продукт начиная с Navisworks 2017 может быть установлен параллельно, у каждого из них будет свой набор записей в реестре. Это означает, что вам необходимо зарегистрировать свой плагин в каждой версии продукта, с которой он совместим. Ключи реестра для каждого плагина показаны в таблице ниже.
| Product | Registry Key |
|---|---|
| Navisworks Manage 2017 | Software\Autodesk\Navisworks Manage\14.0\COM Plugins |
| Navisworks Simulate 2017 | Software\Autodesk\Navisworks Simulate\14.0\COM Plugins |
| Navisworks Manage 2021 64-bit | Software\Autodesk\Navisworks Manage x64\18.0\COM Plugins |
| Добавьте строковые значения, соответствующие идентификаторам программ (progIds) вашего плагина, в соответствующий ключ реестра для данного продукта. |
Программная работа с Navisworks
Данный раздел содержит примеры и рекомендации для программного взаимодействия с Navisworks, моделью и иными механиками продукта. Настоящий раздел полностью авторский и не присутствует в каком-либо в виде в официальной справке.
Приложение Navisworks
О функциональности приложения По существу, доступная функциональность COM-оболочки приложения Navisworks ограничивается следующими действиями:
- открыть проект Navisworks (*.nwd; *.nwf);
- подключить к проекту данные (аналог команды "Главная - Добавить - ... ");
- сохранить проект в файл;
- получить доступ к содержимому проекту (COM-оболочка
InwOpState);
Примечание: добиться работы метода AppendFile у меня не получилось - выбрасывало странное исключение про файл.
Наиболее важное доступное действие - это получение доступа к содержимому проекту (COM-оболочка InwOpState), т.к. именно с ней идут все остальные действия с COM API.
О получении приложения Есть 2 варианта взаимодействия с API - для случая внутреннего подключения через .NET API и в случае внешнего взаимодействия. Рассмотрим 2 эти варианта в отдельности
Внешнее взаимодействие
Рассмотрим случай подключения к Navisworks из-под стороннего процесса, создания нового процесса и переходу к COM из-под .NET API
Navisworks, как приложение, описывается отдельной библиотекой типов под названием "NavisworksAutomation". Её необходимо подключить к проекту вручную. Также необходимо подключить Intergated API. ![[Pasted image 20260418201504.png]]
Приложение Navisworks описывается COM-оболочкой NavisworksAutomationAPI18.Document (где 18 - номер версии Navisworks, в данном случае 2021; приведение нужно скорее для знакомства с API, можно использовать и dynamic, прим. автора). У любого приложения Navisworks процесс имеет постоянный префикс Navisworks.Document. По нему можно идентифицировать запущенные процессы, либо создать новый процесс. В табличке ниже приведена информация о соответствии версии NW и ProgId - она фактически "линейная".
| Версия NW | Соответствующий ProgId | Примечание |
|---|---|---|
| Navisworks 2015 | Navisworks.Document.12 | |
| Navisworks 2016 | Navisworks.Document.13 | |
| Navisworks 2017 | Navisworks.Document.14 | |
| Navisworks 2018 | Navisworks.Document.15 | |
| Navisworks 2019 | Navisworks.Document.16 | |
| Navisworks 2020 | Navisworks.Document.17 | |
| Navisworks 2021 | Navisworks.Document.18 | |
| Navisworks 2022 | Navisworks.Document.19 | 19.1 : 2022.1 |
| Navisworks 2023 | Navisworks.Document.20 | 20.1 : 2023.1 |
| Navisworks 2024 | Navisworks.Document.21 | |
| Navisworks 2025 | Navisworks.Document.22 | |
| Navisworks 2026 | Navisworks.Document.23 | |
| Navisworks 2027 | Navisworks.Document.24 |
Подключение к запущенному Navisworks
Для подключения к приложению Navisworks (если оно запущено) из внешнего процесса необходимо найти среди запущенных процессов начинающиеся на Navisworks.Document и далее использовать его.
Хорошая реализация процесса получения запущенных COM-приложений приведена тут. На всякий случай приведу её листинг ниже:
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
public class COM_Interaction
{
private COM_Interaction() { }
public static List<string> GetCOMProcesses()
{
StringBuilder SB = new StringBuilder();
List<string> processes = new List<string>();
foreach (var moniker in EnumRunningObjects())
{
List<string> t1 = GetMonikerString(moniker).Split('\t').ToList();
processes = processes.Concat(t1).ToList();
}
return processes;
}
private const int S_OK = 0x00000000;
[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(uint reserved, out IRunningObjectTable pprot);
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);
private static void OleCheck(string message, int result)
{
if (result != S_OK)
throw new COMException(message, result);
}
private static IEnumerable<IMoniker> EnumRunningObjects()
{
IRunningObjectTable objTbl;
OleCheck("GetRunningObjectTable failed", GetRunningObjectTable(0, out objTbl));
IEnumMoniker enumMoniker;
IMoniker[] monikers = new IMoniker[1];
objTbl.EnumRunning(out enumMoniker);
enumMoniker.Reset();
while (enumMoniker.Next(1, monikers, IntPtr.Zero) == S_OK)
{
yield return monikers[0];
}
}
private static bool TryGetCLSIDFromDisplayName(string displayName, out string clsid)
{
var bBracket = displayName.IndexOf("{");
var eBracket = displayName.IndexOf("}");
if (bBracket > 0 && eBracket > 0 && eBracket > bBracket)
{
clsid = displayName.Substring(bBracket, eBracket - bBracket + 1);
return true;
}
else
{
clsid = string.Empty;
return false;
}
}
private static string ReadSubKeyValue(string keyName, RegistryKey key)
{
var subKey = key.OpenSubKey(keyName);
if (subKey != null)
{
using (subKey)
{
var value = subKey.GetValue("");
return value == null ? string.Empty : value.ToString();
}
}
return string.Empty;
}
private static string GetMonikerString(IMoniker moniker)
{
IBindCtx ctx;
OleCheck("CreateBindCtx failed", CreateBindCtx(0, out ctx));
var sb = new StringBuilder();
string displayName;
moniker.GetDisplayName(ctx, null, out displayName);
sb.Append(displayName);
sb.Append('\t');
string clsid;
if (TryGetCLSIDFromDisplayName(displayName, out clsid))
{
var regClass = Registry.ClassesRoot.OpenSubKey("\\CLSID\\" + clsid);
if (regClass != null)
{
using (regClass)
{
sb.Append(regClass.GetValue(""));
sb.Append('\t');
sb.Append(ReadSubKeyValue("ProgID", regClass));
sb.Append('\t');
sb.Append(ReadSubKeyValue("LocalServer32", regClass));
}
}
}
return sb.ToString();
}
}
Пример работы с листингом выше может выглядеть так (для метода GetNWInstance):
using System.Runtime.InteropServices;
[DllImport("ole32.dll")]
public static extern int GetActiveObjectExt(ref Guid rclsid, IntPtr reserved, [MarshalAs(UnmanagedType.Interface)] out object ppunk);
public static object? GetNWInstance()
{
foreach (string comProcId in COM_Interaction.GetCOMProcesses())
{
if (comProcId.Contains("Navisworks.Document."))
{
var type = Type.GetTypeFromProgID(comProcId);
var guid = type.GUID;
object obj;
int result = GetActiveObjectExt(ref guid, IntPtr.Zero, out obj);
return obj;
}
}
return null;
}
Примечание: в листинге выше используется обращение к GetActiveObjectExt, это универсальная конструкция для .NET5+ и .NET Framework.
Запуск нового экземпляра Navisworks
Если на данном ПК установлен любой Navisworks, то можно запустить его экземпляр для заданной версии ProgID (см. табличку в начале раздела).
string nwProgID = "Navisworks.Document.18"; // for NW 2021
var type = System.Type.GetTypeFromProgID(nwProgID);
object nwApp = System.Activator.CreateInstance(type);
Подключение к COM из-под .NET API
Для этого в .NET API имеется специальный класс Autodesk.Navisworks.Api.ComApi.ComApiBridge (из Autodesk.Navisworks.ComApi.dll), а само COM API доступно через пространство имён Autodesk.Navisworks.Api.Interop. Тогда переход к COM-оболочки модели будет выглядеть как:
using ComBridge = Autodesk.Navisworks.Api.ComApi.ComApiBridge;
using COMApi = Autodesk.Navisworks.Api.Interop.ComApi;
COMApi.InwOpState oState = ComBridge.State;
Модель (проект) Navisworks
Прим. автора - не уверен, как это правильно называется, называю из логики работы.
Проект у приложения Navisworks существует в единственном экземпляре и характеризует некоторую загруженную модель с рядом файлов, точек обзора, настройками визуализации и т.д. Функции работы с проектом доступны через COM-оболочку InwOpState с суффиксами до 11 включительно. Возможно, так развивалось API - путем добавления новой функциональности в новую COM-оболочку с соответствующим суффиксом. При использовании динамической типизации (dynamic) нет разницы к чему приводить полученный у приложения State - все методы "номерных" оболочек можно применять и к базовому InwOpState.
Для удобства, можете считать, что модель Navisworks описывается COM-оболочкой InwOpState11 , которая наследует все методы от базовой InwOpState. Далее будем рассматривать функциональность InwOpState без привязки к версии (фактически, будем говорить о InwOpState11).
Для удобства, в таблице ниже приведена информация, каким элементам UI соответствуют методы COM-оболочек InwOpState** и краткая справка, что они делают.
Как читать третью колонку:
- "✅" - если для метода COM-оболочки имеется прямое соответствие в UI;
- "🔧" - различные внутренние технические методы;
- "❓" - автор не уверен в точной идентификации;
| Метод интерфейса InwOpState | Чему соответствует в Naviworks | UI |
|---|---|---|
| InwOpState | ||
| NumTriangles | Главная - Проект - Окно "Статистика сцены", числовое значение напротив "Треугольников, линий и точек:" | ✅ |
| GetBoundingBox | Главная - Проект - Окно "Статистика сцены", значение напротив "Ограничивающий параллелепипед:" | ✅ |
| GlobalAmbient | Контекстное меню модели - Параметры файла - Освещение сцены - Ползунок для рассеянного цвета | ✅ |
| SceneLights | Прямого соответствия нет. Информация о расположении источников света в загруженных файлах (например, камеры (?) в DWG) | |
| CreatePlugin | Технический метод, создание пользовательского COM-плагина | 🔧 |
| Plugins | Технический метод, перечисление всех пользовательских плагинов | 🔧 |
| SavedViews | Вид - Рабочее пространство - Окна - Сохраненные точки обзора | ✅ |
| NdxArray2SavedView | Технический метод, поиск сохраненной точки обзора по внутреннему пути | 🔧 |
| SavedView2NdxArray | Технический метод, получение пути для сохраненной точки обзора | 🔧 |
| NdxArray2Node | Технический метод, получение узла дерева по внутреннему пути | 🔧 |
| SelectionSets | Вид - Рабочее пространство - Окна - Наборы | ✅ |
| BeginEdit | Технический метод, аналог транзакций в API (начало работы) | 🔧 |
| EndEdit | Технический метод, аналог транзакций в API (конец работы) | 🔧 |
| ObjectFactory | Технический метод, создание новых экземпляров объектов всех поддерживаемых типов | 🔧 |
| CurrentView | То, как сейчас видна модель в Naviworks. Численные параметры камеры в "Точка обзора - Редактирование точки обзора - Текущий вид" | ✅ |
| CurrentSelection | Набор выбранных объектов в Naviworks | ✅ |
| CurrentPartition | Первый загруженный в модель файл (в Дереве выбора) | ✅ |
| GetEnum | Технический метод, для языков с динамической типизацией получить значение перечисления по его строковому варианту | 🔧 |
| FrameRate | Контекстное меню модели - Параметры файла - Скорость - Частота кадров | ✅ |
| ZoomInCurViewOnSel | Контекстное меню - Показать выбранные (если в модели выбран 1 или несколько объектов) | ✅ |
| ZoomInViewOnSel | "Клик" на данной сохраненной точке обзора в окне "Сохраненные точки обзора" | ✅ |
| OverrideColor | Контекстное меню модели - Переопределить - Переопределить цвет (если выбран хотя бы 1 объект в модели) | ✅ |
| OverrideTransparency | Контекстное меню модели - Переопределить - Переопределить прозрачность (если выбран хотя бы 1 объект в модели) | ✅ |
| OverrideReset | Контекстное меню модели - Сбросить для элемента - Сброс внешнего вида (если выбран хотя бы 1 объект в модели у кого был переопределен цвет и\или прозрачность) | ✅ |
| OverrideResetAll | Прямого соответствия нет. Сбрасывает для всех объектов имевшие место переопределения цвета и прозрачности | 🔧 |
| SelectionHidden | Контекстное меню у выбранного набора элементов - Скрыть (true) и Показать (false) | ✅ |
| SelectionRequired | Контекстное меню у выбранного набора элементов - Обязательный (true = галочка стоит, false = галочка не стоит) | ✅ |
| HiddenItemsResetAll | Контекстное меню модели - Сбросить все - Показать все | ✅ |
| RequiredItemsResetAll | Контекстное меню модели - Сбросить все - Сделать все необязательными | ✅ |
| EventsEnabled | Технический метод. Временное отключение и включение обработки событий действий с объектами (для повышения производительности) | 🔧 |
| CreatePicture | Точка обзора - Экспорт - Изображение Для данной точки модели (со стороны API данная точка доступна через метод CurrentView) | ✅ |
| CurrentAnimation | Анимация - активная анимация (среди списка) | ✅ |
| BackgroundColor | Контекстное меню модели - Фон - Цвет | ✅ |
| HeadlightAmbient | Контекстное меню модели - Параметры файла - Лобовое освещение - Ползунок для рассеянного цвета (?) | ✅❓ |
| HeadlightIntensity | Контекстное меню модели - Параметры файла - Лобовое освещение - Ползунок для направленного цвета (?) | ✅❓ |
| SeekSelection | Технический метод, запрос у пользователя выбора объектов | 🔧 |
| CurrentPlanView | Вид - Рабочее пространство - Окна - Вид в плане | ✅ |
| CurrentSectionView | Вид - Рабочее пространство - Окна - Вид в сечении | ✅ |
| AreaCullThreshold | Контекстное меню модели - Параметры файла - Отсев - Площадь - численное поле "Минимальное количество пикселов для отсева" | ✅ |
| MaxNearDistance | Контекстное меню модели - Параметры файла - Отсев - Площадь отсечения - Ближняя - численное поле "Расстояние" для фиксированного значения | ✅ |
| MinFarDistance | Контекстное меню модели - Параметры файла - Отсев - Площадь отсечения - Дальнее - численное поле "Расстояние" для фиксированного значения | ✅ |
| ApplyView | Технический метод. Переход к заданному виду (с данными настройками камеры) | 🔧 |
| TwoSided | Прямого соответствия нет. Как подсказывает ИИ, где-то в настройках визуализации во встроенном рендере от Autodesk. Наиболее ближе по смыслу Точка обзора - Стиль визуализации - Режим - Полная визуализация | ❓ |
| ViewAll | Контекстное меню модели - Показать все | ✅ |
| StopMovement | Прямого соответствия нет. Прерывает любую анимацию (?) | ❓ |
| InwOpState2 | ||
| OverrideTransform | Контекстное меню - Переопределить - Переопределить преобразование (если выбран хотя бы 1 объект в модели) | ✅ |
| OverrideTransformReset | Контекстное меню модели - Сбросить все - Отменить преобразование (если выбран хотя бы 1 объект в модели) | ✅ |
| OverrideTransformResetAll | Контекстное меню модели - Сбросить все - Преобразования | ✅ |
| InwOpState3 | ||
| CurrentFindSpec | Вид - Рабочее пространство - Окна - Поиск элементов Имеются в виду параметры поиска ( InwOpFindSpec):- выборка (где искать) selection;- условия поиска Conditions;- "До первого найденного" true в ResultDisjoint;- Выпадающий список "Найти" - SearchMode, перечисление nwESearchMode | ✅ |
| GetAttributeProperties | Вспомогательный метод. Преобразование атрибута в перечень свойств | 🔧 |
| StdName | Вспомогательный метод. Получение внутреннего имени объекта. Контекстное меню модели - Глобальные параметры - Интерфейс - Разработчик - Показывать внутренние имена свойств (если это выбрано) | 🔧✅ |
| SetOverrideURL | ||
| GetOverrideURL | ||
| OverrideURLReset | ||
| OverrideURLResetAll | ||
| DeleteSelectedFiles | Сбросить выбор объектов в модели | ✅ |
| GlobalProperties | Вспомогательный метод. Возвращает настройки модели прим. автора - все настройки про URL | 🔧❓ |
| URLsEnabled | ||
| IsComposite | ||
| GetMeasureFirstPos | ||
| GetMeasureEndPos | ||
| GetMeasureDiff | ||
| GetMeasureValue | ||
| GetGUIPropertyNode | ||
| SmartTagsEnabled | ||
| InwOpState4 | ||
| GetFirstInstanceOfNode | Технический метод. Возвращает первый узел дерева для данного внутреннего пути | 🔧 |
| ZoomInCurViewOnBoundingBox | Вид - Включить сечение (настроить рамку и масштаб) | ✅ |
| SmartTagText | Технический метод. Получение содержимого тэга по внутреннему пути Аналог просмотра тэга вручную (?) | 🔧❓ |
| GetIOPluginOptions | 🔧 | |
| DriveIOPlugin | 🔧 | |
| PluginOptions | 🔧 | |
| PluginOption | 🔧 | |
| InwOpState5 | ||
| CheckLicense | Верхняя панель функций - Справка - О программе ... | ✅ |
| InwOpState6 | ||
| StartInteractive | 🔧 | |
| EndInteractive | 🔧 | |
| GetCurrentFilename | Панель Свойства - Элемент - Имя файла источника (для выбранного узла из Дерева выбора, соответствующего файлу) | ✅ |
| InwOpState7 | ||
| LoadedFileCount | Число загруженных в модель файлов. В UI не отображается, но можно посчитать вручную из Дерева выбора | ✅🔧 |
| LoadedFileFromNdx | Технический метод. Получение информации о загруженном файле Интерактивный выбор в Дереве выбора по индексу | ✅🔧 |
| LoadedFileFromPath | Технический метод. Получение информации о загруженном файле по внутреннему пути | 🔧 |
| InwOpState8 | ||
| SelectionSetsEx | Вероятно, какая-то безопасная версия метода SelectionSets.По сути, перечень Вид - Рабочее пространство - Окна - Наборы | 🔧 |
| FileVersion | 🔧 | |
| InwOpState9 | ||
| GetProductInfo | Заголовок приложения Navisworks (то что отображается в шапке приложения) | ✅ |
| InwOpState10 | ||
| PtrEquals | Технический метод. Сравнение двух объектов | 🔧 |
| X64PtrVar | Технический метод. Получение указателя на объект | 🔧 |
| X64PtrLongs | Технический метод. Сравнение двух объектов (по указателям) | 🔧 |
| InwOpState11 | ||
| OverrideTransformEx | Вероятно, какая-то безопасная версия метода OverrideTransform.Контекстное меню - Переопределить - Переопределить преобразование (если выбран хотя бы 1 объект в модели) | ✅🔧 |
О базовых представлениях объектов
Перед тем, как переходить к рассмотрению объектов, необходимо уделить внимание двум базовым COM-оболочкам, описывающим объекты в Navisworks -- InwOaSceneBase и InwBase.
Первая оболочка InwOaSceneBase характерна для непосредственно структурных объектов (видимых в Дереве выбора в NW) и атрибутов объектов (т.к. наследуется у InwOaNode и InwOaAttribute). Вторая оболочка InwBase наследуется широким перечнем объектов, тех, что сохраняются в памяти файла проекта Navisworks (nwf; nwd).
InwOaSceneBase
Опишем далее состав доступных методов у данного интерфейса:
- UserName - отображаемое имя элемента (привычный заголовок);
- ClassUserName - тип элемента;
- ClassName - внутреннее имя типа элемента;
Например, для загруженного в модель NW файла "Pyramid.nwc" (он будет описываться с помощью интерфейса InwOaPartition) выдача свойств выше будет следующей:
ClassName: LcOaPartition,
UserName: Pyramid.nwc,
ClassUserName: Файл
Все эти значения можно увидеть на стандартной панели "Свойства" во вкладке "Общие" в Navisworks. UserName - свойство "Имя", ClassUserName - свойство "Тип". Чтобы увидеть ClassName необходимо включить режим "Глобальные параметры - Интерфейс - Разработчик - Показывать внутренние свойства", в свойствах появится "Внутренний тип", и его значение будет соответствовать значению ClassName.
Пользовательское имя (UserName) по API доступно к изменению. Также можно переопределить значения ClassName и ClassUserName, воспользовавшись методом Rename с соответствующими аргументами в указанном порядке -- ClassName и ClassUserName.
InwBase
Опишем далее состав доступных методов у данного интерфейса:
| Метод или свойство | Что делает | Примечание |
|---|---|---|
| nwReadOnly | Возвращает признак, доступен ли объект и содержимое только для чтения | Если свойство = true, то его свойства нельзя изменить через API |
| nwInvalidated | Возвращает признак, является ли объект и его содержимое недействительными (напр., ссылка на объект устарела или он был удален из исходных данных) | |
| nwHandle | Уникальный идентификатор (хэндл) объекта в памяти сессии Navisworks | ⚠️Не доступен к получению из внешнего процесса Ошибка "Отказано в доступе. (Исключение из HRESULT: 0x80070005 (E_ACCESSDENIED))" |
| nwID | Числовой идентификатор объекта | ⚠️Не доступен к получению из внешнего процесса Ошибка "Отказано в доступе. (Исключение из HRESULT: 0x80070005 (E_ACCESSDENIED))" |
| Xtension() | Позволяет получить доступ к "Расширениям" (Extensions) объекта. Это механизм для хранения пользовательских данных или метаданных, которые не входят в стандартные свойства элемента. | |
| nwProcess | Возвращает номер процесса в системе, где существует объект | |
| nwThread | Возвращает номер потока процесса, где сейчас существует объект | |
| nwInit() | Вызывается для инициализации объекта. Вызывать в случае создания элемента через state.ObjectFactory | |
| nwInvalidate() | Принудительно помечает объект как недействительный. Чтобы заставить NW пересчитать для него свойства или обновить геометрию | |
| nwLock | Управление блокировкой объекта. Для безопасных (в памяти) изменений объекта, особенно если он nwReadOnly = true | |
| nwOwn | Возвращает или задает "право владения объектом" - ручные действия с объектом для очистки его из памяти, если true. | Для работы с временными объектами |
| ObjectName | Имя типа объекта | Не то же самое, что InwOaSceneBase.UserName. Что-то похожее, но другое (созвучное с ним). |
| Copy() | Создает копию данного объекта |
Ниже в таблица приведена справочная информация, какими объектами данный интерфейс наследуется.
| Чем наследуется | Что это за объекты |
|---|---|
| InwGUIAttribute | Атрибут приложения |
| InwOpState | Модель NW |
| InwLBox3f | Геометрия. Ограничивающая призма |
| InwLBaseVec3f | Геометрия. Представление 3D-вектора |
| InwOpSavedView | Сохраненная точка обзора |
| InwOaSceneBase | Базовое представление для объектов и атрибутов (см. выше) |
| InwOpAnonView | Любой именованный вид |
| InwNvViewPoint | Точка обзора NW |
| InwNvCamera | Параметры камеры NW |
| InwLRotation3f | Геометрия. Вектор направления и угол вращения |
| InwOpSelection | Выборка объектов NW |
| InwOaPath | Внутренние пути к данным NW |
| InwLTransform3f | Геометрия. Параметры преобразования координат |
| InwOpFindSpec | Настройки поиска объектов в NW |
| InwOaPropertyVec | Набор свойств |
| InwURLOverride | Переопределение тэга (?) |
| InwGlobalProperties | Обобщенные настройки проекта (что-то про ссылки) |
| InwSmartTagsOpts | Настройки тэгов (?) |
| InwGUIPropertyNode | Оболочка для получения коллекции атрибутов приложения |
| InwOpFind | Найденный объект по условиям (вроде для спецификаций) |
| InwOpFindCondition | Поисковое условие |
| InwOaCommonLight | Базовое представления источника освещения |
| InwOaProperty | Базовое представление определения свойства |
| InwOaClipPlane | Плоскость сечения |
| InwLPlane3f | Геометрия. Определение плоскости |
| InwOaFragment | Часть геометрии объекта (из-под него предоставляется доступ к чтению геометрии) |
| InwOpComment | Комментарий на модели |
| InwOpProgress | Вспомогательное. Прогресс выполнения задачи |
| InwOpSelectionSet | Именованный набор выбора (аналог в окне "Наборы") |
| InwURL | Именованная ссылка |
| InwURLCategory | Набор именованных ссылок (категория?) |
| InwOpInternalPlugin | Вспомогательное. |
| InwNvViewer | Параметры реалистичности при просмотре (?) |
| InwSimpleVertex | Вспомогательное. Точка геометрии |
| InwSelectionSetFolder | Доступ к наборам выборки |
| InwPlugin_Site | Вспомогательное. Место плагина в меню (?) |
| InwOclTestResult | Результат проверки на коллизии |
| InwOclClashTest | Параметры проверки на коллизии |
| InwOpClashElement | Коллизирующий элемент |
| InwUInt32Vector | Геометрия. Вектор с координатами int32 |
| InwOpUserFindSpec | Пользовательские настройки поиска объектов |
| InwOpUserSelectionTreeSpec | Вспомогательное |
| InwOpUserSelectionTreePlugin | Вспомогательное |
Работа с загруженными файлами и объектами
Рассмотрим, как получить перечень данных в модели (объектов с иерархией, обладающих свойствами и геометрией). То есть методам API, которые соответствуют "Дереву выбора" в UI Navisworks.
Первоначально необходимо получить перечень загруженных файлов\проектов через методы со стороны COM-оболочки InwOpState7. Напомним, что проект описывается с помощью COM-оболочки InwOaPartition.
using System.Runtime.InteropServices;
using NavisworksAutomationAPI18;
using NavisworksIntegratedAPI18;
Inavisdoc3? nwDoc = Marshal.GetActiveObject("Navisworks.Document.18") as Inavisdoc3;
InwOpState11? nwState = nwDoc.State() as InwOpState11;
for (int fileIndex = 0; fileIndex < nwState.LoadedFileCount; fileIndex++)
{
InwOaPartition nwPartition = nwState.LoadedFileFromNdx(fileIndex + 1);
}
Примечание: обращаем внимание, что все коллекции внутри Navisworks начинаются не с 0, а с 1 (для этого в теле метода LoadedFileFromNdx делаем +1);
Всего в Navisworks COM API существует 4 разных оболочки, описывающих содержимое загруженных в него данных:
InwOaPartition(такжеInwOaPartition2,InwOaPartition3) - представляет собой отдельный проект\файл;InwOaGroup- представляет любой элемент, у которого есть потомки (вложенные элементы по иерархии);InwOaNode- базовая оболочка для любых объектов, фактически предоставляет полноценный доступ к объекту;InwOaGeometry- обёртка над геометрией. Никаких специальных методов не содержит, кроме того, что для неё свойство Fragments уInwOaNodeвернет набор составляющих геометрию объектов и далее с ней продолжится работа, об этом чуть позднее).
Далее для каждого загруженного файла необходимо получить рекурсивно доступ к элементам. В примере ниже полученная информация выводится в окно.
using System;
using System.Runtime.InteropServices;
using System.Text;
using NavisworksAutomationAPI18;
using NavisworksIntegratedAPI18;
using System.Windows; //WPF, MessageBox
Inavisdoc3? nwDoc = Marshal.GetActiveObject("Navisworks.Document.18") as Inavisdoc3;
InwOpState11? nwState = nwDoc.State() as InwOpState11;
StringBuilder tmpStructure = new StringBuilder();
tmpStructure.AppendLine("Hierarchy info");
for (int fileIndex = 0; fileIndex < nwState.LoadedFileCount; fileIndex++)
{
InwOaPartition nwPartition = nwState.LoadedFileFromNdx(fileIndex + 1);
childProcessing(nwPartition, "");
}
void childProcessing(InwOaNode node, string prefix)
{
tmpStructure.AppendLine(prefix + node.UserName);
if (node.IsGroup)
{
InwOaGroup inwOaGroup = node as InwOaGroup;
foreach (InwOaNode childElem in inwOaGroup.Children())
{
childProcessing(childElem, "-" + prefix);
}
}
}
MessageBox.Show(tmpStructure.ToString());
Работа с геометрий
Дисклеймер: автор заранее извиняется на изложение материала далее, так как сам не до конца понимает механику в Navisworks.
Геометрию нельзя получить через какие-либо методы, вместо этого разработчику предлагается создать специальный класс, унаследованный от интерфейса InwSimplePrimitivesCB, где реализовать методы, получающие соответственно вырожденную геометрию: точку, линию, 3d-грань.
Ниже приведен минималистичный вид данных интерфейсов из библиотеки типов Integrated. Для того, чтобы создать класс-обработчик геометрии, вам придется подключать её к проекту как зависимость, реализовать обработку через dynamic-типизацию со "своим" интерфейсом, одинаковым по сигнатуре с Navisworks, не выйдет (у автора, во всяком случае, не получилось).
public interface InwSimpleVertex
{
object coord { get; }
object tex_coords { get; }
object normal { get; }
object color { get; }
}
public interface InwSimplePrimitivesCB
{
void Triangle(InwSimpleVertex v1, InwSimpleVertex v2, InwSimpleVertex v3);
void Line(InwSimpleVertex v1, InwSimpleVertex v2);
void Point(InwSimpleVertex v1);
void SnapPoint(InwSimpleVertex v1);
}
Реализация чтения с данным классом будет выглядеть так (сделал полный листинг, для консольного приложения):
using System;
using System.Runtime.InteropServices;
using NavisworksAutomationAPI18;
using NavisworksIntegratedAPI18;
public class PrimitiveChecker : InwSimplePrimitivesCB
{
public bool HasTriangles { get; private set; }
public bool HasLines { get; private set; }
public bool HasPoints { get; private set; }
public bool HasSnapPoints { get; private set; }
public void Line(InwSimpleVertex v1, InwSimpleVertex v2) => HasLines = true;
public void Point(InwSimpleVertex v1) => HasPoints = true;
public void SnapPoint(InwSimpleVertex v1) => HasSnapPoints = true;
public void Triangle(InwSimpleVertex v1, InwSimpleVertex v2, InwSimpleVertex v3) =>
HasTriangles = true;
}
internal class Program
{
static void Main(string[] args)
{
Inavisdoc3? nwDoc = Marshal.GetActiveObject("Navisworks.Document.18") as Inavisdoc3;
InwOpState11? nwState = nwDoc.State() as InwOpState11;
for (int fileIndex = 0; fileIndex < nwState.LoadedFileCount; fileIndex++)
{
InwOaPartition nwPartition = nwState.LoadedFileFromNdx(fileIndex + 1);
childProcessing(nwPartition);
}
void childProcessing(InwOaNode node)
{
if (node.IsGroup)
{
InwOaGroup inwOaGroup = node as InwOaGroup;
foreach (InwOaNode childElem in inwOaGroup.Children())
{
childProcessing(childElem);
}
}
if (node.IsGeometry)
{
foreach (InwOaFragment3 geomFragm in node.Fragments())
{
PrimitiveChecker geomChecker = new PrimitiveChecker();
geomFragm.GenerateSimplePrimitives(nwEVertexProperty.eNORMAL, geomChecker);
if (geomChecker.HasTriangles)
{
//... some work the geometry
}
}
}
}
Console.WriteLine("\nEnd!");
}
}
Пример класса для обработки геометрии можете посмотреть у Speckle.Navisworks (конкретно, в этом месте).
Примечание про пользовательскую реализацию
Путем экспериментов, если реализовать вот такую конструкцию:
[ComImport]
[Guid("1F4067D7-48FB-4759-BB8E-3E4A281FC841")]
public interface InwSimplePrimitivesCB
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void Triangle([In][MarshalAs(UnmanagedType.Interface)] InwSimpleVertex v1, [In][MarshalAs(UnmanagedType.Interface)] InwSimpleVertex v2, [In][MarshalAs(UnmanagedType.Interface)] InwSimpleVertex v3);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void Line([In][MarshalAs(UnmanagedType.Interface)] InwSimpleVertex v1, [In][MarshalAs(UnmanagedType.Interface)] InwSimpleVertex v2);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void Point([In][MarshalAs(UnmanagedType.Interface)] InwSimpleVertex v1);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SnapPoint([In][MarshalAs(UnmanagedType.Interface)] InwSimpleVertex v1);
}
public interface InwSimpleVertex
{
object coord
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[return: MarshalAs(UnmanagedType.Struct)]
get;
}
object tex_coord
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[return: MarshalAs(UnmanagedType.Struct)]
get;
}
object normal
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[return: MarshalAs(UnmanagedType.Struct)]
get;
}
object color
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[return: MarshalAs(UnmanagedType.Struct)]
get;
}
}
И для неё написать класс-обработки геометрии, то подключать к проекту COM-библиотеку типов вроде как нет необходимости, необходимо проверить, одинаков ли идентификатор у InwSimplePrimitivesCB в библиотеках типов для других версий Navisworks.
Работа со свойствами
У COM-оболочки InwOaNode, напомним, это "базовое" представление объекта и данных в Navosiworks, имеется свойство Attributes, возвращающее коллекцию атрибутов. Все атрибуты имеют "базовый" интерфейс InwOaAttribute. Всего атрибутов в Navisworks 7+1 (7 тех, что могут быть в коллекции атрибутов объекта и 1 (nwGUIAttribute), характерный для свойств приложения).
| Имя свойства (ObjectName) | Чем описывается |
|---|---|
| nwOaNameAttribute | InwOaNameAttribute |
| nwOaMaterial | InwOaMaterial |
| nwOaPublishAttribute | InwOaPublishAttribute |
| nwOaNat64Attribute | InwOaNat64Attribute |
| nwOaTransform | InwOaTransform |
| nwOaBinaryAttribute | InwOaBinaryAttribute |
| nwOaPropertyAttribute | InwOaPropertyAttribute |
| nwOaAttribute | InwOaAttribute |
| Принцип обработки показан ниже. |
InwNodeAttributesColl attrsColl = node.Attributes();
foreach (InwOaAttribute atrrBase in attrsColl)
{
string attrType = atrrBase.ObjectName;
switch (attrType)
{
case "nwOaNameAttribute":
InwOaNameAttribute attrName = atrrBase as InwOaNameAttribute;
//...
break;
case "nwOaMaterial":
InwOaMaterial attrMaterial = atrrBase as InwOaMaterial;
//...
break;
}
}
Прочие инструменты
В разделе описываются различные оболочки и вспомогательные инструменты
Выборка объектов
Выбор каких либо объектов в API описывается с помощью COM-оболочки InwOpSelection.
Для перехода от неё к непосредственно выбранным объектом можно воспользоваться следующим методом:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using NavisworksAutomationAPI18;
using NavisworksIntegratedAPI18;
Inavisdoc3? nwDoc = Marshal.GetActiveObject("Navisworks.Document.18") as Inavisdoc3;
InwOpState11? nwState = nwDoc.State() as InwOpState11;
InwOpSelection nwCurrentSelection = nwState.CurrentSelection;
InwSelectionPathsColl selectionResultPaths = nwCurrentSelection.Paths();
List<InwOaNode> needNodes = new List<InwOaNode>();
foreach (InwOaPath nwPath in selectionResultPaths)
{
// Возвращается полное "дерево" выбора от корня (файла) до геометрии.
// Т.к. свойства объекта привязаны к "родителю" геометрии, то нужно
// получить последний в цепочке структурный элемент (не геометрию)
InwPathNodesColl nwNodes = nwPath.Nodes();
// Поэтому начинаем отсчет с конца
for (int nodeIndex = nwNodes.Count; nodeIndex > 0; nodeIndex--)
{
InwOaNode node = nwNodes[nodeIndex];
if (!node.IsGeometry && node.UserName != "GeometryCollection")
{
needNodes.Add(node);
break;
}
}
}
MessageBox.Show("Selected next objects: " +
string.Join("\n", needNodes.Select(n => n.UserName)));
Набор выборки объектов
Набор выборки описывается COM-оболочкой InwOpSelectionSet, имеется также InwOpSelectionSet2, но она содержит лишь какие-то технические методы.
Набор выборки отличается от самой выборки только тем, что он имеет связанные имя name, дату Date, информацию об авторе Author и поле с комментариями Comments, и конечно, ссылку на саму выборку InwOpSelection- через свойство selection.
Примечание: при внешнем обращении к API при попытке получения даты (Date) выбрасывает ошибку System.Runtime.InteropServices.COMException: '<<Navisworks Error - Unspecific>>'.
Ниже приведен код, получающий перечень сохраненных выборок в модели (в UI видны в окне "Наборы") и выводящий в окно информацию об имени набора и количестве объектов в выборке:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using NavisworksAutomationAPI18;
using NavisworksIntegratedAPI18;
Inavisdoc3? nwDoc = Marshal.GetActiveObject("Navisworks.Document.18") as Inavisdoc3;
InwOpState11? nwState = nwDoc.State() as InwOpState11;
List<string> ssInfo = new List<string>();
InwSelectionSetColl nwSelSets = nwState.SelectionSets();
foreach (InwOpSelectionSet nwSelectionSet in nwSelSets)
{
InwSelectionPathsColl selectionResultPaths = nwSelectionSet.selection.Paths();
List<InwOaNode> needNodes = new List<InwOaNode>();
foreach (InwOaPath nwPath in selectionResultPaths)
{
InwPathNodesColl nwNodes = nwPath.Nodes();
for (int nodeIndex = nwNodes.Count; nodeIndex > 0; nodeIndex--)
{
InwOaNode node = nwNodes[nodeIndex];
if (!node.IsGeometry && node.UserName != "GeometryCollection")
{
needNodes.Add(node);
break;
}
}
}
ssInfo.Add($"Набор {nwSelectionSet.name} - {needNodes.Count} шт.");
}
MessageBox.Show(string.Join("\n", ssInfo));