Расскажу по-простому, что такое Ревит АПИ, зачем оно нужно и как с ним работать в Питоне внутри Динамо. После этой статьи сможем начать практику на реальных задачах, потому что без АПИ мы не можем взаимодействовать с элементами проекта через Питон.

Что такое API по-простому
АПИ — это application programming interface, интерфейс для программирования приложений. По сути это такой набор команд, который нам предоставляет разработчик программы, чтобы мы могли обращаться к его программе через нашу программу.
Например, в Ревите есть инструмент для построения трубы. Это кнопка на ленте, мы её нажимаем и определённым алгоритмом рисуем трубу, мы это делаем руками в интерфейсе самого Ревита. В Ревит АПИ есть команда для такого же действия, но не руками, а помощью другой программы. В нашем случае это скрипт в Динамо или какой-нибудь плагин. Мы пишем команду, наш скрипт обращается по этой команде в Ревит, Ревит понимает, что от него надо, и делает то, что говорит наш скрипт.
Эту команду надо написать по правилам, которые описаны в Ревит АПИ. Напишем иначе — ничего не получится, Ревит не поймёт, когда мы к нему обратимся. Можно воспринимать эти команды как заклинания: если скажете левиоса неправильно, то магии не будет, но если сделаете всё правильно, то ваше перышко полетит.
Списки этих команд обычно хранятся в специальных файлах dll, например RevitAPI.dll. DLL — это динамически подключаемая библиотека. Книжки в этой библиотеке — это наш набор команд.
Итого. Ревит АПИ — это конкретный набор команд, с помощью которых мы можем через наши скрипты и плагины получать данные из модели, менять и создавать элементы модели. Ревит АПИ довольно большое и плохо описано, то есть сложно найти алгоритм, как и что делать. Некоторыми алгоритмами делился в своём блоге Джереми Таммик, но там всё на Си шарпе, хотя и оттуда можно выцедить информацию для работы в Питоне.
Нам дали кучу всего, но как это применять обычно люди исследуют на практике. Что-то получается несложно, что-то вообще неочевидно. Но таков путь, другого нет. Я покажу, что знаю, а дальше уже будете сами искать методы и способы. Есть хорошее сообщество в Телеграме, где всегда помогут и обосрут Питон.
Что такое API по-сложному
Не знаю.
Подключение API в Питон-скрипт
Чтобы взаимодействовать с АПИ внутри Питона в Динамо, нам нужно подключить эти самые библиотеки с командами. Иначе получится ситуация, что мы пишем какой-то текст, а Питон не понимает, что это команды, а не хухры-мухры. Для этого в начале любого кода объявляют ссылки на библиотеки.
Если создать Питон-нод по умолчанию, то там тоже будет уже готовый код:

Это тоже импортирование всяких библиотек. Но здесь у нас только библиотека для работы с геометрией внутри Динамо. Я с геометрией не работаю, я работаю с элементами модели и их свойствами. Поэтому нужно загрузить другой код вместо этого. У меня по умолчанию это вот такой:
import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager as DM
from RevitServices.Transactions import TransactionManager as TM
doc = DM.Instance.CurrentDBDocument
TM.Instance.EnsureInTransaction(doc) # Открытие транзакции
### Действия внутри транзакции ###
TM.Instance.TransactionTaskDone() # Закрытие транзакции
Что тут для чего. Сперва идёт импорт clr — это common language runtime, хрен его знает, зачем, но без него ничего работать не будет, надо оставлять. Говорят в интернете, что это среда для выполнения кода на нескольких языках программирования. Стало понятнее? Мне — нет.
Дальше мы подгружаем Ревит АПИ, строка from Autodesk.Revit.DB import *
означает, что мы подгружаем все-все команды из Autodesk.Revit.DB
— эта штука называется пространство имён. По сути эти имена — это определённая глава в книге с командами.
Затем грузим Ревит Сервисы, оттуда берём Менеджер Документов и Менеджер Транзакций. Они нужны, чтобы получить доступ к текущему документу и чтобы менять элементы внутри документа. При подгрузке сразу даём им имена DM и TM, чтобы в будущем делать более короткие записи команд.
Вот эти вот короткие имена DM и TM называются алиасы. Они нужны для более короткой и быстрой записи кода, так как зачастую код будет представлять собой длинные цепочки команд через точки. Их неудобно читать, поэтому можно создавать такие вот короткие обозначения.
Строкой doc = DM.Instance.CurrentDBDocument
мы обращаемся к менеджеру документов и в переменную doc записываем текущий документ.
Дальше идут строки для открытия и закрытия транзакций. Они нужны в том случае, если мы вносим изменения в документ: записываем значения в параметры элементов, создаём или удаляем элементы, двигаем их или копируем. Если вам нужны только значения параметров, то транзакции объявлять не нужно.
Автоматическая подгрузка библиотек
Можно сделать так, чтобы при создании Питон-нода у вас сразу был конкретный код, а не тот, что по умолчанию. В теории вы туда можете напихать вообще всё, что хотите, а потом при работе удалять лишнее.
Чтобы добавить свой код, идите по пути: %appdata%\Roaming\Dynamo\Dynamo Revit
, далее нужно зайти в папку Динамо нужной версии. Внутри cоздайте файлик PythonTemplate.py
, где .py — это расширение (сокращение от python). Внутри пишите нужный вам код, можете взять тот, что указал выше. Или взять с сайта справки Динамо, заодно почитайте альтернативный способ замены кода в Питон-ноде. Можно всё это сделать в блокноте, сохранить как txt, а потом переписать txt на py.

