Найти в Дзене
Блог Вадима Муратова

Dynamo: поиск пересечений

Расскажу, как стандартными нодами найти пересечения элементов. Это нужно не столько ради проверки модели на правильность построений, сколько на определение принадлежности элементов. Например, когда нужно определить, к какому помещению относится оборудование или воздухораспределители. Концепция Общая идея простая: берём геометрические объекты и смотрим, что с чем пересекается. В Динамо можно преобразовать элементы в геометрию, то есть получить с семейства набор твёрдых тел — солидов — и кривых линий. Затем можно их преобразовать в bounding box — габаритный параллелепипед, грубо говоря кубик, который построится по максимальным размерам семейства. Грубо — потому что не кубик, а параллелепипед, но я замучаюсь писать это слово, поэтому далее по тексту кубик — это параллелепипед. После стандартными нодами можно проверить, какие кубики пересекаются и получить список true-false. Обработав такой список мы получим нужные нам данные. Вот такой концепт. Реализация Давайте сразу посмотрим на пример
Оглавление

Расскажу, как стандартными нодами найти пересечения элементов.

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

Концепция

Общая идея простая: берём геометрические объекты и смотрим, что с чем пересекается.

В Динамо можно преобразовать элементы в геометрию, то есть получить с семейства набор твёрдых тел — солидов — и кривых линий. Затем можно их преобразовать в bounding box — габаритный параллелепипед, грубо говоря кубик, который построится по максимальным размерам семейства.

Грубо — потому что не кубик, а параллелепипед, но я замучаюсь писать это слово, поэтому далее по тексту кубик — это параллелепипед.

После стандартными нодами можно проверить, какие кубики пересекаются и получить список true-false. Обработав такой список мы получим нужные нам данные. Вот такой концепт.

Реализация

Давайте сразу посмотрим на примере. Есть модель АР с помещениями, модель ОВ с пространствами и в инженерном файле расставлены диффузоры.

Модель АР и диффузоры
Модель АР и диффузоры

Задача — нужно определить, в каких пространствах находятся диффузоры и записать эту информацию в выбранный параметр.

Сам Ревит знает, где находятся диффузоры, потому что показывает в диспетчере инженерных систем, к каким пространствам они относятся. Подробнее про диспетчер можете прочитать в отдельном материале. Про пространства также есть дотошная статья. Тем не менее автоматически вывести эту информацию прямо в диффузоры не получится, придётся использовать Динамо.

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

Получаю все элементы в модели
Получаю все элементы в модели

Теперь нужно преобразовать элементы в геометрию. Для этого есть нод Element.Geometry. Все объёмные тела, которые были в семействе, он превратит в солиды, а линии оставит линиями. При этом текущая детализация не будет влиять на отображение, нод покажет всё. Например, диффузор будет выглядеть так:

Преобразовываю элемент в геометрию
Преобразовываю элемент в геометрию

Динамо внутри себя построило все диффузоры. Чтобы отключить отображение диффузоров, нужно нажать на ноде правой кнопкой мыши и снять галочку «Предварительный просмотр».

Делать такое придётся у всех нодов, чью геометрию хотите скрыть
Делать такое придётся у всех нодов, чью геометрию хотите скрыть

Если обратите внимание на раскрытый список у нода Element.Geometry, то увидите, из чего состоит один диффузор: 13 линий и всего одно твёрдое тело, один солид.

Потому что геометрия диффузора — одно тело вращения, остальное — линии условного графического обозначения. 4 треугольника по 3 линии и окружность в центре, которую сейчас не видно. Вот и получается 13 линий и 1 солид.

Далее я подал геометрию на нод BoundingBox.ByGeometry. Он берёт все линии и солиды, находит две максимально удалённые друг от друга точки и строит кубик. Если раскрыть список у нода, то увидим вот такую запись для каждого диффузора (числа будут разными, но форма записи одинаковая):

BoundingBox(MinPoint = Point(X = 5023.910, Y = 8077.303, Z = 6484.000), MaPoint = Point(X = 6030.128, Y = 9083.521, Z = 6560.000))

