Ранее я уже немного писал про оформление с помощью API, а именно — о простановке размеров: здесь и здесь. Сегодня же поговорим про автоматическое создание марок, и заодно посмотрим на возможную реализацию некоторых фич плагинов с окнами.
Введение
Вообще, Revit позволяет нам автоматически маркировать элементы командой "Маркировать всё". Но у команды есть минусы: например, нельзя отфильтровать элементы или сдвинуть марки. Попробуем сегодня написать плагин, который будет расставлять марки, сдвигать их на выбранную величину и создавать выноску. Фильтровать элементы я не буду, а буду брать все элементы категории на активном виде. Если вам нужно, то для себя вы можете сделать какую угодно фильтрацию (а здесь ещё раз о фильтрации).
Задача
Создадим приложение, в котором будем выбирать из списка нужную категорию для маркировки. После выбора категории выберем из второго списка подходящую для неё марку, назначим горизонтальное и вертикальное смещение в миллиметрах, а также укажем, хотим ли мы делать выноску, и создадим марку по нажатию кнопки запуска
Решение
Одна из неприятных проблем этой задачи: категория не знает о том, к какой категории относятся её марки. То есть стены не знают, что их маркируют Марки стен, и так далее.
Поэтому я покажу вам своё решение этой проблемы, но если вы придумаете более элегантное, обязательно пишите его в комментарии
Примерно тоже самое можно сделать с помощью Dictionary, но я создам отдельный класс, который будет хранить 3 свойства:
- Имя для пользовательского интерфейса
- Категория, которую маркируем
- Марку этой категории
А во ViewModel будем инициализировать список этих объектов так, как нам надо. Для примера я заполню его дверями и окнами:
Дальнейшее заполнение ViewModel я сделаю с помощью библиотеки Community.Toolkit.Mvvm. Если вы ранее не писали оконные приложения на WPF, настоятельно рекомендую ознакомиться с циклом статей про WPF, чтобы понимать, что происходит.
Хотя код по созданию марки будет понятен и без знаний по WPF, так что не спешите закрывать статью.
Итак, заполним нашу ViewModel. У нас будет 2 списка: список CategoryMapper, который я указал выше, для выбора категории; список типов марок для этой категории. Также у нас будет запоминаться выбранный CategoryMapper и выбранный тип марки. И 3 переменных для параметров марки: горизонтальное и вертикальное смещение и строить ли выноску:
Но тут сразу возникает вопрос: а что мы будем отображать во втором списке, если поменяется выбранная категория? Для этого я использую partial метод, создаваемый генератором код в Community.Toolkit.Mvvm:
Этот метод вызывается тогда, когда у нас меняется активный маппер в UI.
На самом деле, можно и вручную также сделать, без генераторов кода, тогда у вас изменится блок set у свойства, что-то типа такого:
public CategoryMapper ActiveMapper
{
get => _activeMapper;
set
{
_activeMapper= value;
OnActiveMapperChanged(value);
OnPropertyChanged();
}
}
Таким образом, у нас каждый раз при смене категории будет меняться предлагаемый список марок.
Осталось только написать команду. Она будет довольно простой, чтобы не усложнять статью:
Какие нюансы тут стоит учесть:
1. Марка по умолчанию ставится с присоединённым концом, по этому в строке 75 я меняю его на свободный.
2. Хотя я назначаю точку положения марки при создании на строке 72, это не особо работает, поэтому я добавляю явное указание на 76 строке.
Вообще, Revit API 2023 предоставляет большой арсенал работы с марками. Что мы можем сделать (ссылка на класс, все методы и свойства внутри):
- Добавить к марке элементы (AddReferences), чтобы у одной марки было несколько выносок, или удалить их (RemoveReferences)
- Объединить выноски (MergeElbows).
- Установить точку присоединения выноски(SetLeaderEnd), точку её излома (SetLeaderElbow) и точку расположения марки (TagHeadPosition).
- Повернуть марку (RotationAngle)
В общем, простор для автоматизации маркировки довольно большой. Однажды я даже писал такой плагин:
- От элемента мы имеем 4 четверти, куда можно сдвинуть марку: вверх влево, вниз влево, вверх вправо, вниз вправо.
- По очереди в одной транзакции ставим марки в каждое из 4 положений
- Создаём Outline по марке и ищем число пересекающихся с маркой элементов
- Переносим марку в положение с наименьшим числом пересечений
Хотя код получился сложный и не всегда рабочий, но марки в разные стороны он раздвигал неплохо. Пробуйте, изучайте тему, может быть, создадите что-то интересное — обязательно делитесь в комментарии результатами.
Ну а у меня на этом всё. Смотрите код из этой в моём репозитории на GitHub, не забывайте подписываться на мой телеграм-канал и до новых встреч!