Теперь мы можем работать с Ревит АПИ в Питоне для Динамо.
Но сперва ещё нужно установить специальный плагин в Ревит, с помощью которого мы сможем смотреть на элементы с точки зрения того, что с ними можно сделать через АПИ. Плагин называется Ревит Лукап, он бесплатный, берите на Гитхабе проекта.
На Гитхабе переходите на страницу нужной версии плагина, крутите вниз до заголовка Assets, там будет список ссылок на скачивание для всех версий.

Мультиюзер — это установка плагина для всех пользователей на компьютере, сингл — только для одного пользователя. Если делите компьютер с бабушкой, которая тоже работает в Ревите, но не любит программирование, то выбирайте СинглЮзер.
Скачали, запустили установщик, Ревит при этом нужно закрыть. Потом запустите, вылетит сообщение о загрузке плагина, нажмите «Всегда загружать». Вот теперь вы хакер, вот теперь вы крутой.
Про работу с Ревит Лукапом можете прочитать в другой моей статье, но в дальнейшем я всё равно буду показывать работу с ним, просто не буду разжёвывать сильно подробно:
Сайт Ревит АПИ. Свойства и методы элементов
Через Ревит АПИ мы можем получить в Питоне свойства элементов или применять к ним разные методы.
Если по-простому, то свойства — это запрос информации, как если вы выделяете элемент в модели и смотрите в окно свойств. Методы — это воздействие на элементы, то есть создание, удаление, перемещение, изменение свойств. Всё это есть в АПИ, соответственно, когда мы пишем определённые команды, то так мы либо получаем значения свойств, либо что-то меняем через методы.
В начале статьи я писал про создание трубы руками и через АПИ. Давайте покажу на этом примере, как всё примерно работает. Как делать руками, вы знаете, но на всякий случай вот алгоритм:
- Активируем инструмент «Труба».
- В свойствах выбираем тип трубы и тип системы.
- Выбираем диаметр и отметку трубы.
Уровень обычно подхватывается текущий, но его тоже можно поменять. - Указываем первую точку и вторую точку построения трубы.
Как альтернатива можем указывать началом или концом существующие соединители в модели. - После второго клика мышкой в модели получаем готовую трубу.
Теперь, как это сделать в Питоне с помощью Ревит АПИ. Сперва идём на сайт Ревит АПИ: https://www.revitapidocs.com/, наверху выбираем версию Ревита. В разных версиях АПИ может меняться, в том числе могут удалять или переименовывать то, что было раньше. Это бесит.
Откроется страница, слева мы видим строку поиска и ниже список под заголовком Namespaces — пространства имён. Термин пришёл из программирования, можете воспринимать это как сборник команд, который поделён на разделы. Например, команды для работы с трубами и системами трубопроводов будут в разделе Autodesk.Revit.DB.Plumbing, так вот называется это пространство имён.
Внутри пространства имён сидят классы. Это пришло их объектно-ориентированного программирования, если просто, то класс — это такой шаблон элемента, в котором прописывается, какие у него есть свойства и методы. В Ревите есть свой набор классов, доступ к нему мы через АПИ и получаем. Когда будете писать свои программы, там вы тоже будете создавать свои классы.
Если приглядитесь к именам классов, то увидите довольно много знакомых слов, так как по сути это всё то, что мы видим в Ревите и с чем взаимодействуем. Например, FlexPipe Class — это класс для экземпляра гибкой трубы, а FlexPipeType Class — это класс для типоразмера гибкой трубы. У экземпляра и типа гибкой трубы разный набор свойств и методов, поэтому это разные классы.


