Всем привет! Сегодня рассмотрим несколько интересных вещей из Revit API: поиск DWG-импортов (и связей), работа с геометрией, создание труб (многие линейные элементы и перекрытия создаются аналогично) и создание новых элементов.
Спойлер: рассматривайте эту статью как сборную солянку: я рассказываю вам интересные штуки про Revit API, а вы используете только то, что надо вам. Категорически не рекомендую чертить подложку в DWG и переносить её в Revit, даже с помощью плагинов.
Задача
Дан DWG-файл с полилиниями. Часть из них имеет слой "Pipes". Необходимо получить эти полилинии и построить трубы по оси входящих в них линий. Каждую пару смежных труб — соединить отводом.
Решение
1. Получение DWG
Загрузим DWG в модель (лучше связью), выделим и нажмём Snoop Selection в Revit Lookup (что за Lookup, где взять?). Видим, что этот элемент относится к классу ImportInstance (причём неважно, связь это или импорт):
Ну а дальше просто используем FilteredElementCollector:
Обратите внимание, что я вынес Document в отдельное поле класса. Это нужно для того, чтобы использовать его во всех методах и не передавать лишний раз.
Также я взял первый экземпляр импорта просто методом .First();. Он выдаст исключение, если последовательность пустая. Если у вас много импортов DWG, то тогда записывайте их в список и делайте то, что нужно вам (удаляйте).
2. Получение полилиний
На этом этапе нужно будет внимательно поработать с Revit Lookup. В вашем случае там могут быть не полилинии, а отрезки, или что угодно ещё. Получение геометрии родных элементов Ревита будет происходить точно также.
Итак, нам нужно пройти по пути Geometry — GeometryInstance — GetInstanceGeometry. Звучит просто, если знать как, в коде чуть-чуть сложнее.
Итак, пошагово в Lookup:
Но это ещё не всё — надо понять, какие из них лежат на слое Pipes. Идём в GraphicStyleId:
Принцип при поиске решения задачи для будущего плагина довольно часто именно такой: находим решение в Lookup, потом реализуем в коде. Посмотрим код:
Давайте разбираться:
1. Свойство Geometry нельзя получить на прямую, синтаксис такой:
element.get_Geometry(options);
В строках 25-27 создаём экземпляр Options. В 31 строке получаем с их помощью геометрию.
А дальше немного непонятный финт. В чём дело:
Свойство Geometry возвращает нам GeometryElement, который является списком GeometryObject. И нам нужно получить (в данном случае) первый такой объект. Для этого мы заводим переменную для него (строка 30), и проходимся циклом, чтобы записать в неё значение.
Если вдруг у вас получилось добиться аналогичного результата проще, пожалуйста, напишите в комментарии со ссылкой на гитхаб или со скринами кода.
Дальше всё просто: в строке 44 получаем список полилиний через GetInstanceGeometry(), и просто проходимся по ним циклом. Я решил обернуть всё это в группу транзакций, потому что в методе CreatePipes создаются транзакции.
Далее осталось проверить слой полилинии. Мы берём стиль на 48 строке и проверяем его имя. Не забываем привести к типу GraphicsStyle.
Итак, полилиния найдена, осталось создать трубы.
Создание труб
Поскольку полилиния представляет собой последовательность линий, я выбрал такой алгоритм: последовательно построить все трубы, записать их в список, а потом последовательно построить отводы для каждой пары труб.
Создать трубы нам поможет статический метод Pipe.Create. Ему нужно передать тип системы, тип трубы и уровень. В данном случае в демонстрационных целях я возьму всё методом First(). Но в настоящих плагинах так, скорее всего, не получится — надо будет писать логику по определению типа системы и типа трубы.
Рассмотрим итоговый код создания трубы:
На строке 63 получаем все точки полилинии. Создаём список для новых труб на 73 строке и начинаем работу:
Запускаем цикл for на 77 строке (мой обзор на циклы C#). Начинаем с единицы, чтобы мы могли взять предыдущую точку из списка точек. Ну и, собственно, создаём трубу на 82 строке.
На 83 строке я назначаю трубе диаметром 10 мм (тут пишу, почему я делаю это именно так). Это необязательно: по умолчанию будет 152,4 мм.
По итогу для полилинии мы получили список труб. Теперь нам надо создать фитинги.
В этом нам поможет класс Document (но другой — из Autodesk.Revit.Creation). Метод NewElbowFitting — создаёт отводы. Вообще, этот класс создаёт все точечные элементы (чьё местоположение определяется точкой и углом поворота), и некоторые другие.
Метод принимает 2 коннектора, поэтому я написал метод, который у 2 труб находит 2 лежащих рядом коннектора:
Создаём отвод:
Задача решена.
Организация проекта
Я создал в своём репозитории https://github.com/SergeyNefyodov/Revit-API-Blog новую папку DwgMepCurveCreator, и в ней один новый класс Command. Я не добавлял ничего в addin-файл, поэтому код из репозитория будет работать только в Addin-manager. (Не забывайте ставить звезду моему репозиторию, это аналог лайка на GitHub).
Тут можно прочитать, как запускать и отлаживать плагины через Addin Manager.
А тут — как подключить внешнюю команду к Revit
Здесь — как превратить команду в кнопку на панели "Надстройки" (или на новой панели).
Посмотрим, что получилось (первый раз пробую с гифкой, если знаете удобные инструменты записи экрана — пишите в комментарии)
А на этом всё! В следующей статье начнём создавать оконные приложения с помощью WPF. Обязательно подписывайтесь на мой телеграм-канал, это центральная часть блога, где я аккумулирую весь контент. До новых встреч!