Я в 2021: изучаю программирование, спрашиваю у своего руководителя, знает ли он, кто такой Джереми Тэммик, чтобы поделиться тем, как много интересной инфы нашёл у него. Он отвечает "конечно, кто ж его не знает"
Я в 2025: в очередной раз попадаю на страницы его блога (но в первый раз не в связи с работой над Revit Lookup)
https://thebuildingcoder.typepad.com/blog/2025/02/tools-for-extensible-storage-and-oauth-auth0.html
Я в 2025: в очередной раз попадаю на страницы его блога (но в первый раз не в связи с работой над Revit Lookup)
https://thebuildingcoder.typepad.com/blog/2025/02/tools-for-extensible-storage-and-oauth-auth0.html
👍14🔥9🆒3❤1
Тут вышла моя не очень большая, но очень интересная статья про утечки памяти в C#, нюансы подписки на события и отписки от них, и как не допустить мультивычисления в DockablePane. Читайте по ссылке
И не забывайте подписываться на LinkedIn моей компании
И не забывайте подписываться на LinkedIn моей компании
www.atomatiq.io
Memory leaks in Revit API applications | atomatiq
C# takes care of memory with automatic garbage collection, but leaks can still sneak in. Learn when they happen and how to prevent them.
🔥16👀7❤6👍5👏1
Всем привет, попробуем оживить канал🔥
Сегодня рассмотрим базовую тему с поиском элементов в коллекции. Допустим, у нас есть какой-то DTO (Data Transfer Object). Мы хотим в коллекции этих классов максимально быстро находить элементы, как нам это сделать?
Допустим, мы будем вести поиск по свойству 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 лучше делать тоже самое, там принцип такой же.
✔️Если вы попытаетесь получить элемент, которого нет в словаре, то вы получите исключение. Лучше всего не использовать метод ContainsKey(), потому что тогда вы сначала ищете по ключу, не пуста ли ячейка, а затем обращаетесь к ячейке — 2 вычисления, а использовать метод TryGetValue
✔️ У ключа вычисляется GetHashCode при добавлении/поиске в словаре. Это значит, что если мы используем какой-то свой класс в качестве ключа, то нам надо переопределить GetHashCode, иначе мы можем получить неожиданный результаты, когда будем предполагать, что отправили в словарь 2 одинаковых объекта (но хэш-коды то у них разные!). Поэтому сложные классы следует использовать в качестве ключей с большой осторожностью.
Спасибо всем за внимание, не забывайте ставить реакции если было интересно! До новых встреч!
Сегодня рассмотрим базовую тему с поиском элементов в коллекции. Допустим, у нас есть какой-то 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 одинаковых объекта (но хэш-коды то у них разные!). Поэтому сложные классы следует использовать в качестве ключей с большой осторожностью.
Спасибо всем за внимание, не забывайте ставить реакции если было интересно! До новых встреч!
❤25👍19🔥13🎉8🤯4🆒2✍1💯1🏆1
Ключевое слово record: что это и зачем используется?
Допустим, мы хотим создать какой-то класс для описания сущностей (DTO — Data Transfer Object). Мы можем написать его 2 способами:
1. Обычный класс. Тут вы всё и так знаете
Где стоит применять record?
Вообще, вы можете применять где угодно, вас никто не осудит. Скорость работы у него практически такая же, как и у обычного класса, дело только в удобстве. Но понятно, что сложные сервисы, ViewModel, статические классы или классы с большим числом свойств или логики делать record-ами не стоит.
А вот маленькие классы, которые появляются часто, которые сравниваются друг с другом, записи из базы данных, объекты, описывающие элементы Revit — вот тут это может быть полезно. Их неизменяемость тоже может стать плюсом — однажды создав их, вы можете быть уверены, что все свойства соответствуют истине, сравнить старую версию с новой. Но это же и ограничивает сферу применения 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-ов — мы не можем использовать их для объектов, значения полей которого меняет пользователь.
В общем, для кого-то это может быть обычный синтаксический сахар, а кто-то сделает с их помощью свою работу более быстрой и эффективной. Спасибо вам за внимание и отличных выходных!
И конечно же, передаю лучи любви моим дорогим подписчикам в День Святого Валентина 💘
Дзен | Статьи
JetBrains Rider — теперь бесплатная IDE. Почему лучше выбрать его вместо Visual Studio
Статья автора «Revit API и автоматизация Revit с нуля» в Дзене ✍: .Net-разработчики делятся на 2 типа: те, кто любят Rider, и те, кто ещё его не пробовал.
❤11👍8🔥3✍1🤩1🏆1😈1
Всем привет, сегодня поговорим про стили кода, расскажу, как я осуществляю ветвление в циклах 🌴
Довольно часто начинающие ревит-апи-разработчики понимают, что Revit API готовит нам кучу сюрпризов, в которых наша программа может вылететь. Метод пришлёт null вместо элемента или параметра, элемент окажется не валидным или ещё что-то. И в результате получается код типа такого:
Я уже не стал вас мучать, и добавлять тут try-catch и транзакции, но вы можете о них почитать мои статьи по ссылкам, если забыли что это (не забудьте тогда поставить им лайк) — вложенность и так высокая вышла, код уехал направо.
А как бы я написал этот код:
С точки зрения быстродействия это точно такой же код, единственная разница — в читаемости. Я инвертировал условия if и для ненужного нам варианта поставил continue;
В чём я тут вижу преимущества:
✔️меньше фигурных скобок и пустых строк
✔️меньше вложенности, код выравнивается по левому краю, удобнее читать
✔️ну и главное: когда мы перечитываем свой код, или код другого человека, нам не надо думать "а в каком именно мы сейчас if, куда записать строку-изменения?". Мы всегда в актуальной ветке, мы просто отбросили не интересующие нас условия. Нам не интересно, что элемент — null или не валидный, нам интересно то, когда всё хорошо, и только эту ветку кода мы и держим в голове
Довольно часто начинающие ревит-апи-разработчики понимают, что 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 или не валидный, нам интересно то, когда всё хорошо, и только эту ветку кода мы и держим в голове
👍22❤8🔥5🌭1🏆1
Сегодня наконец-то пост только про Revit API, ура!!!
Недавно при разработке заметил интересный баг — у элемента есть общий параметр, но при попытке получить его через get_Parameter(guid) я получаю null.
Мой код в таком случае пытается добавить отсутствующий параметр, и получает исключение — параметр то уже добавлен. То есть параметр есть, накинут на категорию, но через код его получить нельзя. А потом каким-то образом появляется😳😳😳
Пока разбирался, заметил одну интересную особенность. Вы знали, в чём разница между свойствами элемента Parameters и ParameterMap? Ну, базово понятно — один возвращает ParameterSet, второй — ParameterMap. Читаем описание:
И у мапы:
То есть написано вроде бы чёрным по белому: все параметры, хранящиеся в элементе. Все. Всееее.
Но нюанс в том, что ParameterMap работает как словарь — он хранит пары ключ-значение. Ключом является строка. Но что если у нас 2 параметра имеют одно и тоже имя? Так разве сможет ParameterMap хранить все параметры???
К чему это я? Во время отладки я заметил, что число параметров в этих свойствах не совпадает, и написал вот такой код:
И что же я получил:
1. Для некоторых элементов ParameterMap даёт исключение при попытке получить его. Просто исключение без подробностей
2. В ParameterSet всегда больше элементов, чем в ParameterMap и в GetOrderedParameters(). Наверное, влияет как раз наличие повторяющихся параметров, ведь даже некоторые встроенные параметры имеют одно и тоже имя
Какие выводы тут можно сделать? Я бы сказал, никаких, ведь никто же не пользуется ParameterMap и GetOrderedParameters()? Но я всё таки сделаю 2 вывода:
1. Пишите такой код и такой API, чтобы другим людям были понятны ваши намерения. Не обманывайте ваших коллег и не пишите то, чего ваш код не делает
2. Теперь вы знаете, что более быстрый метод GetOrderedParameters() не всегда точный, и лучше всё таки этой штукой для получения всех параметров пользоваться с осторожностью
Ну и напомню про свою уже старую-старую статью, которая тут как нельзя в тему:
https://dzen.ru/a/ZWBZYKdnlk1FsVrV
Кстати, у меня на дзене всего 7 подписчиков до 1000. Так что кто не подписан там — можете меня порадовать, ну и реакции ставить тут не забывайте. До новых встреч!
Недавно при разработке заметил интересный баг — у элемента есть общий параметр, но при попытке получить его через 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. Так что кто не подписан там — можете меня порадовать, ну и реакции ставить тут не забывайте. До новых встреч!
Дзен | Статьи
5 вещей в Revit API, которые меня бесят
Статья автора «Revit API и автоматизация Revit с нуля» в Дзене ✍: Всем привет! Решил взять небольшую паузу по поводу технических статей, и написать ещё одно размышление. Сегодня — хейтерская статья. 1.
👍29❤9🔥7👏2🏆1🍓1👀1
Всем привет, вот и новый лонгрид от меня подъехал:
https://dzen.ru/a/aa1A0sIaASJfB5JA
Вам тоже спасибо, уважаемые подписчики, 1000 на дзене, очень приятно🥳
Восстанавливаю комменты в честь такого события
https://dzen.ru/a/aa1A0sIaASJfB5JA
Вам тоже спасибо, уважаемые подписчики, 1000 на дзене, очень приятно🥳
Восстанавливаю комменты в честь такого события
Дзен | Статьи
Обмен сообщениями между классами и модулями приложения
Статья автора «Revit API и автоматизация Revit с нуля» в Дзене ✍: Всем привет! Сегодня рассмотрим интересный функционал, который даёт нам библиотека Community.Toolkit — обмен сообщениями.
🔥13👍9❤2💅2🏆1😇1💊1
Новая статья — о том, что такое csproj-файл и как его модифицировать в удобный SDK-style. Всем хорошей рабочей недели!
Дзен | Статьи
Csproj-файл, что это, с чем едят и как можно его упростить. SDK-style .csproj.
Статья автора «Revit API и автоматизация Revit с нуля» в Дзене ✍: Сегодня расскажу про тему, которую начинающие программисты, особенно использующие Visual Studio, часто упускают из виду.
🔥11👨💻5❤3🏆1🍓1💅1
Врываюсь в этот понедельник с новой статьёй на дзене. Всем отличной рабочей недели!
Дзен | Статьи
Паттерн Result и управление потоком выполнения программы
Статья автора «Revit API и автоматизация Revit с нуля» в Дзене ✍: В этой статье я не буду открывать Америку — материалов про паттерн Result на любом языке очень много.
🔥13👍3❤1🏆1🍓1🤓1🤗1
Новая статья на канале — про ForgeTypeId, единицы измерения и обнаруженный мной баг Ревита в связи с этим. Как обычно, по ссылке
Дзен | Статьи
Единицы измерения в Revit и ForgeTypeId
Статья автора «Revit API и автоматизация Revit с нуля» в Дзене ✍: Если вы начинали свой путь в программировании под Ревит с Dynamo, то, наверное, помните магическое число 304,8 (или 0,3048).
👍12🥰4🏆3🍓1
В последнее время было несколько проектов, в которых я использовал гибкие настройки через Excel. Почему xlsx, а не json? Чтобы администрировать было удобно. Небольшой пример такой работы привожу в своей новой статье. А как это дальше применить — тут уже ваш полёт фантазии
Дзен | Статьи
Работа с Excel-настройками для плагина. Библиотека ClosedXML
Статья автора «Revit API и автоматизация Revit с нуля» в Дзене ✍: Всем привет!
🔥12👍7❤3🕊1
Уважаемые читатели, делюсь с вами радостной новостью. Год назад я пытался запустить свой веб-сайт, но столкнулся с некоторыми трудностями при его разработке, а также перестал легко находить новые темы для статей. Но в 2026 году, как видите, блог вернулся. А теперь я сделал и следующий шаг: я всё же запустил свой сайт:
https://mostbim.vercel.app/
пока он ещё не наполнен контентом, я только перенёс 5 статей из основного блога, и всё. Пока ещё нет комментариев, лайков, и прочей прикольной мишуры.
Но зато есть возможность показывать код в виде кода, который можно выделить и копировать, а не в виде скринов (не представляете, как меня это бесило и бесит каждый раз при написании статей на Дзене)
Сайт будет постепенно наполняться новыми фичами и новым контентом, так что следите за обновлениями. Возможно, поменяю в будущем доменное имя на более красивое.
Если вдруг у вас есть интересные темы для статей — пишите, обсудим, опубликую (и добавлю блок "Авторы" в меню).
Порадоваться за меня можно в комментариях, и поставив 🔥 этому посту. До новых встреч!!!
https://mostbim.vercel.app/
пока он ещё не наполнен контентом, я только перенёс 5 статей из основного блога, и всё. Пока ещё нет комментариев, лайков, и прочей прикольной мишуры.
Но зато есть возможность показывать код в виде кода, который можно выделить и копировать, а не в виде скринов (не представляете, как меня это бесило и бесит каждый раз при написании статей на Дзене)
Сайт будет постепенно наполняться новыми фичами и новым контентом, так что следите за обновлениями. Возможно, поменяю в будущем доменное имя на более красивое.
Если вдруг у вас есть интересные темы для статей — пишите, обсудим, опубликую (и добавлю блок "Авторы" в меню).
Порадоваться за меня можно в комментариях, и поставив 🔥 этому посту. До новых встреч!!!
mostbim.vercel.app
BIM & Revit API
Revit API blog by Sergei Nefedov
🔥57👍17❤7🏆2🍾2🍓1👨💻1🤗1🆒1👾1
Уважаемые коллеги, столкнулся с такой проблемой:
нужно загрузить в Ревит младшей (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: не пишите "так на том же форуме дальше написано: не оборачивайте загрузку в транзакцию, и ничего не блокируется". Действительно, не блокируется — но и семейство не загружается, я проверил
нужно загрузить в Ревит младшей (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: не пишите "так на том же форуме дальше написано: не оборачивайте загрузку в транзакцию, и ничего не блокируется". Действительно, не блокируется — но и семейство не загружается, я проверил
Autodesk Community
Loading a rfa file into a document using LoadFamily() freezes Revit UI
Hi, I have encountered a problem while using the Document.LoadFamily() api to load an rfa file into Revit 2019 and Revit 2020. The problem can cause the ribbon UI to freeze until manually moving the mouse to any ribbon button or just resizing the revit…
❤3🤔2😱2🌭1🏆1
Написал тут статью для сайта нашей компании про AI.
Для этой статьи сделал небольшую игрушку: ИИ-чат с Claude внутри Ревита, который сам пишет, компилирует и исполняет код (и от души поедает платные токены, но все же делает всякие приколюхи).
Почитать и посмотреть видео как это работает можно здесь или здесь (LinkedIn)
Желаю всем хороших длинных выходных!
Для этой статьи сделал небольшую игрушку: ИИ-чат с Claude внутри Ревита, который сам пишет, компилирует и исполняет код (и от души поедает платные токены, но все же делает всякие приколюхи).
Почитать и посмотреть видео как это работает можно здесь или здесь (LinkedIn)
Желаю всем хороших длинных выходных!
www.atomatiq.io
Agentic AI for Revit | atomatiq
Explore the future of BIM automation with our custom Agentic AI for Revit. Learn how we integrated Claude Code via a local Model Context Protocol (MCP) server to dynamically generate, compile, and execute C# scripts directly inside a live Revit session.
👍7🍾3🍓2😁1🤡1🏆1🙈1
Уважаемые читатели, публикую новую статью, сегодня об обмене данными между Ревитом и веб-приложениями
Это первая статья, первоначальная публикация которой идёт только на новом сайте. Немножко волнительно, ну да ладно
Почитать можно по ссылке
Это первая статья, первоначальная публикация которой идёт только на новом сайте. Немножко волнительно, ну да ладно
Почитать можно по ссылке
mostbim.vercel.app
Обмен информацией между Revit и Web-приложением
👍24🔥11🍓2🍾2🐳1
Всем привет. Немного изучил новую для себя тему — добавление графики в рабочее поле Ревит, и делюсь с вами этой информацией. Идеи реального применения вы можете придумать сами
Статья здесь
Статья здесь
mostbim.vercel.app
Добавление графики в рабочее поле Revit. Введение в ExternalServices
🔥13👍7❤4
Добрый день, уважаемые коллеги! Сегодня рассказываю, как легко и быстро запустить автоматическое Unit-тестирование вашего Ревит-плагина
Статья по ссылке тут
Статья по ссылке тут
mostbim.vercel.app
Введение в Unit-тестирование с использованием Revit
👍14❤7🆒4🦄3
Всем хорошей пятницы, уважаемые подписчики!
Сегодня хочу рассказать про новый продукт моего товарища Эрика: онлайн-платформу для поиска пересечений и работы с ними. Подробнее почитать о нём и попробовать на практике, вы можете на его канале. Подписывайтесь, пользуйтесь и давайте обратную связь автору
Скоро постараюсь выпустить ещё новых статей, не переживайте, контент будет 😊
Сегодня хочу рассказать про новый продукт моего товарища Эрика: онлайн-платформу для поиска пересечений и работы с ними. Подробнее почитать о нём и попробовать на практике, вы можете на его канале. Подписывайтесь, пользуйтесь и давайте обратную связь автору
Скоро постараюсь выпустить ещё новых статей, не переживайте, контент будет 😊
❤4🔥3🐳2👍1🥰1
Forwarded from IT4BIM (Erik Gette)
❗️❗️❗️Пристегните ремни, мы взлетаем 🛫🛫🛫
Встречайте ClashFlow-первая цифровая платформа
по поиску и устранению
пересечений строительных
конструкций на основе
технологии BIM.
смотрите тут 🔥
От настройки до результата — один автоматизированный цикл
Платформа связывает актуальные данные, автоматический запуск, рабочие места инженеров и инфраструктуру компании.
Координатор один раз задает параметры и расписание — дальше система сама готовит модели, проверку и отчет.
Источники моделей, серверная обработка и рабочие места соединяются единым API.
Мы даем не еще один плагин , а выстроенный процесс!
Встречайте ClashFlow-первая цифровая платформа
по поиску и устранению
пересечений строительных
конструкций на основе
технологии BIM.
смотрите тут 🔥
От настройки до результата — один автоматизированный цикл
Платформа связывает актуальные данные, автоматический запуск, рабочие места инженеров и инфраструктуру компании.
Координатор один раз задает параметры и расписание — дальше система сама готовит модели, проверку и отчет.
Источники моделей, серверная обработка и рабочие места соединяются единым API.
Мы даем не еще один плагин , а выстроенный процесс!
it4bim.ru
IT4BIM ClashFlow
ClashFlow — цифровая платформа для поиска, обработки и устранения BIM-коллизий.
🔥10❤5👍3🤔1
Обычно я не выкладываю статью в выходные дни, но в день памяти Виктора Цоя решил сделать исключение. Статья правда не связана с ним никак, разве что картинкой на обложке.
Тем не менее, я попытался разобраться, как библиотека Revit API взаимодействует с Revit под капотом, и что это значит для нас. Сегодня без сложных выкладок и кодов, просто приятное чтение. Читать здесь
Тем не менее, я попытался разобраться, как библиотека Revit API взаимодействует с Revit под капотом, и что это значит для нас. Сегодня без сложных выкладок и кодов, просто приятное чтение. Читать здесь
mostbim.vercel.app
Взаимодействие Revit API с нативным Revit-кодом
🔥12