Кроме классов тут есть ещё Интерфейсы и Энумераторы. Что такое интерфейсы я не знаю, а энумераторы — это фиксированные списки значений. Например, есть PipeSystemType Enumeration. Это по сути список классификации систем для труб в Ревите. Если посмотрите внутри проекта, то список классификаций систем ограничен, мы не можем создавать свои, только использовать готовые. И вот список этих классификаций есть в Энумераторе.

При этом обратите внимание на столбец Value — здесь мы видим значения, которые получим при запросе классификации системы с элемента. То есть при получении свойства мы увидим число, и вот по этому числу придётся уже определять, что там за классификация конкретно.
Например, в старых Ревитах можно было получить форму соединителя воздуховода в виде текста: "round", "rectangular" и так далее. А потом они поменяли систему, и вместо словесных обозначений стали числа. Теперь для круглого соединителя будет 0, для прямоугольного 1 и так далее. Это могло ломать скрипты, основанные на старой логике обозначений. Поэтому надо обращать внимание на то, что там возвращается в свойствах.
Теперь вернёмся к нашей трубе. Труба — это pipe, поэтому ищу Pipe Class, разворачиваю и вижу вот такую картину:

Внутри Пайп класса есть мемберсы, методы и пропертисы. Мемберсы — это члены, получайте члены, так как вы теперь программист. Неожиданно, понимаю. Члены — это все методы и свойства, которые доступны для класса, просто список всего, что доступно.
Методы — это действия, которые можно совершать над трубой, в том числе её создание.
Пропертис — это свойства, то есть информация, которую можно получить с трубы.
Если нажать на методы, то слева в дереве будет короткий список, а справа будет большой перечень методов. Отличие в том, что слева вы видите методы, которые присущи только этому классу, а справа — все методы, которые можно применить к этому классу, в том числе методы, которые наследуются от классов уровнем выше.

В объектно-ориентированном программировании одно из важных свойств — это наследование. В нашем случае есть класс под названием Element, это просто абстрактный элемент, и почти любой объект в нашей модели — это какой-то элемент. Труба — это другой класс, но в иерархии она является подклассом элемента, поэтому наследует с класса Элемент его методы и свойства.
Поэтому справа у нас много всего. Если посмотрите на описание методов, то у некоторых есть примечание в скобках, что метод наследован с класса элементов:

Так как мне нужно создать трубу, то я ищу метод создать — Create. Проще всего найти его в меню слева и там нажать. Откроется страница, где можно выбрать разные методы Create.

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

