Бесит
Есть вот задачи в работе координатора, которые прям бесят и заставляют выть - открыть 200 моделей и прокинуть виды, классический пример.
Это бесило когда я только начал, это бесит и сейчас. Но не так давно я начал по-тихоньку учиться писать небольшие скрипты и автоматизации, в этой статье речь пойдет об одном из них.
Попробую описать что он делает:
- Открывает в фоновом режиме модели с сервера в автоматическом режиме
- Закрывает и синхронит так же на автомате
Ой, кажется все весьма просто или нет…
ВАЖНОЕ ПРИМЕЧАНИЕ ОДИН
Я не программист! Я координатор, который не программирует, а пишет скрипты по автоматизации, если вы программист, то и сами знаете как что работает и как сделать круче, лучше и вообще вы классные. Тут простыми словами, о вещах, которые мне помогли облегчить работу. Сам код может быть не очень хорош, но он прекрасно справляется со своей задачей.
ВАЖНОЕ ПРИМЕЧАНИЕ ДВА
Все пишется на ironpython под pyrevit
Начало
1- Кодировка файла для того чтобы использовать русские символы.
2- Имя скрипта которое отобразится на кнопке
3- Указание автора скрипта
3- Описание которое отобразится на кнопке
8-13- Импорты, на 11 строчке импорт функции о которой написал тут:
17-18 - Эти строки создают объект вывода, который используется принтов.
script.get_output().close_others(all_open_outputs=True) закрывает все открытые выводы, чтобы избежать их накапливания.
20 - получаем активный документ Revit и сохраняет его в переменной doc, чтобы можно было обращаться к нему в коде.
21 - получаем апликейшен
22 - получаем имя пользователя, который в данный момент использует Revit, и сохраняет его в переменной user.
23-24- создаем экземпляр класса для подсчета времени и настраиваем формат
Создание локальной копии и получение пути для их хранения
Возрадуемся братья и сестры и скажем аллилуйя, что можно открывать модели в фоновом режиме! Аллилуйя!
В API есть такой вот метод - OpenDocumentFile()
И вроде все ок, весьма просто - пишем функцию или вызываем все напрямую и вуаля, но основная проблема при использование OpenDocumentFile заключается в том, что у данного метода нет опции создать Локальную копию файла который он будет открывать, что странно, так как настройка отсоединяющая модель есть:
Получается что ФХ будет открыт напрямую и чтобы написать аналог галочки «Создать локальную копию» нужно использовать метод CreateNewLocal класса WorksharingUtils
В качестве аргументов ему надо отдать 2 ModelPath:
- адрес текущей модели
- адрес новой модели (то есть где-то на диске выделить место и придумать имя самого файла)
И, по хорошему, нужно сохранять в туже папку, в которой у нас хранятся локальные копии при открытие через интерфейс.
И теперь встал вопрос: а как этот путь получить?
Мы знаем что:
- Путь для сохранения мы задаем в настройках ревита
- Все настройки для ревита хранятся в файле Revit.ini
- Данный файл расположен в appdata в папке с нужной версией ревита.
Получается чтобы сгенерировать полный путь до новой модели которую создаст CreateNewLocal надо:
- Добраться до файла Revit.ini текущей сессии Revit (для этого есть свойство CurrentUserDataFolderPath https://www.revitapidocs.com/2021.1/3ff50826-aae6-0b19-8057-15af6a88cd41.htm)
- Прочитать его
- Найти строчку отвечающую за адрес локальных копий
- Забрать путь
Тут мы:
27- Добираемся до папки где лежат настройки и прибавляем к ним имя файла с настройками, что бы сформировать нормальный путь
28- проверяем существует ли по данному пути такой файл
29- печатаем ошибку если его нет
30- и выкидываем False, чтобы прервать скрипт
31- открывает try чтобы поймать ошибку открытия, в целом можно и без этого
32- используя модуль codecs открываем файл в режиме чтения указав в какой кодировке он encoding='utf-16-le'
33- с помощью next отлавливаем первое совпадение с уловием в строчках. Условие такое "if line.startswith('ProjectPath=')" именно тут лежит путь куда сохраняются локальные файлы по дефолту.
35- закрываем ловлю ошибок
35- печатаем ошибку
36- возвращаем False что бы прервать скрипт
Если кто-то знает как, по-другому получить путь, который задается тут:
буду очень рад помощи.
Создание локальной копии
Опишем функцию
Принимает функция: путь до модели которую хотим открыть и путь куда сохранять, это то для чего мы писали функцию get_project_path_from_ini()
40- запускаем таймер
41- на всякий случай нормализую адрес и сохраняю в переменную folderforsave
42 - забираю у адреса модели имя модели и удаляю «.rvt»
43 - создаю новое имя, используя старое + разделитель + имя пользователя которое хранится в глобальной переменной user
46 - создаю полный адрес для новой модели
49 - проверяем существует ли такая модель и если да удаляем ее (стр 52)
Вообще, ревит в таком случае спрашивает что сделать: заменить или добавить к старой дату и время, тем самым освободив имя, но я для экономии места просто затираю старую локалку
54- открываем try except
55- c помощью ModelPathUtils.ConvertUserVisiblePathToModelPath преобразую ссылку на модель в экземпляр класса ModelPath с которым ревит может работать
56- аналогично
57- наконец-то передаем их в метод CreateNewLocal класса WorksharingUtils
Итогом работы данной функции является создание локальной копии и возврата нам targetPath- ссылки на локальную копию в виде объекта ModelPath
Открытие моделей
69- создание экземпяра класса OpenOptions()
70- используем свойство Audit задав ему True чтобы открывать с проверкой
71 - создаем настройки рабочих наборов и применяем к ним закрытие
72 - передаем эти настройки к нашему options
73- запускаем таймер
74- на всякий случай обернул в try except
75- от апликешена вызываем открытие модели через OpenDocumentFile передав путь до локальной копии и настройки. Ревит возвращает нам документ файла, которого он откроет, поэтому записываем в переменную doc
76- завершаем подсчет времени
77- печатаем что мы молодцы и сколько это заняло времени
79-80- ловим ошибку и печатаем ее
MAIN
83- вызываем функцию get_project_path_from_ini()
84- проверяем что она не вернула False
85- вызываем функцию select_file(). Она нужна для выбора ссылок на модели. Данную функцию я импортировал на 11 строчке, она самописная. О ней можно прочитать тут
86- проверяем что она нам что-то вернула
87-88- печатаем вступительное слово
89- запускаем таймер общего времени
90-обновляем прогресс бар для визуального отображения хода работы программы
92-начинаем работать со списком моделей которые мы выбрали через sel_models
enumerate используется для итерации по элементам списка и получения индекса элемента (i) и самого элемента (m). Индекс нужен для прогресс бара.
93- печатаем выбранную нами модель
94- вызываем функцию создания локальной копии
95- вызываем функцию открытия модели
96- обновляем прогресс бар
98-100- выводим итоговое время
Итог
Спустя 100 строк кода мы получаем инструмент тотального управления моделями.
Скрипт выдаст вот такое окно:
и теперь если посмотреть скажем через RevitLookup
у нас будет несколько открытых документов, хотя вкладка в Revit всего одна.
Условный JOTools будет видеть эти модели и даст возможность выбрать их как модели, в которые можно что-то скопировать. Другими словами теперь эти модели доступны для редактирования через код или какие то плагины.
Тут разбираем скрипт позволяющий закрыть все эти фоновые модели.
Кстати, есть у меня вот такой тестовый файл размером в 1 Гб
На его открытие ушло всего 2.5 минуты. Разве не чудо?!