Revit API на русском
СтатистикаАвтор блога: @nefedov_sa Пишите напрямую по вопросам рекламы, заказа плагинов, и по всем другим вопросам
- Последний пост
- 15 авг.
- Последнее чтение
- 13 авг.
- Постов за неделю
- 1
- Всего постов
- 21
- Тип
- открытый
- Язык
- русский
- В каталоге с
- 12 авг.
- 1/24сутки в ленте
- 242
- 1/48двое суток
- 277
- 1/72трое суток
- 299
Оценка по просмотрам недавних постов: пост набирает почти всё за первые сутки.
Посты
видео или голосовое, без подписи
❗️❗️❗️Пристегните ремни, мы взлетаем 🛫🛫🛫 Встречайте ClashFlow-первая цифровая платформа по поиску и устранению пересечений строительных конструкций на основе технологии BIM. смотрите тут 🔥 От настройки до результата — один автоматизированный цикл Платформа связывает актуальные данные, автоматический запуск, рабочие места инженеров и инфраструктуру компании. Координатор один раз задает параметры и расписание — дальше система сама готовит модели, проверку и отчет. Источники моделей, серверная обработка и рабочие места соединяются единым API. Мы даем не еще один плагин , а выстроенный процесс!
Всем хорошей пятницы, уважаемые подписчики! Сегодня хочу рассказать про новый продукт моего товарища Эрика: онлайн-платформу для поиска пересечений и работы с ними. Подробнее почитать о нём и попробовать на практике, вы можете на его канале. Подписывайтесь, пользуйтесь и давайте обратную связь автору Скоро постараюсь выпустить ещё новых статей, не переживайте, контент будет 😊
Добрый день, уважаемые коллеги! Сегодня рассказываю, как легко и быстро запустить автоматическое Unit-тестирование вашего Ревит-плагина Статья по ссылке тут
Всем привет. Немного изучил новую для себя тему — добавление графики в рабочее поле Ревит, и делюсь с вами этой информацией. Идеи реального применения вы можете придумать сами Статья здесь
Уважаемые читатели, публикую новую статью, сегодня об обмене данными между Ревитом и веб-приложениями Это первая статья, первоначальная публикация которой идёт только на новом сайте. Немножко волнительно, ну да ладно Почитать можно по ссылке
Написал тут статью для сайта нашей компании про AI. Для этой статьи сделал небольшую игрушку: ИИ-чат с Claude внутри Ревита, который сам пишет, компилирует и исполняет код (и от души поедает платные токены, но все же делает всякие приколюхи). Почитать и посмотреть видео как это работает можно здесь или здесь (LinkedIn) Желаю всем хороших длинных выходных!
Уважаемые коллеги, столкнулся с такой проблемой: нужно загрузить в Ревит младшей (2022-...) версии семейства старшей (2021) версии с сервера. Какие есть варианты: 1. Хранить на сервере отдельно семейства для каждой версии Ревит. Плюсы: у пользователя нет всплывающих окон об обновлении, быстрая загрузка. Минусы: обновление библиотеки семейств ведёт к тому, что надо обновлять их во всех папках всех версий, для чего нужен как минимум компьютер со всеми установленными версиями. Но даже так по идее придётся запускать вручную каждую версию, ждать обновления файла с семействами и жать на кнопку "Загрузить", это долго 2. Загружать как есть. И тут проблема: если загрузить через API старое семейство, то оно обновится, но при этом UI Ревита жёстко заблокируется. Есть указанное здесь решение (https://forums.autodesk.com/t5/revit-api-forum/loading-a-rfa-file-into-a-document-using-loadfamily-freezes/m-p/10143488). Суть такая: с помощью библиотеки AdWindows вызываем следующий код: public static void ShowBalloonTip(string msg) { Autodesk.Internal.InfoCenter.ResultItem ri = new Autodesk.Internal.InfoCenter.ResultItem(); ri.Title = msg; // showing ballon tip for the shortest amount of time. Autodesk.Windows.ComponentManager .InfoCenterPaletteManager.Configuration.BalloonDisplayPeriod = 1; // Max transparency for the LoadFamily fix to work. Autodesk.Windows.ComponentManager .InfoCenterPaletteManager.Configuration.BalloonTransparency = 80; Autodesk.Windows.ComponentManager .InfoCenterPaletteManager.ShowBalloon(ri); } Оно классное, оно работает. Минус — в правом верхнем углу Ревита вылезает всплывающая подсказка. Мелочь, но хотелось бы совсем без неё Если кто знает рабочий и проверенный метод, как решить эту задачу, пожалуйста, поделитесь в комментариях PS: не пишите "так на том же форуме дальше написано: не оборачивайте загрузку в транзакцию, и ничего не блокируется". Действительно, не блокируется — но и семейство не загружается, я проверил
Уважаемые читатели, делюсь с вами радостной новостью. Год назад я пытался запустить свой веб-сайт, но столкнулся с некоторыми трудностями при его разработке, а также перестал легко находить новые темы для статей. Но в 2026 году, как видите, блог вернулся. А теперь я сделал и следующий шаг: я всё же запустил свой сайт: https://mostbim.vercel.app/ пока он ещё не наполнен контентом, я только перенёс 5 статей из основного блога, и всё. Пока ещё нет комментариев, лайков, и прочей прикольной мишуры. Но зато есть возможность показывать код в виде кода, который можно выделить и копировать, а не в виде скринов (не представляете, как меня это бесило и бесит каждый раз при написании статей на Дзене) Сайт будет постепенно наполняться новыми фичами и новым контентом, так что следите за обновлениями. Возможно, поменяю в будущем доменное имя на более красивое. Если вдруг у вас есть интересные темы для статей — пишите, обсудим, опубликую (и добавлю блок "Авторы" в меню). Порадоваться за меня можно в комментариях, и поставив 🔥 этому посту. До новых встреч!!!
В последнее время было несколько проектов, в которых я использовал гибкие настройки через Excel. Почему xlsx, а не json? Чтобы администрировать было удобно. Небольшой пример такой работы привожу в своей новой статье. А как это дальше применить — тут уже ваш полёт фантазии
Новая статья на канале — про ForgeTypeId, единицы измерения и обнаруженный мной баг Ревита в связи с этим. Как обычно, по ссылке
Врываюсь в этот понедельник с новой статьёй на дзене. Всем отличной рабочей недели!
Новая статья — о том, что такое csproj-файл и как его модифицировать в удобный SDK-style. Всем хорошей рабочей недели!
Всем привет, вот и новый лонгрид от меня подъехал: https://dzen.ru/a/aa1A0sIaASJfB5JA Вам тоже спасибо, уважаемые подписчики, 1000 на дзене, очень приятно🥳 Восстанавливаю комменты в честь такого события
Сегодня наконец-то пост только про Revit API, ура!!! Недавно при разработке заметил интересный баг — у элемента есть общий параметр, но при попытке получить его через get_Parameter(guid) я получаю null. Мой код в таком случае пытается добавить отсутствующий параметр, и получает исключение — параметр то уже добавлен. То есть параметр есть, накинут на категорию, но через код его получить нельзя. А потом каким-то образом появляется😳😳😳 Пока разбирался, заметил одну интересную особенность. Вы знали, в чём разница между свойствами элемента Parameters и ParameterMap? Ну, базово понятно — один возвращает ParameterSet, второй — ParameterMap. Читаем описание: Retrieves a set containing all of the parameters that are contained within the element. И у мапы: Retrieves a map containing all of the parameters that are contained within the element. То есть написано вроде бы чёрным по белому: все параметры, хранящиеся в элементе. Все. Всееее. Но нюанс в том, что ParameterMap работает как словарь — он хранит пары ключ-значение. Ключом является строка. Но что если у нас 2 параметра имеют одно и тоже имя? Так разве сможет ParameterMap хранить все параметры??? К чему это я? Во время отладки я заметил, что число параметров в этих свойствах не совпадает, и написал вот такой код: public override void Execute() { var elements = Document.EnumerateInstances<ElectricalSystem>(); var count = 0; foreach (var element in elements) { try { var pSet = element.Parameters; var pMap = element.ParametersMap; var orderedParameters = element.GetOrderedParameters(); if (pSet is null || pMap is null || orderedParameters is null) { continue; } if (pMap.Size != pSet.Size || pSet.Size != orderedParameters.Count) { count++; } } catch (Exception e) { Debug.WriteLine(e); } } } И что же я получил: 1. Для некоторых элементов ParameterMap даёт исключение при попытке получить его. Просто исключение без подробностей 2. В ParameterSet всегда больше элементов, чем в ParameterMap и в GetOrderedParameters(). Наверное, влияет как раз наличие повторяющихся параметров, ведь даже некоторые встроенные параметры имеют одно и тоже имя Какие выводы тут можно сделать? Я бы сказал, никаких, ведь никто же не пользуется ParameterMap и GetOrderedParameters()? Но я всё таки сделаю 2 вывода: 1. Пишите такой код и такой API, чтобы другим людям были понятны ваши намерения. Не обманывайте ваших коллег и не пишите то, чего ваш код не делает 2. Теперь вы знаете, что более быстрый метод GetOrderedParameters() не всегда точный, и лучше всё таки этой штукой для получения всех параметров пользоваться с осторожностью Ну и напомню про свою уже старую-старую статью, которая тут как нельзя в тему: https://dzen.ru/a/ZWBZYKdnlk1FsVrV Кстати, у меня на дзене всего 7 подписчиков до 1000. Так что кто не подписан там — можете меня порадовать, ну и реакции ставить тут не забывайте. До новых встреч!
Всем привет, сегодня поговорим про стили кода, расскажу, как я осуществляю ветвление в циклах 🌴 Довольно часто начинающие ревит-апи-разработчики понимают, что Revit API готовит нам кучу сюрпризов, в которых наша программа может вылететь. Метод пришлёт null вместо элемента или параметра, элемент окажется не валидным или ещё что-то. И в результате получается код типа такого: public void ChangeParameters() { var elements = GetElements(); foreach (Element element in elements) { if (element is not null) { if (element.IsValidObject) { var parameter = element.get_Parameter(ParameterGuid); if (parameter is not null) { var value = parameter.AsString(); if (value > AsDouble) { if (!parameter.IsReadOnly) { parameter.Set(BreakingValue); } } } } } } } Я уже не стал вас мучать, и добавлять тут try-catch и транзакции, но вы можете о них почитать мои статьи по ссылкам, если забыли что это (не забудьте тогда поставить им лайк) — вложенность и так высокая вышла, код уехал направо. А как бы я написал этот код: public void ChangeParameters() { var elements = GetElements(); foreach (Element element in elements) { if (element is null) continue; if (!element.IsValidObject) continue; var parameter = element.get_Parameter(ParameterGuid); if (parameter is null) continue; var value = parameter.AsDouble(); if (value <= BreakingValue) continue; if (parameter.IsReadOnly) continue; parameter.Set(BreakingValue); } } С точки зрения быстродействия это точно такой же код, единственная разница — в читаемости. Я инвертировал условия if и для ненужного нам варианта поставил continue; В чём я тут вижу преимущества: ✔️меньше фигурных скобок и пустых строк ✔️меньше вложенности, код выравнивается по левому краю, удобнее читать ✔️ну и главное: когда мы перечитываем свой код, или код другого человека, нам не надо думать "а в каком именно мы сейчас if, куда записать строку-изменения?". Мы всегда в актуальной ветке, мы просто отбросили не интересующие нас условия. Нам не интересно, что элемент — null или не валидный, нам интересно то, когда всё хорошо, и только эту ветку кода мы и держим в голове
Ключевое слово record: что это и зачем используется? Допустим, мы хотим создать какой-то класс для описания сущностей (DTO — Data Transfer Object). Мы можем написать его 2 способами: 1. Обычный класс. Тут вы всё и так знаете public class ElementClassDto { public string Name { get; set; } = string.Empty; public int Id { get; set; } } 2. Класс-record (буквально — запись, он для этого и придуман): public record ElementRecordDto(string Name, int Id); Что же мы получаем, если используем вариант 2? По сути, это обычный класс, но с некоторыми важными отличиями, которые и делают его полезным: ✔️record-ы сравниваются по значению, а не по ссылке. Если мы создадим 2 record-а c одинаковыми значениями свойств, оператор == вернёт true, но для класса это будет false, если мы не переопределим операторы ==, != и метод Equals(). Это достигается очень просто: record компилируется в класс, где эти методы переопределены: Тут я бы хотел показать вам Low-Level C# код, который можно посмотреть через Rider после сборки приложения, но он выглядит буквально так: return (object) other != null && Type.op_Equality(this.EqualityContract, other.EqualityContract) && EqualityComparer<string>.Default.Equals(this.<Name>k__BackingField, other.<Name>k__BackingField) && EqualityComparer<int>.Default.Equals(this.<Id>k__BackingField, other.<Id>k__BackingField); (да, это всё одна строка). Поэтому я покажу вам, как это выглядит примерно, не меняя сути: public override bool Equals(object? obj) => Equals(obj as ElementRecordDto); public virtual bool Equals(ElementRecordDto? other) { if (ReferenceEquals(this, other)) return true; if (other is null) return false; return Name == other.Name && Id == other.Id; } public static bool operator ==(ElementRecordDto? left, ElementRecordDto? right) => EqualityComparer<ElementRecordDto>.Default.Equals(left, right); public static bool operator !=(ElementRecordDto? left, ElementRecordDto? right) => !(left == right); Так что, если убрать подробности, мы получаем удобную вещь, которую легко сравнивать через ==, и это может упростить наш код ✔️У record по умолчанию переопределены методы ToString() и GetHashCode(). За счёт этого мы можем выводить записи в консоль или куда угодно, не переживая, что получим на выходе просто FullClassName. На практике применимо редко, но при отладке — очень удобно: public override string ToString() { return $"ElementRecordDto {{ Name = {Name}, Id = {Id} }}"; } ✔️ Свойства record неизменяемы (init-only) по умолчанию. Мы можем быть уверены, что если взяли его где-либо, данные актуальные: classDto.Name = recordDto.Name; //можно recordDto.Name = classDto.Name; //ошибка, не скомпилируется Где стоит применять record? Вообще, вы можете применять где угодно, вас никто не осудит. Скорость работы у него практически такая же, как и у обычного класса, дело только в удобстве. Но понятно, что сложные сервисы, ViewModel, статические классы или классы с большим числом свойств или логики делать record-ами не стоит. А вот маленькие классы, которые появляются часто, которые сравниваются друг с другом, записи из базы данных, объекты, описывающие элементы Revit — вот тут это может быть полезно. Их неизменяемость тоже может стать плюсом — однажды создав их, вы можете быть уверены, что все свойства соответствуют истине, сравнить старую версию с новой. Но это же и ограничивает сферу применения record-ов — мы не можем использовать их для объектов, значения полей которого меняет пользователь. В общем, для кого-то это может быть обычный синтаксический сахар, а кто-то сделает с их помощью свою работу более быстрой и эффективной. Спасибо вам за внимание и отличных выходных! И конечно же, передаю лучи любви моим дорогим подписчикам в День Святого Валентина 💘
Всем привет, попробуем оживить канал🔥 Сегодня рассмотрим базовую тему с поиском элементов в коллекции. Допустим, у нас есть какой-то DTO (Data Transfer Object). Мы хотим в коллекции этих классов максимально быстро находить элементы, как нам это сделать? public class ElementDto { public int Id { get; set; } public string Name { get; set; } public string ParameterValue { get; set; } } Допустим, мы будем вести поиск по свойству Id, имеющему тип int. Ну, очевидное решение какое: запускаем цикл for/foreach, проверяем каждый элемент, если Id совпал, то мы нашли наш элемент, выходим из цикла через break, всё просто и понятно. Продвинутые пользователи скажут: нет, зачем нам писать цикл, мы просто используем метод FirstOrDefault() из LINQ, и найдём нужный объект, код станет читаеме и проще. Да вот только под капотом будет примерно тот же самый foreach, только ещё с созданием делегатов, замыканий, и в результате более медленный (для данной задачи — поиск элемента в коллекции по Id — да) Что если у нас 100.000 элементов, и мы часто к ним обращаемся, и хотим чтобы это было быстро? Ответ простой: нужно использовать Dictionary<TKey, TValue>, и в качестве TKey использовать простой тип данных (string / int / long). Доступ по индексу у словаря занимает константное время О(1). Это значит, что неважно, 5 элементов в словаре, 55 или 100500 — мы находим элемент всегда за одно и тоже время. Сравните с циклом foreach, который сделает в худшем в случае 100500 итераций! Но как так получается? Почему словарь работает так быстро? Как он ищет так быстро в коллекции любого объёма? Словарь не ищет ничего внутри себя. При добавлении элемента по ключу он вычисляет хеш-код ключа (кстати, для int — это значение самого int, вычисление очень быстрое), а затем вычисляет индекс ячейки в массиве в зависимости от того, какой сейчас capacity у словаря. И сразу кладёт элемент в эту ячейку. Когда мы хотим получить элемент, происходит тоже самое, вычисляется индекс ячейки и мы просто берём элемент из ячейки — словарю всё равно, сколько в нём элементов всего. Profit! Какие важные нюансы стоит учитывать: ✔️ Под капотом словаря есть массивы. Массивы, как вы помните, в C# имеют постоянную величину. Поэтому если вы знаете заранее, что у вас будет, например, 1000 элементов, задайте сразу в конструкторе capacity, например, 1300, чтобы уменьшить накладные расходы по переносу элементов из массива в массив и рехэширование (перевычисление индексов в массивах. Оно происходит каждый раз, когда наш словарь близок к переполнению по capacity. Со списками List лучше делать тоже самое, там принцип такой же. var dictionary = new Dictionary<int, ElementDto>(1300); ✔️Если вы попытаетесь получить элемент, которого нет в словаре, то вы получите исключение. Лучше всего не использовать метод ContainsKey(), потому что тогда вы сначала ищете по ключу, не пуста ли ячейка, а затем обращаетесь к ячейке — 2 вычисления, а использовать метод TryGetValue if (!TryGetValue(key, out ElementDto dto)) return; DoSomeAction(dto) ✔️ У ключа вычисляется GetHashCode при добавлении/поиске в словаре. Это значит, что если мы используем какой-то свой класс в качестве ключа, то нам надо переопределить GetHashCode, иначе мы можем получить неожиданный результаты, когда будем предполагать, что отправили в словарь 2 одинаковых объекта (но хэш-коды то у них разные!). Поэтому сложные классы следует использовать в качестве ключей с большой осторожностью. Спасибо всем за внимание, не забывайте ставить реакции если было интересно! До новых встреч!
Тут вышла моя не очень большая, но очень интересная статья про утечки памяти в C#, нюансы подписки на события и отписки от них, и как не допустить мультивычисления в DockablePane. Читайте по ссылке И не забывайте подписываться на LinkedIn моей компании
Я в 2021: изучаю программирование, спрашиваю у своего руководителя, знает ли он, кто такой Джереми Тэммик, чтобы поделиться тем, как много интересной инфы нашёл у него. Он отвечает "конечно, кто ж его не знает" Я в 2025: в очередной раз попадаю на страницы его блога (но в первый раз не в связи с работой над Revit Lookup) https://thebuildingcoder.typepad.com/blog/2025/02/tools-for-extensible-storage-and-oauth-auth0.html