Тут есть описание, оно гласит: [метод] создаёт новую трубу, которая подключается к двум существующим соединителям. То есть с помощью этого метода можно создать трубу между существующими элементами с точками подключения к трубе.
В синтаксисе есть пример записи на языке Си Шарп, как нужно писать метод, что в него нужно подать. Тут нам важно только то, что в скобках, это такая расшифровка с комментариями:
public static Pipe Create(
Document document,
ElementId pipeTypeId,
ElementId levelId,
Connector startConnector,
Connector endConnector
)
В скобках после объявления метода Create мы должны через запятую перечислить:
- Документ, то есть проект, в котором создаём трубу.
- Айди типа трубы.
- Айди уровня, на котором создаём трубу.
- Соединитель для начала трубы.
- Соединитель для конца трубы.
Начало и конец трубы будут определять вектор её построения. Он не повлияет на передачу расхода, он влияет на геометрию трубы, иногда вектор построения важен, но сейчас это не особо важно.
Сравните этот список со списком выше для ручного построения. Тут очень много пересечений, так как логика построения что в интерфейсе Ревита, что через АПИ похожа, ведь мы создаём одно и то же.
В ручном методе мы не указывали документ, потому что по умолчанию все действия выполняются внутри текущего проекта. Тип трубы мы указываем явно руками в свойствах трубы, через АПИ указываем айди типа трубы. Уровень тоже подхватывается обычно сам, но можем и в свойствах поменять руками. Через АПИ надо явно указать айди уровня. Айди элемента и сам элемента — это не одно и то же. Ну и соединители в ручном режиме мы выбираем руками, стыкуем по ним трубы, а тут указываем сами соединители.
Чего мы не делаем, так это не указываем диаметр трубы. Потому что в данном случае диаметр, а также тип системы, наследуются с соединителя.
Если строить трубу просто в воздухе, то нужно выбрать другой метод — Create Method (Document, ElementId, ElementId, ElementId, XYZ, XYZ). В нём мы указываем документ, айди типа системы, айди типа трубы, айди уровня, координаты начала и конца трубы. Это чуть ближе к ручному созданию трубы в воздухе.
public static Pipe Create(
Document document,
ElementId systemTypeId,
ElementId pipeTypeId,
ElementId levelId,
XYZ startPoint,
XYZ endPoint
)
Диаметра трубы тут нет, потому что он задаётся после создания трубы через редактирования свойств. Давайте посмотрим, как это происходит и на этом закончим.
Создание трубы в Питоне
Создаю Питон-скрипт. Нам понадобятся тип системы, тип трубы и уровень для создания. Их можно взять внутри Питона, а можно получить через Динамо и подать в Питон-нод. Координаты придумаем сами.
Я выберу второй способ, так как так будет нагляднее. Получаю типы системы и трубы, а также уровень, пусть это будет первый этаж. Пусть будет система ADSK_Отопление_Т11, это 8 индекс в списке. Тип трубы в проекте один, уровень уже выбрал. При этом мне нужны айди, а не сами эти элементы.


Теперь идём в Питон-нод. Надо создать переменные для исходных данных. Запишу их в том порядке, в каком они идут в методе создания трубы. И подам данные на входе в Питон.
import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager as DM
from RevitServices.Transactions import TransactionManager as TM
doc = DM.Instance.CurrentDBDocument
pipe_system_type_id = IN[0]
pipe_type_id = IN[1]
level_id = IN[2]import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager as DM
from RevitServices.Transactions import TransactionManager as TM
doc = DM.Instance.CurrentDBDocument
pipe_system_type_id = IN[0]
pipe_type_id = IN[1]
level_id = IN[2]
В Динамо айди элемента — это целое число. В метод нам нужно подать ElementId. Это не совсем число, поэтому нужно преобразовать число в этот самый элемент айди. Проверяется это так: на странице метода по созданию трубы нажимаем по ElementId, потом нажимаем слева на мемберсы и смотрим на конструктор — на то, как создавать такой элемент.




Если прощёлкать по всем ссылкам, как я выше, то видим, что ElementId создаётся через одноименную команду и в скобках подаём целое число — айди нашего элемента.
Поэтому я немного изменю запись в Питоне, в которой назначаю переменные айдишникам системы, типа трубы и уровня:
pipe_system_type_id = ElementId(IN[0])
pipe_type_id = ElementId(IN[1])
level_id = ElementId(IN[2])
То есть я получаю из Динамо целые числа, тут же их преобразую в ЭлементАйди и запишу значения в переменные.
Начало и конец трубы сделаем отдельными переменными. В них нужно указать XYZ. Это точка в трехмерном пространстве. Чтобы лучше понять, как такое записывать, делаем то же, что с ЭлементАйди. Прямо на странице с методом жму по тексту XYZ. Далее клик по мемберсам XYZ в меню слева, тогда справа увижу область Constructors, тут вижу что-то про создание точек.


