Посмотрим, как можно округлить числа в Динамо, а потом перевести их в текст в нужном виде. Иногда это бывает нужно, чтобы сформировать текстовое примечание, например наименование элемента с его размерами или той же толщиной стенки.
Получу длины воздуховодов из модели.
Видно, что длина разная. Чтобы округлить есть два нода Round:
Первый нод просто берёт и округляет до целых. Второму можно указать количество знаков после запятой (digits). Пусть мне нужно округлить до двух знаков.
Если вам очень критичны эти ошибки округления, то решить проблему можно только с помощью дополнительного геморроя или Питон-кода.
Для площадей квартира эти копейки важны, конечно, но и сам Ревит округляет так же, как в Динамо, так что только геморрой!
Будьте осторожны, а мы переходим к переводу чисел в текст, ведь тут тоже есть заморочки. Начнём с нода: для этого есть нод String from Object. Проще всего его найти по запросу «tostring».
Этот нод может переводить разные типы данных в текст (или строку, это то же самое). Не только числа, но почти всё, что вы видите в выпадающих списках у нодов можно перебросить в текст. Айди элементов (цифры на зелёном фоне) переводится не будут.
Теперь давайте переведём число в текст и посмотрим, что будет. А будет вот так:
Как видите, основная проблема тут в лишних нулях, их называют трейлинг нули. Они появляются всегда, если вы подаёте дробное число, то есть переменную с типом данных double. С учётом того, что дробная часть везде разная, нужно не просто отрезать сколько-то знаков после точки, а в каждом случае определить, сколько нулей надо убирать.
Есть много разных способов это сделать, покажу тот, что использую сам. Он основан на нескольких нодах для обработки строк.
Расскажу алгоритм:
String.Split (Строка.Разделить)— нод делит строку по указанному разделителю на два значения: до разделителя и после. В итоге, если у меня есть два и более нолей, то я получаю на каждое число подсписок, в котором первой позицией идёт число до разделителя, а второй позицией — то, что после разделителя. Проще всего понять, если посмотреть на исходные числа и на результат. Далее нодом List.FirstItem (Список.ПервоеЗначение) я получаю первые значения из каждого подсписка. А что @L2 в нём — читайте в статье про уровни в списках.
По сути нод String.Split вышвыривает все лишние нули, оставляя только реально дробную часть. Теперь остаётся только убрать точки там, где они не нужны. Не нужны они там, где текст точкой заканчивается, поэтому использую нод String.EndsWith (Строка.ЗаканчиваетсяНа) для поиска позиций, которые оканчиваются точкой.
В результате получаю список из выражений true и false. True — текст заканчивается точкой, false — не закачивается. Где true — там надо убрать последний символ, то есть точку. Для этого буду использовать нод String.Remove (Строка.Удалить).
String.Remove работает так: нужно подать строку, которой делаем обрезание (ой-вэй), индекс начала (с какого символа начинаем удалять) и сколько символов удаляем. Логика такая: если строка оканчивается на точку, то надо удалить один символ, если не оканчивается, то ноль символов.
Поэтому надо получить нули и единицы, а также длину строки. Для этого использую нод String.Length (Строка.Длина). Подаю на него мою строку с текстом и получаю длину каждой строки. Длина в данном случае — это количество символов.
Нули и единицы получаю с помощью нода If (Если). На вход «test» подаю свой список true и false, на вход «true» — 1, на «false» — 0. В результате получаю список, в котором по сути все false заменились на нули, а true — на единицы.
Теперь важный момент: длина строки не равна индексу последнего символа. Если я сейчас подам длину строки на вход нода String.Remove, то получу ошибку. Дело в том, что индексы в программировании всегда начинают свой отсчёт от нуля, а не от единицы. Поэтому длина будет как бы на единицу больше, чем максимальное значение индекса. Разберём на примере.
Вот есть текст «3315.5». Его длина — 6 символов, то есть 6 знаков. Но индекс каждого символа будет отсчитываться с нуля. Обозначу индекс в виде [i], получится вот так:
[0]: 3
[1]: 3
[2]: 1
[3]: 5
[4]: .
[5]: 5
Таким образом, если я подам на String.Remove длину строки, то приду в несуществующий символ и получу ошибку. Поэтому я вычитаю один знак, тем самым как бы прихожу в последний символ строки.
А далее нод смотрит на количество знаков, которые надо удалить. Где точка на конце — будет удаляться один знак, где нет точки — ноль знаков, то есть строка останется без изменений.
В итоге получаю свои числа в текстовом виде с нужным количеством знаком. Длинно? Геморрно? Ну да, а что поделать. Более изящным способом было бы написать код в Питоне, но речь в статье про Динамо и ноды.
Пусть это дурацкий метод, но благодаря ему вы достигаете желаемого результата, но что ещё важнее — изучаете работу разных нодов.
Варианты решения с помощью Питона
Иван Волощенко поделился примером кода в Питоне, которым можно округлить числа до нужной величины. Текст после знака решётки — это комментарии, они не влияют на код, а просто поясняют его.
spis = IN[0] # список значений
kr = 0.01 # округлить до значения
spis = spis if type(spis)==list else [spis] # проверка списка
mas = [] # создаем пустой список для записи значений
for s in spis:
mas.append(round(s/kr)*kr)
OUT = mas
Или тоже самое, но в одну строку:
OUT = [round(s/kr)*kr for s in spis]
Чтобы отбросить трейлинг нули, я нашёл вот такой метод: rstrip().
Если у вас есть список из «бывших» чисел с нулями, то можно использовать такой цикл:
Понравилась статья?
Тогда можете сделать небольшое пожертвование (как это ни звучало) — любую удобную вам сумму.
Новые статьи удобно получать в Телеграм-канале «Блог Муратова про Revit MEP». Подписывайтесь и приглашайте коллег. Можно обсудить статью и задать вопросы в специальном чате канала. В Телеграме много полезных чатов по Ревиту, присоединяйтесь!
Бесплатные обзоры ваших моделей
Раз в две недели провожу «Ревит-линчи» — разбираю файлы семейств и проектов пользователей и отвечаю на вопросы по Ревиту и БИМ-технологиям. Дату и ссылку на Ревит-линч публикую в Телеграм-канале. Приходите, там интересно.