Текст целиком не влезает — давняя беда Динамо
Текст целиком не влезает — давняя беда Динамо

В этой записи зашифрованы координаты минимальной и максимальной точки кубика. Минимальная — та, которая ближе всего к внутреннему началу, а максимальная — та, что дальше. Внутреннее начало — это начало локальной системы координат файла, его нельзя передвинуть или изменить.

Обычно, если вы разместите базовую точку проекта в нулях, то увидите это самое внутреннее начало. С версии 2020.2 у него появилось своё обозначение в виде трёх осей координат.

Если хотите посмотреть, как Динамо воспринимает баундин бокс, то подайте нод с ним на другой стандартный нод BoundingBox.ToCuboid. Получите вот такую картину:

Серый кубики — визуализация баундин боксов
Серый кубики — визуализация баундин боксов

Итак, мы получили диффузоры в виде баундин боксов, то же самое нужно сделать с пространствами. Поскольку пространства сами по себе — кубики, то и баундин боксы будут их повторять, превращая аналитический объём в геометрический. А раз у нас есть два тела, то их можно проверить на пересечения.

Для этого есть нод BoundingBox.Intersects. Поскольку у нас есть список диффузоров и пространств и нам нужно проверить пересечение каждого диффузора с каждым пространством, то нужно включить векторное переплетение списков. Подробнее об этом читайте в статье про списки.

Подаю баундин боксы диффузоров и пространств на нод для проверки пересечений
Подаю баундин боксы диффузоров и пространств на нод для проверки пересечений

Поскольку нужно получить на выходе список пространств, которые соответствуют списку диффузоров, то лучше подавать на вход boundingBox список диффузоров, а на вход other — пространств. Так итоговая информация будет удобнее для обработки.

Теперь у нас есть список true-false. Там, где true — пересечение, диффузор находится в пространстве. Значит, нужно получить список пространств, чтобы он соответствовал списку диффузоров. Использую нод List.AllIndicesOf для получения индексов true-позиций, а потом выдёргиваю нодом List.GetItemAtIndex нужные пространства.

Получаю пространства
Получаю пространства

В ноде BoundingBox.Intersects я получаю список пересечений. В каждом подсписке со значением true «сидит» пространство, в котором находится диффузор. Получал индекс для true, то есть его порядковый номер в подсписке, а потом из списка всех пространств получаю искомое.

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

Получаю имена и номера пространств, формирую список
Получаю имена и номера пространств, формирую список
Записываю информацию в диффузоры в параметр «Комментарии»
Записываю информацию в диффузоры в параметр «Комментарии»

Готово. Если составить спецификацию на диффузоры и вывести столбец со значениями параметра «Комментарии», то получаю всю информацию:

Проверил в модели — всё правильно
Проверил в модели — всё правильно

Вот картинка всего скрипта, чтобы вы примерно ориентировались, что с чем соединяется, хотя лучше проделайте всю процедуру самостоятельно, чтобы глубже разобраться в способе.

Скрипт на пересечение диффузоров и пространств
Скрипт на пересечение диффузоров и пространств

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

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

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

Когда нужна более высокая точность, преобразовывайте элементы в геометрию и используйте нод Geometry.DoesIntersect. Вы так же получите список true-false, однако следите за тем, что подаёте на нод. Лучше предварительно очистить геометрию от ненужных линий. В остальном всё работает аналогично.

Обновления статей удобно получать в Телеграм-канале «Блог Муратова про Revit MEP». Подписывайтесь и приглашайте коллег. Можно обсудить статью и задать вопросы в специальном чате канала.

Читайте методичку для проектировщиков: полезный материал, в котором последовательно рассказываю, как создавать модель.

Бесплатные обзоры ваших моделей

Периодически провожу «Ревит-линчи» — разбираю файлы семейств и проектов пользователей и отвечаю на вопросы по Ревиту и БИМ-технологиям. Дату и ссылку на Ревит-линч публикую в Телеграм-канале. Приходите, там интересно.

Отблагодарить автора

Я много времени уделяю блогу и разработке семейств. Если хотите отблагодарить меня, то можете сделать небольшой подарок (именно подарок, такой перевод не облагается налогом).