Первый конструктор XYZ создаёт точку в нуле координат. Второй позволяет задать координаты точки. Нажму по нему, чтобы увидеть синтаксис записи. Он вот такой:
public XYZ(
double x,
double y,
double z
)
То есть пишу XYZ и в скобках указываю просто три числа. Пусть труба строится вдоль оси Х, поэтому точки будут у меня такими:
start_point = XYZ()
end_point = XYZ(1000, 0, 0)
Сразу проверю, получатся ли точки, вроде получились, но это ещё не факт, что в модели всё будет нормально. Возможно, что Ревит эту 1000 воспримет как 1000 футов, а не миллиметров. Скоро узнаем.

Важно! Это неудобно, но вот эти вот координаты отсчитываются от внутреннего начала проекта. То есть мы вроде как указываем уровень, хочется, чтобы и высоты отсчитывались от уровня, но нет, всё считается от внутреннего начала проекта.
Например, если задам отметки по координате Z равными 2000 мм, а уровнем выберу второй этаж, у которого отметка +3,300, то труба создастся на уровне второго этажа, но с отметкой -1300 мм.
Поэтому, если хотите указать смещение от уровня, то надо ещё вводить корректировку на расстояние от внутреннего начала до уровня. Такое себе, но вот так работает.
Теперь создам переменную new_pipe и в ней напишу команду по созданию трубы. Так как мы создаём элемент, то делать это нужно внутри транзакции. Выглядеть это будет так:
TM.Instance.EnsureInTransaction(doc) # Открытие транзакции
new_pipe = Plumbing.Pipe.Create(doc, pipe_system_type_id, pipe_type_id, level_id, start_point, end_point)
TM.Instance.TransactionTaskDone() # Закрытие транзакции

Разбираемся в синтаксисе. Что за Plumbing.Pipe такой?
В самом начале мы подгрузили команды из Ревит АПИ:

Здесь мы подгружали целиком всё пространство имён Автодеск.Ревит.ДБ. Внутри этого пространства имён есть пространство имён Plumbing. Мы оттуда брали наш метод Create. Внутри пространства имён Plumbing есть класс Pipe. Таким образом, когда пишем в начале Plumbing.Pipe, то мы как бы уточняем, из какого класса в пространств имён Автодеск.Ревит.ДБ берём команду Create. Ведь аналогичная команда есть и в других классах в рамках пространства имён.
Дальше имя самого метода и в скобках перечисляем через запятую атрибуты, что указаны на сайте Ревит АПИ. Делать это нужно обязательно в том порядке, в каком указано на сайте. Иначе перышко не взлетит.
До и после команды строки с открытием и закрытием транзакции. Как говорил выше, без этого мы не можем вносить изменения в модель. Просто примите как данность.
В итоге после запуска скрипта получаю трубу. Но есть незадача. Ревит реально воспринял координаты (1000, 0, 0) как футы, поэтому труба получилась длиной 304800 мм. Многовато.
Самое тупое и простое, что можно сделать — поделить 1000 на 304.8 в момент создания координаты. Выглядит отвратительно, но для одного примера пойдёт. Если делать полноценный скрипт, то каждую координату я бы всё равно совал в переменную, а уже переменную бы делил.

Труба построилась, но диаметр её странный:

Чтобы поменять диаметр трубы, поменяем внутри транзакции её свойство — диаметр. Для этого давайте посмотрим, как он выглядит в свойствах трубы через Ревит Лукап, чтобы знать, в каких единицах писать значение.
Выделяем трубу и нажимаем по Ревит Лукапу, выбираем Snoop Selection (Изучить выбранное).


В этом окне мы видим разнообразные свойства объекта. Под заголовком Element видим как раз те свойства, что труба наследует у класса Элемент. Так как мы хотим менять параметры, то ищем строку Parameters, она выделена жирным — значит, по ней можно нажать, и откроется ещё окно.
В этом окне будут свойства экземпляра. Тут будут как общие параметры, так и параметры проекта или встроенные параметры. Диаметр — это встроенный параметр. Он есть у трубы, потому что на уровне Ревита у класса Труба есть такое свойство. Поэтому абсолютно у любой трубы всегда будет такой параметр.

