Приветствую вас! Меня зовут Влад Созутов, и я работаю инженером по автоматизации в строительной сфере, и в этой отрасли пребываю с 2015 года. Цель этого блога - поделиться моими знаниями с коллегами, людьми смежных профессий, которые рассчитывают расширить свои проф. интересы. Начнём, пожалуй, с использования метода по автоматическому заполнению спецификаций системных семейств (кабельных лотков) в Revit 2019.
Системные семейства в Revit содержат типоразмеры, по которым в моделях , создаются базовые элементы зданий: стены, полы, потолки, лестницы и, в нашем случае - кабельные лотки. Так как системные семейства заранее определены в Revit, для их сохранения в шаблонах и проектах не требуется загрузка из внешних файлов. Системные семейства невозможно копировать, изменять или удалять, однако в системных семействах можно копировать и изменять типоразмеры, создавая пользовательские типоразмеры на основе системных семейств.
Однако записывать в типоразмеры параметры неудобно. Поэтому пользователи стали записывать параметры в ключевые спецификации.
Ключевая спецификация - это заполнение и использование клавиш для автоматизации процесса пополнения спецификаций согласованными данными.
Грубо говоря, это набор данных, где можно обращаться по ключу и брать нужные значения этого ключа.
Создать ключевую спецификацию очень просто: нажмите правой кнопкой мыши на "Ведомости/Спецификации" в диспетчере проекта, а затем нажмите "Создать спецификацию/количества..". Далее необходимо выбрать категорию и переключить на "Ключи спецификации".
Затем добавляем необходимые параметры во вкладке "Доступные поля". Сразу скажу, что параметры из файла общих параметров добавить нельзя, поэтому создадим параметры внутри проекта и укажем соответствующую категорию. После этого заполняем поля в ключевой спецификации.
Имея данную спецификацию, выбираем параметр ключа у элемента в модели. После чего, все значения ключа автоматически заполняются у элемента.
Автоматическое заполнение, заранее согласованного списка материалов, является большим преимуществом в работе со спецификациями. Поэтому ключевые спецификации всё чаще появляются в шаблонах по электрике и слаботочке.
Выглядит неплохо, верно? Тем не менее существуют определённые трудности при работе с ключевыми спецификациями:
- Заполнение ключевой спецификации. Стандартные методы не позволяют загружать свои согласованные списки из excel; приходится забивать вручную, параметр за параметром, что является утомительным занятием.
- Для каждого элемента модели мы должны вручную выбрать ключ, что, по моему мнению, неудобно. Присутствует шанс что-то забыть или выбрать, случайно, неверный ключ.
Поэтому было решено исправить данные недочёты с помощью Dynamo + Python.
План действий
- Автоматическое добавление позиций из заранее составленного списка в excel
- Проверка имени типоразмер (нужно чтобы работало только с “нашими” лотками, в нашем случае префикс “SVD_”, создадим список для маски)
- Сопоставление имени типоразмера и его размера с ключом спецификации
- Автоматическое заполнение ключа по имени и размеру лотка
Реализация
Для первого пункта я не стал сам создавать скрипт. Его нетрудно найти в интернете. Единственное что нужно знать, ваши столбцы в excel должны быть полностью идентичны названиям параметров в Revit. Любой пробел или отличающийся регистр не позволит добавить нашу таблицу. И ещё, нельзя чтобы были пустые поля. Я обычно делаю это так:
- Выгружаю таблицу с параметрами из Revit (Файл → Экспорт → Отчёты → Спецификация)
- Копирую из своей таблицы в созданную таблицу из Revit
- Удаляю верхнюю строку (оставляем только столбцы с параметрами)
- Открываю скрипт Dynamo и выбираю нужный excel файл
Для себя я сделал дополнительную проверку количества передаваемых строк, чтобы убедиться, что мы передали весь список.
Переходим к самому интересному. Второй по четвёртый пункты я решил объединить в один скрипт на Dynamo. Я не так давно изучаю Dynamo, но неплохо знаю Python. Поэтому меня не раз выручал нод “Python Script”, где можно писать на Питоне, если не можешь найти нужный нод. Динамо поддерживает IronPython, одну из разновидностей этого языка, но различий немного.
Первое что нужно - проверка на имя типоразмера. Здесь нет ничего сложного, обращаемся вновь к “Python Script”, но для начала в категории “Revit - Selects” выберем пару нодов. “Categories”и “All Elements of Category”. Выбираем кабельные лотки из списка.
Далее, выбираем нод “Python Script”. И приступаем к написанию кода. Сначала нам необходимо отфильтровать наименование по типоразмеру. Входные данные нужно выразить через UnwrapElement, чтобы сделать их нативными (данные Dynamo отличаются от данных Revit, и чтобы работать с элементом как Revit-элементом, нужно “упасть” на порядок ниже). Я решил, что мне нужны только мои созданные лотки с префиксом "SVD_", поэтому необходимо создать маску (список допустимых значений). Таким образом мы будем работать только с лотками с префиксом "SVD_".
cableTrays = UnwrapElement(IN[0])
maskName = ["SVD_Проволочный кабельный лоток", "SVD_Лестничный кабельный лоток", "SVD_Перфорированный кабельный лоток", "SVD_Неперфорированный кабельный лоток"]
Чтобы пройтись по всем элементам массива и найти семейства с префиксом в типе "SVD_" воспользуемся циклом:
for cableTray in cableTrays:
if cableTray.Name in maskName:
correctCableTraysNames.append(cableTray.Name)
correctCableTrays.append(cableTray)
Данный цикл отсеивает все элементы, кроме нашей маски. Мы проходим циклом по всем лоткам и отбираем "SVD" лотки.
Идём дальше. Чтобы сравнить ключ спецификации с именем типа кабельного лотка, необходимо трансформировать имя типа лотка. Используем все тот же цикл:
for element in correctCableTraysNames:
transformName1 = element.lower().split('_')
transformName2.append(transformName1)
transformName3 = transformName2[n][1].split(' ')
correctName.append(transformName3[2] + ' ' + transformName3[0])
n += 1
Пробегаемся по именам типов лотков. С помощью метода "lower" все буквы имени преобразовываются в нижний регистр. Метод "split" разделяет имя на отдельные слова, разделитель, в нашем случае нижнее подчеркивание ("_"). С помощью transformName2.append(transformName1) добавляем в промежуточный список (метод append значит добавить в список transformName). В строке transformName3 = transformName2[n][1].split(' ') мы переставляем местами слова в названии типа. А в correctName добавляем transformName3[2] + ' ' + transformName3[0] нужные части, получая корректное наименование.
Далее нам нужно трансформировать значение параметра "размер". Сейчас у нас параметр выглядит так - 300/100 (ширина/высота), по ключу спецификации нам нужно наоборот 100х300 (высота/ширина). Для начала нам нужно взять значения параметра "Размер". Используем метод описанный в API Revit.
for i in cableTrays:
if i.Name in maskName:
getParamSize = i.LookupParameter("Размер").AsString()
size.append(getParamSize)
if i.Name in maskName - сначала проверяем элементы на соответствие маски. Метод LookupParameter позволяет вытащить нужное значение из параметра по наименованию. AsString означает, что на выходе мы получим данные в виде строки. Запишем полученные значения в переменную size.append(getParamSize).
Теперь приступим к трансформации значения размера.
for i in size:
transformSize = i[4::] + "х" + i[:3:]
correctSize.append(transformSize)
Здесь все просто - мы переставили значения "ширина/высота" на "высота/ширина" и добавили разделитель "х". В итоге у нас должно получится вот такое значение - "100х300".
Теперь соединим "корректное имя" с "корректным размером" и добавим префикс "LS".
for element in correctName:
fullNameCableTrays.append("LS_" + element.capitalize() + "_" + correctSize[k])
k += 1
Метод capitalize позволяет написать строку с заглавной буквы.
Нам осталось только создать массив, в котором будут элемент модели и его "полное корректное имя".
for j in correctCableTrays:
outCableTrays.append([j, fullNameCableTrays[v]])
v += 1
На выходе получаем такой вот массив:
Здесь есть ID элемента и его "правильное наименование". Этого достаточно, чтобы сравнить лотки со списком ключей.
Весь код блока ниже:
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
dataEnteringNode = IN
cableTrays = UnwrapElement(IN[0])
maskName = ["SVD_Проволочный кабельный лоток", "SVD_Лестничный кабельный лоток", "SVD_Перфорированный кабельный лоток", "SVD_Неперфорированный кабельный лоток"]
correctCableTrays = []
correctCableTraysNames = []
transformName1 = []
transformName2 = []
transformName3 = []
correctName = []
size = []
correctSize = []
fullNameCableTrays = []
outCableTrays = []
n = 0
k = 0
v = 0
for cableTray in cableTrays:
if cableTray.Name in maskName:
correctCableTraysNames.append(cableTray.Name)
correctCableTrays.append(cableTray)
for element in correctCableTraysNames:
transformName1 = element.lower().split('_')
transformName2.append(transformName1)
transformName3 = transformName2[n][1].split(' ')
correctName.append(transformName3[2] + ' ' + transformName3[0])
n += 1
for i in cableTrays:
if i.Name in maskName:
getParamSize = i.LookupParameter("Размер").AsString()
size.append(getParamSize)
for i in size:
transformSize = i[4::] + "х" + i[:3:]
correctSize.append(transformSize)
for element in correctName:
fullNameCableTrays.append("LS_" + element.capitalize() + "_" + correctSize[k])
k += 1
for j in correctCableTrays:
outCableTrays.append([j, fullNameCableTrays[v]])
v += 1
OUT = outCableTrays
Далее нам нужно скачать пакет "Springs", так как я не нашел способа прочитать данные ключевой спецификации. В дальнейшем планирую разобраться с этой проблемой, чтобы не нужно было скачивать лишние пакеты. Идем в верхнюю панель навигации - Пакеты - Поиск пакетов. Качаем пакет.
Создаем еще несколько нодов:
- Views
- Springs.Collector.ElementsInView
- Element.Name
Остался финальный штрих - нужен скрипт для сравнения нашего имени с именем ключа в спецификации. Создаем еще один Python Script:
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitNodes')
from Revit.Elements import Element
dataEnteringNode = IN
cableList = IN[0]
keys = IN[1][0]
a = []
for cableTray, name in cableList:
for element in keys:
if element.Name == name:
Element.SetParameterByName(cableTray,"Стиль кабельных лотков",element)
a.append(name)
OUT = a
Соединяем оставшиеся ноды и получаем вот такую картину:
На момент публикации этой статьи версия скрипта отличается от того, что здесь описано. Скачать текущую версию вы можете по ссылке.
Спасибо, что дочитали до конца, надеюсь это было полезно. Предлагайте свои идеи для автоматизации и подписывайтесь на мой блог!