Что нам тут надо. Definition — для встроенных параметров это их внутреннее имя.
Далее смотрим StorageType — тип данных, тут у нас double, то есть дробное число. Поэтому далее смотрим на AsDouble — это то, в чём Ревит считает длину трубы внутри себя. Тут у нас 0.5. При этом ниже есть AsValueString — это значение в виде строки, обычно это то, что Ревит выводит в окне свойств с учетом единиц проекта. Видим, что тут есть расхождение, так как значение 152.4 мм совпадает с тем, что в свойствах трубы, но это никак не 0.5.
Всё потому, что снова вылезла имперская система единиц, в данном случае 0,5 — это футы. 1 фут = 304,8 мм, соответственно половина фута будет равна 152.4 мм. Что мы и получили в Ревите. Это значение не подходит, его нужно поменять.
Как это сделать в Питоне. Для этого нужно обратиться к параметру, а потом специальным методом Set() записать значение. Выглядит в коде это так, запишу сначала получение параметра, потом запись нового значения:
# получение значения
pipe_diameter = new_pipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).AsDouble()
# запись значения
pipe_diameter = new_pipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).Set(63/304.8)
В обоих случаях начало одинаковое. Что происходит: объявляю новую переменную pipe_diameter, это необязательно, если дальше диаметр нигде не нужен, можно просто писать код без переменной. Дальше беру свою трубу из переменной new_pipe, пишу через точку метод get_Parameter(), а в скобках пишу встроенное имя параметра. Чтобы Ревит понял, что это имя параметра, пишу сначала текст BuiltInParameter — то есть говорю, что это встроенный в программу параметр, а потом пишу это самое встроенное имя. Его как раз видим в Definition в Лукапе.
В Ревит АПИ нет метода get_Parameter(), там есть метод GetParameters(). В метод из АПИ подают имя параметра в виде строки, а возвращаются все параметры с этим именем. Пусть и маловероятно, но возможна ситуация, когда у элемента будет несколько параметров с одинаковым именем, что усложняет получение нужного значения.
Метод get_Parameter() удобно использовать со встроенными параметрами и их встроенными именами, а также по гуидам общих параметров. Это метод из Си Шарпа, но мы работаем в Питоне, почему метод срабатывает? Потому что мы в начале загрузили CRL.
Если нужно получать значения по имени параметра или из общего параметра, то чаще использую метод LookupParameter(). В скобки подаёте имя параметра в строковом виде.
После этого я получу сам параметр, а мне нужно его числовое значение. Для этого подписываю AsDouble(), это такой метод в программировании, чтобы получить значение в виде дробного числа. И чтобы знать, какой метод писать, я посмотрел тип хранения данных в Лукапе.
Есть нюанс — после такого вы получите значение в имперских единицах, в данном случае это будет как раз те самые 0.5 фута. Самое тупое и простое — домножьте значение на 304.8, получите миллиметры. Существуют методы для конвертации единиц, но мне они не нравятся, так как меняются в разных версиях Ревита. А домножение — тупое, но рабочее решение.
При этом так как у нас тип данных параметра по умолчанию — это футы, то и значение надо писать в футах. Поэтому во втором примере кода я обращаюсь точно так же к параметру, а потом использую метод Set(), в скобках которого пишу значение. Выбрал диаметр 63 мм, он есть у такой трубы. Ну и делю на 304.8, чтобы перевести в футы.

В итоге сразу получаю трубу нужной длины и диаметра. В этом случае, кстати, Ревит и сегмент трубы заполнит нормально, потому что в первом случае с диаметром в полфута параметр «Сегмент трубы» был пустым, так как у данного типа трубы нет такого диаметра в настройках сегмента, а потому параметр Ревит не заполнил.
Итоги
В статье рассказал, что такое Ревит АПИ и как пользоваться сайтом Ревит АПИ Докс. Всё на новичковом уровне, но пока этого достаточно.
Далее показал, как подгрузить в Питон библиотеки из Ревит АПИ и как добавить код по умолчанию, чтобы он сразу появлялся в Питон-ноде при его создании в Динамо. Это удобно, рекомендую тоже так сделать. Можете закинуть побольше кода, с запасом, а можете взять мой короткий код.
Разобрал пример, в котором с помощью Ревит АПИ создаём элемент в модели и потом читаем и меняем его свойства.
В следующих статьях будем ещё разбирать примеры, так что этот материал — базовый, надо в нём хорошо разобраться.



