Списки помогают упорядочивать данные. В операционной системе компьютера существуют файлы и папки. Приложение Dynamo устроено аналогично, только роль файлов в нем играют элементы, а папок — списки. Как и в операционной системе, в Dynamo существует множество способов создания, изменения и запроса данных. В этой главе рассказывается о том, как управлять списками в Dynamo.
Определившись с тем, что такое список, поговорим о том, какие операции можно выполнять с ним. Представим список в виде колоды карт. Колода — это список, а каждая карта — элемент.
Фото предоставлено Кристианом Гидлефом (Christian Gidlöf)
Какие запросы доступны в списке? Это возможность вызова существующих свойств.
Сколько карт в колоде? 52.
Количество мастей? 4.
Из какого материала они изготовлены? Бумага.
Какова их длина? 3,5 дюйма, или 89 мм.
Какова их ширина? 2,5 дюйма, или 64 мм.
Какие действия можно выполнять со списком? Это изменяет список в зависимости от конкретной операции.
Колоду можно перемешать.
Колоду можно отсортировать по значению.
Колоду можно отсортировать по масти.
Колоду можно разделить.
Колоду можно раздать отдельным игрокам.
Можно выбрать отдельную карту из колоды.
У всех перечисленных выше операций есть аналогичные узлы Dynamo для работы со списками типовых данных. На уроке ниже будут рассмотрены основные операции, которые можно выполнять со списками.
Скачайте файл примера, щелкнув указанную ниже ссылку.
Полный список файлов с примерами можно найти в приложении.
На изображении ниже показан базовый график для построения линий между двумя окружностями с целью представления основных операций со списками. Далее рассматривается управление данными в списке и демонстрируются визуальные результаты с помощью действий со списком.
Начните с узла Code Block со значением
500;
.Соедините его с входным параметром «x» узла Point.ByCoordinates.
Соединим узел из предыдущего шага с входным параметром origin узла Plane.ByOriginNormal.
Соединим узел из предыдущего шага с входным параметром plane узла Circle.ByPlaneRadius
С помощью узла Code Block укажите значение
50;
в качестве значения параметра radius. Это будет первая окружность.С помощью узла Geometry.Translate переместим окружность вверх на 100 единиц в направлении Z.
С помощью узла Code Block задайте диапазон из десяти чисел от 0 до 1, используя следующую строку кода:
0..1..#10;
.Соединим блок кода из предыдущего шага с входным значением param двух узлов Curve.PointAtParameter. Соединим узел Circle.ByPlaneRadius с входным параметром curve верхнего узла, а узел Geometry.Translate с входным параметром curve узла под ним.
С помощью узла Line.ByStartPointEndPoint соедините два узла Curve.PointAtParameter.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
Узел List.Count сравнительно прост: он подсчитывает количество значений в списке и возвращает это число. При работе со списками списков в использовании этого узла появляются дополнительные нюансы. О них мы поговорим в следующих разделах.
Узел **List.Count ****** возвращает количество линий в узле Line.ByStartPointEndPoint. В данном случае значение равно 10, что соответствует количеству точек, созданных с помощью исходного узла Code Block.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
List.GetItemAtIndex — основной способ запроса элемента в списке.
Сначала щелкните правой кнопкой мыши узел Line.ByStartPointEndPoint, чтобы отключить его предварительный просмотр.
С помощью узла List.GetItemAtIndex выбираем индекс 0 или первый элемент в списке линий.
Измените значение регулятора от 0 до 9, чтобы выбрать другой элемент с помощью List.GetItemAtIndex.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
Узел List.Reverse располагает все элементы в списке в обратном порядке.
Для корректной визуализации обращенного списка линий создайте дополнительные линии, изменив значение узла Code Block на
0..1..#50;
.Создайте копию узла Line.ByStartPointEndPoint, вставьте узел List.Reverse между узлом Curve.PointAtParameter и вторым узлом Line.ByStartPointEndPoint.
Используйте узлы Watch3D для предварительного просмотра двух различных результатов. Первый узел показывает результат без обращенного списка. Линии соединяются вертикально с точками напротив. Второй узел показывает результат обращения списка, где все точки соединяются с точками напротив в обратном порядке.
Скачайте файл примера, щелкнув указанную ниже ссылку.
Полный список файлов с примерами можно найти в приложении.
List.ShiftIndices — это удобный инструмент для создания скручиваний или спиралей и других подобных манипуляций с данными. Этот узел смещает элементы в списке на заданное количество индексов.
В том же сценарии, где был создан обращенный список, вставьте узел List.ShiftIndices между узлами Curve.PointAtParameter и Line.ByStartPointEndPoint.
С помощью узла Code Block укажите значение 1 для сдвига списка на один индекс.
Изменение незначительное, но все линии в нижнем узле Watch3D сместились на один индекс при соединении с другим набором точек.
Если увеличить значение в узле Block Code, например, до 30, в диагональных линиях появляется существенное различие. В данном случае сдвиг работает аналогично диафрагме камеры, закручивая исходную цилиндрическую форму.
Скачайте файл примера, щелкнув указанную ниже ссылку.
Полный список файлов с примерами можно найти в приложении.
Узел List.FilterByBooleanMask удаляет определенные элементы на основе списка логических операций или значений «Истина»/«Ложь».
Чтобы создать список значений «Истина» или «Ложь», необходимо выполнить несколько дополнительных действий.
С помощью узла Code Block задайте выражение со следующим синтаксисом:
0..List.Count(list);
. Соединим узел Curve.PointAtParameter с входным параметром list. Этот процесс будет рассмотрен подробнее в главе о блоках кода, но в данном случае строка кода дает список, где представлены все индексы узла Curve.PointAtParameter.С помощью узла %** (модуль)** соедините выходной параметр узла Code Block с входным параметром x, а значение 4 с входным параметром y. Это позволит вычислить остаток при делении списка индексов на 4. Узел «Коэффициент» очень полезен при создании массивов. Все значения будут представлять собой возможный остаток от 4: 0, 1, 2, 3.
Благодаря узлу %** (модуль)** мы знаем, что значение 0 означает делимость индекса на 4 (0, 4, 8 и т. д.). С помощью узла == можно проверить делимость по значению 0.
Узел Watch выводит лишь следующий результат: массив истинных и ложных значений в виде true,false,false,false.....
Соедините этот массив с входным параметром mask обоих узлов List.FilterByBooleanMask.
Соедините узел Curve.PointAtParameter с входными параметрами list узла List.FilterByBooleanMask.
Выходными данными для Filter.ByBooleanMask будут_in_ и out. In — это значения, которым было присвоено значение маски true, а out — значения, которым было присвоено значение false. Соедините выходные параметры in с входными параметрами startPoint и endPoint узла Line.ByStartPointEndPoint, создав тем самым отфильтрованный список линий.
Узел Watch3D показывает, что количество линий меньше, чем количество точек. Отфильтровав только истинные значения, мы выбрали 25 % узлов.
Список — это набор элементов или компонентов. Возьмем, к примеру, связку бананов. Каждый банан является элементом списка (или связки). Проще взять в руки связку бананов, чем брать бананы по одному. Точно так же работать с элементами, сгруппированными по параметрическим связям в структуре данных, проще, чем с отдельными элементами.
Когда мы идем в магазин, мы кладем все, что купили, в пакет. Этот пакет также является списком. Мы хотим испечь банановый кекс, и нам нужно три связки бананов (мы печем очень большой кекс). Пакет представляет собой список связок, а каждая связка представляет собой список бананов. Пакет — это список списков (двумерный), а банан — это простой список (одномерный).
В Dynamo данные в списках упорядочиваются, и первому элементу в каждом списке присваивается индекс 0. Ниже мы рассмотрим то, как задать список в Dynamo, а также то, как разные списки могут быть связаны друг с другом.
Первому элементу в списке всегда назначается индекс 0, а не 1, и поначалу это может показаться странным. Поэтому запомните, что, если речь идет о первом элементе в списке, подразумевается элемент с индексом 0.
Например, если бы вам потребовалось посчитать количество пальцев на правой руке, то вы бы начали считать с 1 до 5. Однако если бы вам потребовалось внести ваши пальцы в список, то приложение Dynamo назначило бы им индексы от 0 до 4. Это может показаться странным тем, кто только начинает заниматься программированием, однако индекс, отсчитываемые от нуля, является стандартным для большинства вычислительных систем.
Обратите внимание, что такой список по-прежнему включает пять элементов, просто в нем используется система отсчета от нуля, а не от единицы. Элементы списка не обязательно должны быть числами. Это могут быть данные любого типа, который поддерживается в Dynamo, например точки, кривые, поверхности, семейства и т. д.
a. Индекс
b. Точка
c. Элемент
Зачастую самым простым способом узнать тип данных в списке является подключение узла Watch к порту вывода другого узла. По умолчанию узел Watch автоматически отображает все индексы в левой части списка, а элементы данных — в правой.
Эти индексы играют ключевую роль при работе со списками.
При работе со списками требуемые входные и выходные данные различаются в зависимости от используемого узла Dynamo. Для примера возьмем список из пяти точек и соединим его порт вывода с двумя разными узлами Dynamo: PolyCurve.ByPoints и Circle.ByCenterPointRadius:
Порт ввода points узла PolyCurve.ByPoints выполняет поиск элемента "Point[]". Этот элемент представляет собой список точек.
Выходные данные узла PolyCurve.ByPoints — это элемент PolyCurve, созданный на основе списка из пяти точек.
Порт ввода centerPoint узла Circle.ByCenterPointRadius запрашивает элемент "Point".
Выходные данные Circle.ByCenterPointRadius представляют собой список из пяти окружностей, центры которых соответствуют точкам из исходного списка.
Узлы PolyCurve.ByPoints и Circle.ByCenterPointRadius используют одни и те же входные данные, однако узел Polycurve.ByPoints на выходе дает одну сложную кривую, а узел Circle.ByCenterPointRadius — пять окружностей с центрами в каждой точке. На интуитивном уровне это кажется понятным, так как сложная кривая строится путем соединения всех пяти точек, а окружности создают отдельную окружность в каждой точке. Что же происходит с данными?
При наведении указателя мыши на порт ввода points узла Polycurve.ByPoints можно увидеть, что этому порту требуется элемент Point[]. Обратите внимание на скобки в конце. Этот элемент представляет список точек, и чтобы создать сложную кривую, в качестве входных данных этому узлу требуется отдельный список точек для каждой кривой. В результате узел объединяет каждый список в одну сложную кривую.
Порт ввода centrePoint узла Circle.ByCenterPointRadius запрашивает элемент Point. Этому узлу требуется одна точка, являющаяся отдельным элементом, для определения центра окружности. Поэтому на основе тех же входных данных мы получаем пять отдельных окружностей. Знание различий в использовании входных данных в Dynamo помогает лучше понимать, как узлы распоряжаются данными.
Сопоставление данных является проблемой, для которой не существует четкого решения. Это происходит, когда узел получается доступ к входным данных разных размеров. Изменение алгоритма сопоставления данных может привести к существенным различиям в результатах.
Рассмотрим в качестве примера узел, который создает сегменты линий между точками (Line.ByStartPointEndPoint). У него есть два входных параметра, которые используются для представления координат точек:
Самый простой способ — попарно соединять входные данные с одинаковыми индексами, пока один из списков не закончится. Это алгоритм по самому короткому списку. Узлы Dynamo используют этот алгоритм по умолчанию.
Алгоритм переплетения по самому длинному списку соединяет все входные элементы, используя некоторые элементы повторно, пока не закончатся оба списка:
Наконец, при использовании метода «Векторное произведение» создаются все возможные соединения:
Как мы видим, прочертить линию через эти наборы точек можно разными способами. Параметры переплетения можно просмотреть, щелкнув центр узла правой кнопкой мыши и выбрав меню «Переплетение».
Скачайте файл примера, щелкнув указанную ниже ссылку.
Полный список файлов примеров можно найти в приложении.
Для изучении операций переплетения ниже мы воспользуемся этим базовым файлом, чтобы определить самый короткий и самый длинный списки, а также векторное произведение.
Измените настройку переплетения узла Point.ByCoordinates в графике выше, оставив остальные элементы без изменений.
При выборе Самый короткий список в качестве варианта переплетения (также является вариантом по умолчанию) мы получаем базовую диагональную линию, состоящую из пяти точек. Пять точек — это длина наименьшего списка. Таким образом, переплетение по самому короткому списку прекращается по достижении конца этого списка.
При изменении способа переплетения на Самый длинный список вы получите диагональную линию, которая имеет продолжение по вертикали. Аналогично схематическому изображению выше, последний элемент короткого списка используется повторно, пока не будет достигнут конец более длинного списка.
Изменив способ переплетения на Векторное произведение, вы получите все возможные соединения между списками, в результате чего создается сетка 5 х 10 точек. Эта структура данных эквивалентна векторному произведению, показанному в схематическом изображении выше, однако данные теперь являются списком списков. Путем соединения сложной кривой можно увидеть, что каждый список определяется значением X, в результате чего образуется ряд вертикальных линий.
Добавим еще больше уровней в иерархию и углубимся в нашу кроличью нору. Структура данных может быть гораздо более объемной, чем простой двумерный список списков. Поскольку списки являются самостоятельными элементами в Dynamo, мы можем создать данные с практически неограниченным количеством измерений.
Это похоже на матрешку. Каждый список можно рассматривать как один контейнер, который содержит несколько элементов. Каждый список обладает собственными свойствами и рассматривается как отдельный объект.
Набор матрешек (фотография предоставлена ) является аналогией многомерных списков. Каждый слой представляет список, и каждый список содержит элементы. В Dynamo каждый контейнер может содержать несколько контейнеров (представляющих элементы каждого списка).
Многомерные списки сложно объяснить визуально, но в данном разделе есть несколько упражнений, которые помогут вам разобраться в работе со списками, число измерений которых превышает два.
Сопоставление — возможно, самый сложный аспект управления данными в Dynamo, особенно когда речь идет о сложных иерархических структурах, состоящих из списков. В рамках приведенных ниже упражнений мы рассмотрим случаи, в которых следует использовать сопоставление и комбинации при работе с многомерными данными.
Основные сведения по работе с узлами List.Map и List.Combine можно найти в предыдущем разделе. Эти узлы будут использованы для работы со сложной структурой данных в последнем из приведенных ниже упражнений.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
Это первое из трех упражнений, направленных на работу с импортированной геометрией. От упражнения к упражнению структура данных будет усложняться.
Начнем с файла SAT, расположенного в папке с файлами для упражнения. Добавим его в приложение с помощью узла File Path.
Узел Geometry.ImportFromSAT импортирует геометрию в Dynamo и отображает ее в виде двух поверхностей.
Для простоты в этом упражнении вы будете работать только с одной поверхностью.
Чтобы выбрать верхнюю поверхность, задайте индекс 1. Для этого добавьте узел List.GetItemAtIndex.
Отключите предварительный просмотр геометрии в области предварительного просмотра Geometry.ImportFromSAT.
Теперь нужно преобразовать поверхность в сетку точек.
1. С помощью узла Code Block вставьте две следующие строки кода:
0..1..#10;
0..1..#5;
.2. Используя узел Surface.PointAtParameter, соедините два значения Code Block с входными параметрами «u» и v. Задайте для параметра Переплетение этого узла значение Векторное произведение.
3. Полученная структура данных отображается в области предварительного просмотра Dynamo.
Затем используйте точки из последнего шага для создания десяти кривых вдоль поверхности.
Чтобы отобразить структуру данных, соедините узел NurbsCurve.ByPoints с портом вывода узла Surface.PointAtParameter.
Для получения более четкого результата можно отключить предварительный просмотр в узле List.GetItemAtIndex.
Базовый узел List.Transpose позволяет поменять местами столбцы и строки в списке списков.
При соединении порта вывода узла List.Transpose с узлом NurbsCurve.ByPoints вы получите пять кривых, идущих горизонтально вдоль поверхности.
Для получения того же результата можно отключить предварительный просмотр в узле NurbsCurve.ByPoints на предыдущем шаге.
Усложним задачу. Предположим, что нам нужно выполнить определенное действие с кривыми, которые мы получили в предыдущем упражнении. Например, нужно связать эти кривые с другой поверхностью и выполнить лофтинг между ними По сути, логика остается прежней, но задача требует более внимательной работы со структурой данных.
Начнем с операции, уже знакомой вам по предыдущему упражнению. Изолируйте верхнюю поверхность импортированной геометрии с помощью узла List.GetItemAtIndex.
Используя узел Surface.Offset, задайте значение 10, чтобы сместить поверхность.
Как и в предыдущем упражнении, добавьте узел Code Block с двумя следующими строками кода:
0..1..#10;
0..1..#5;
.Соедините порты вывода этого узла с двумя узлами Surface.PointAtParameter и задайте для параметра Переплетение каждого из них значение Векторное произведение. Один из этих узлов соединен с исходной поверхностью, а второй — с поверхностью смещения.
Отключите предварительный просмотр этих поверхностей.
Как и в предыдущем упражнении, соедините порты вывода с двумя узлами NurbsCurve.ByPoints. В результате отображаются кривые, соответствующие двум поверхностям.
С помощью узла List.Create можно объединить два набора кривых в один список списков.
В результате создаются два списка с десятью элементами, каждый из которых представляет собой связанный набор NURBS-кривых.
С помощью узла Surface.ByLoft можно создать визуальное представление этой структуры данных. Узел выполняет лофтинг для всех кривых в каждом списке.
Отключите предварительный просмотр узла Surface.ByLoft на предыдущем шаге.
Как вы помните, узел List.Transpose позволяет поменять местами столбцы и строки в списке списков. В результате использования этого узла два списка из десяти кривых каждый преобразуются в десять списков из двух кривых каждый. Теперь каждая NURBS-кривая связана с соседней кривой на другой поверхности.
С помощью узла Surface.ByLoft мы получили реберную конструкцию.
Далее демонстрируется альтернативный процесс получения этого результата
Перед началом отключите предварительный просмотр Surface.ByLoft во избежание путаницы.
Вместо узла List.Transpose можно использовать узел List.Combine. Он выполняет роль «комбинатора» для каждого вложенного списка.
В данном случае мы используем List.Create в качестве «комбинатора» для создания списка по каждому элементу во вложенных списках.
Добавив узел Surface.ByLoft, мы получаем те же поверхности, что и на предыдущем шаге. В данном случае узел Transpose является более простым вариантом, но при работе с еще более сложной структурой данных надежнее будет использовать узел List.Combine.
Вернемся на несколько шагов назад. Если вы хотите изменить ориентацию кривых в реберной конструкции, узел List.Transpose следует применить до соединения с узлом NurbsCurve.ByPoints. В результате столбцы и строки поменяются местами, и мы получим пять горизонтальных ребер.
Продолжаем усложнять задачи. В этом упражнении мы используем обе импортированные поверхности, чтобы создать сложную иерархическую структуру данных. По сути, вам предстоит выполнить то же самое действие, пользуясь той же самой логикой, что и ранее.
Вернемся к файлу, импортированному в предыдущем упражнении.
Как и в предыдущем упражнении, используйте узел Surface.Offset, чтобы задать значение смещения, равное 10.
Обратите внимание, что добавление узла смещения привело к созданию двух поверхностей.
Как и в предыдущем упражнении, добавьте узел Code Block с двумя следующими строками кода:
0..1..#20;
0..1..#20;
.Соедините порты вывода этого узла с двумя узлами Surface.PointAtParameter и задайте для параметра «Переплетение» каждого из них значение Векторное произведение. Один из этих узлов соединен с исходными поверхностями, а второй — с поверхностями смещения.
Как и в предыдущем упражнении, соедините порты вывода с двумя узлами NurbsCurve.ByPoints.
Посмотрите на выходные данные узла NurbsCurve.ByPoints и обратите внимание, что они представляют собой список, состоящий из двух списков, что является более сложной структурой, чем в предыдущем упражнении. Данные упорядочиваются по базовой поверхности, поэтому в структуру данных добавлен еще один уровень.
Обратите внимание, что структура данных в узле Surface.PointAtParameter стала более сложной. В нем представлен список, состоящий из списков списков.
Перед продолжением отключите предварительный просмотр существующих поверхностей.
С помощью узла List.Create объедините NURBS-кривые в одну структуру данных, чтобы создать список, состоящий из списков списков.
При подключении узла Surface.ByLoft мы получаем новую версию исходных поверхностей, так как они остаются в собственном списке в соответствии с исходной структурой данных.
В предыдущем упражнении мы использовали узел List.Transpose для создания реберной конструкции. В этом случае данная функция не подходит. Перенос следует использовать с двумерными списками, но мы имеем дело с трехмерным списком, поэтому перестановка столбцов и строк не сработает. Поскольку списки являются объектами, то узел List.Transpose выполнит перестановку между списками с вложенными списками, но она не затронет NURBS-кривые в списках на уровень ниже.
В этом случае List.Combine является более подходящим инструментом. При работе с более сложными структурами данных используются узлы List.Map и List.Combine.
Используя List.Create в качестве «комбинатора», создайте структуру данных, которая лучше подойдет для ваших целей.
Структуру данных все еще требуется перенести на один уровень вниз по иерархии. Для этого используйте узел List.Map. Его работа аналогична узлу List.Combine, однако в нем используется только один список входных данных, а не два или больше.
К узлу List.Map будет применена функция List.Transpose, которая меняет местами столбцы и строки вложенных списков в главном списке.
Наконец, выполните лофтинг между NURBS-кривыми с использованием соответствующей иерархии данных, чтобы получить реберную конструкцию.
Добавим глубину геометрии с помощью узла Surface.Thicken с входными параметрами, как показано на изображении.
Будет полезно добавить поверхность, поддерживающую конструкцию, поэтому добавьте еще один узел Surface.ByLoft и используйте в качестве входного параметра первый вывод узла NurbsCurve.ByPoints из предыдущего шага.
Чтобы не перегружать экран, отключите предварительный просмотр этих узлов. Щелкните узел правой кнопкой мыши и снимите флажок «Предварительный просмотр», чтобы лучше рассмотреть результат.
Теперь увеличьте толщину выбранных поверхностей.
В результате мы получили нечто, похожее на слегка неустойчивое кресло-качалку. Зато сколько данных ушло на его создание!
Наконец, изменим направление бороздок. Для этого выполните процедуру, аналогичную преобразованию, которое вы уже использовали ранее.
Чтобы заполнить еще один уровень иерархии, используйте узел List.Map с функцией List.Tranpose, чтобы изменить направление NURBS-кривых.
Если требуется увеличить количество канавок, то данные узла Code Block можно изменить на следующие:
0..1..#20;
0..1..#30;
.
Если первая версия кресла-качалки была обтекаемой, то вторая получилась более похожей на колесо внедорожника.
Фотография предоставлена .
Добавим еще один уровень в иерархию. Если взять колоду карт из первого примера и создать рамку, в которой будет находиться несколько колод, то эта рамка будет представлять собой список колод, а каждая колода — список карт. Это и есть список списков. В качестве аналогичного примера для этого раздела ниже представлен список столбиков монет, каждый из которых содержит список монет.
Фото предоставлено Dori.
Какие запросы доступны в таком списке списков? Это возможность вызова существующих свойств.
Сколько всего типов монет? 2.
Какова ценность типов монет? $0.01 и $0.25.
Какие материалы используются для изготовления монет номиналом 0,25 долл. США? 75 % меди и 25 % никеля.
Какие материалы используются для изготовления цента? 97,5 % цинка и 2,5 % меди.
Какие действия можно выполнять со списком списков? Они приведут к изменению списка списков в зависимости от конкретной операции.
Выбрать один столбик из монет номиналом 1 или 25 центов.
Выбрать одну монету номиналом 1 или 25 центов.
Переупорядочить столбики.
Перемешать столбики.
Для каждой из перечисленных выше операций в Dynamo имеется аналогичный узел. Поскольку мы работаем с абстрактными данными, а не с физическими объектами, необходимо установить набор правил, определяющих порядок перемещения вверх и вниз по иерархии данных.
При работе со списками списков данные располагаются по слоям и имеют сложную структуру, но это дает возможность выполнять ряд уникальных параметрических операций. Остановимся подробнее на основных операциях, оставив другие для последующих занятий.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
В данном разделе необходимо усвоить один базовый принцип: Dynamo рассматривает сами по себе списки как объекты. Эта нисходящая иерархия разработана с учетом объектно-ориентированного программирования. Вместо выбора вложенных элементов с помощью, например, команды List.GetItemAtIndex в Dynamo будет выбран индекс основного списка в структуре данных. Этот элемент, в свою очередь, может быть другим списком. Рассмотрим этот вопрос подробнее на примере изображения ниже.
С помощью узла Code Block было задано два диапазона:
0..2; 0..3;
.Эти диапазоны соединены с узлом Point.ByCoordinates, а в качестве переплетения выбран вариант Cross Product (векторное произведение). При этом создается сетка точек, а в качестве выходных данных возвращается список списков.
Обратите внимание, что узел Watch содержит 3 списка с 4 элементами в каждом.
При использовании функции List.GetItemAtIndex с индексом 0 Dynamo выберет первый список и все его содержимое. Другие программы могут выбрать первый элемент каждого списка в структуре данных, но в Dynamo при работе с данными используется иерархия «сверху вниз».
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
Функция Flatten удаляет все уровни в структуре данных. Это удобно, если для выполнения операции не требуется наличие иерархий данных, но имеются определенные риски, так как удаляется информация. В примере ниже показан результат выравнивания списка данных.
Вставьте одну строку кода для определения диапазона в узле Code Block:
-250..-150..#4;
.При вставке блока кода во входные данные x и y узла Point.ByCoordinates в качестве варианта переплетения укажем Cross Product (векторное произведение), чтобы получить сетку точек.
Узел Watch показывает наличие списка списков.
Узел PolyCurve.ByPoints создаст ссылки для каждого списка и построит соответствующую сложную кривую. Обратите внимание, что в области предварительного просмотра Dynamo отобразятся четыре сложные кривые, представляющие каждый ряд сетки.
После вставки функции Flatten перед узлом сложной кривой был создан один список для всех точек. Узел PolyCurve.ByPoints создает ссылку для списка, чтобы создать одну кривую, а так как все точки находятся в одном списке, получается одна зигзагообразная сложная кривая, которая проходит по всему списку точек.
Можно также выровнять изолированные уровни данных. С помощью узла List.Flatten можно указать определенное количество уровней данных, чтобы выполнить выравнивание от верхнего уровня иерархии. Это очень полезный инструмент при работе со сложными структурами данных, которые могут быть не всегда нужны в рабочем процессе. Еще один вариант — использовать узел Flatten в качестве функции в List.Map. Далее мы подробнее обсудим List.Map.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
При параметрическом моделировании бывает необходимо изменить структуру данных в существующем списке. С этой целью можно использовать множество других узлов, из которых Chop — самая базовая версия. С помощью функции Chop можно разделить список на вложенные списки с заданным количеством элементов.
Команда Chop (обрезка) делит списки на основе заданной длины списка. В некотором смысле обрезка обратна выравниванию: вместо упрощения структуры данных она добавляет в нее новые уровни. Это удобный инструмент для геометрических операций, таких как в примере ниже.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
Узел List.Map/Combine позволяет применить заданную функцию к списку входных данных, но на один шаг вниз по иерархии. Набор комбинаций аналогичен команде Maps, за исключением наличия нескольких наборов входных данных, соответствующих входным данным заданной функции.
Примечание. Это упражнение было создано в предыдущей версии Dynamo. Большая часть функциональных возможностей List.Map была упразднена с добавлением функции List@Level . Дополнительные сведения см. в разделе List@Level ниже.
В качестве краткого введения рассмотрим узел List.Count из предыдущего раздела.
Узел List.Count подсчитывает все элементы в списке. Мы воспользуемся этим для демонстрации работы List.Map.
Вставьте следующие две строки кода в узел Code Block:
-50..50..#Nx; -50..50..#Ny;
.После ввода этих данных блок кода создаст два набора входных данных для Nx и Ny.
С помощью двух узлов Integer Slider задайте значения Nx и Ny путем их присоединения к Code Block.
Соедините каждую строку блока кода с соответствующими входными данными X и Y узла Point.ByCoordinates. Щелкните узел правой кнопкой мыши, выберите «Lacing» (переплетение), а затем Cross Product (векторное произведение). Будет создана сетка точек. Так как мы определили диапазон от -50 до 50, он охватывает сетку Dynamo по умолчанию.
Созданные точки отображаются в узле Watch. Обратите внимание на структуру данных. Мы создали список списков. Каждый список представляет собой ряд точек сетки.
Вставьте узел List.Count в выходные данные узла Watch из предыдущего шага.
Соедините узел Watch с выходными данными List.Count.
Обратите внимание, что узел List.Count выдает значение 5. Это значение равно переменной Nx, заданной в блоке кода. Почему?
Во-первых, в качестве основного входного параметра для создания списков в узле Point.ByCoordinates используется входной параметр «x». Если Nx равно 5, а Ny — 3, получается список, состоящий из 5 списков, в каждом из которых содержится 3 элемента.
Так как Dynamo рассматривает списки сами по себе как объекты, то узел List.Count применяется к основному списку в иерархии. В результате получается значение 5 (количество списков в главном списке).
С помощью узла List.Map спустимся на один шаг вниз по иерархии и на этом уровне выполним функцию.
Обратите внимание, что узел List.Count не имеет входных данных. Так как узел List.Count используется в качестве функции, он будет применен к каждому отдельному списку на один шаг вниз по иерархии. Пустые входные данные узла List.Count соответствуют входным данным списка в узле List.Map.
Результаты узла List.Count теперь выдают список из 5 элементов, в каждом из которых имеется значение 3. Это соответствует длине каждого вложенного списка.
Примечание. Это упражнение было создано в предыдущей версии Dynamo. Большая часть функциональных возможностей List.Combine была упразднена с добавлением функции List@Level . Дополнительные сведения см. в разделе List@Level ниже.
В этом упражнении узел List.Combine используется, чтобы продемонстрировать, как его с его помощью можно применять функцию к отдельным спискам объектов.
Начните с настройки двух списков точек.
Используйте узел Sequence для создания 10 значений, каждое с увеличением на 10.
Соедините результат с входным параметром «x» узла Point.ByCoordinates. В Dynamo будет создан список точек.
Добавьте второй узел Point.ByCoordinates в рабочее пространство. Используйте тот же выходной параметр Sequence в качестве входного параметра «x», но используйте Interger Slider в качестве входного параметра «y» и задайте для него значение 31 (оно может быть любым, если не перекрывается первым набором точек), чтобы два набора точек не перекрывались друг другом.
Используйте List.Combine, чтобы применить функцию к объектам в 2 отдельных списках. В данном случае это будет простая функция рисования линий.
Добавьте узел List.Combine в рабочее пространство и соедините 2 набора точек в качестве входных данных list0 и list1.
Используйте узел Line.ByStartPointEndPoint в качестве входной функции для узла List.Combine.
После этого 2 набора точек с помощью функции Line.ByStartPointEndPoint архивируются или связываются вместе, и в Dynamo возвращаются 10 строк.
См. упражнение в многомерных списках для просмотра другого примера использования List.Combine.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
В отличие от List.Map функция List@Level позволяет выбрать необходимый уровень списка непосредственно на входном порте узла. Эту функцию можно применять ко всем поступающим входным данным узлов и получать доступ к уровням списков быстрее, чем при использовании других методов. Просто сообщите узлу, какой уровень списка требуется использовать в качестве входных данных, и он сам сделает все необходимое.
В этом упражнении с помощью функции List@Level изолируется определенный уровень данных.
Начнем с простой 3D-сетки точек.
Поскольку сетка создается с диапазоном для X, Y и Z, структура данных будет иметь 3 уровня: список X, список Y и список Z.
Эти уровни расположены на разной высоте (уровнях). Они указаны в нижней части марки предварительного просмотра. Столбцы уровня списка соответствуют данным списка выше, что позволяет быстрее найти нужный уровень.
Уровни списка располагаются в обратном порядке, так что данные самого низкого уровня всегда находятся на высоте L1. Благодаря этому графики будут функционировать запланированным образом, даже если что-то изменится в предыдущем алгоритме.
Чтобы использовать функцию List@Level, нажмите кнопку «>». В меню отобразятся два флажка.
Использовать уровни: этот вариант включает функцию List@Level. Если этот флажок установлен, можно с помощью мыши выбрать уровни списка входных данных, которые будут использованы узлом. С помощью этого меню можно быстро проверить различные конфигурации уровней, щелкая мышью выше или ниже.
Сохранить структуру списков: если установить этот флажок, можно будет сохранить структуру уровней этих входных данных. Иногда данные бывают сознательно разделены по вложенным спискам. Если установить этот флажок, можно сохранить структуру списка неизменной без какой-либо потери информации.
Благодаря этой простой 3D-сетке можно получить доступ к структуре списка и визуализировать ее, переключаясь между уровнями списка. Любая комбинация уровня списка и индекса возвращает собственный набор точек из исходного 3D-набора.
С помощью элемента @L2 в DesignScript можно выбрать только список на уровне 2. Список на уровне 2 с индексом 0 включает в себя только первый набор точек Y и возвращает только сетку XZ.
Если задать фильтр уровней L1, можно увидеть все содержимое первого уровня списка. Список на уровне 1 с индексом 0 включает в себя все 3D-точки в одноуровневом списке.
В аналогичном случае с L3 будут видны только точки третьего уровня списка. Список на уровне 3 с индексом 0 включает в себя только первый набор точек Z и возвращает только сетку XY.
В аналогичном случае с L4 будут видны только точки третьего уровня списка. Список на уровне 4 с индексом 0 включает в себя только первый набор точек X и возвращает только сетку YZ.
Несмотря на то, что данный конкретный пример можно также создать с помощью List.Map, функция List@Level существенно упрощает взаимодействие и доступ к данным узла. Ниже представлено сравнение методов List.Map и List@Level.
Оба метода предоставляют доступ к одним и тем же точкам, однако List@Level позволяет легко переключаться между слоями данных в одном узле.
Для доступа к сетке точек с помощью List.Map требуется добавить узел List.GetItemAtIndex в дополнение к List.Map. Для каждого нижестоящего уровня списка необходимо использовать дополнительный узел List.Map. В некоторых сложных списках для получения доступа к нужному уровню информации требуется включение в график значительного количества узлов List.Map.
В этом примере узел List.GetItemAtIndex с узлом List.Map возвращает тот же набор точек и ту же структуру списка, что и List.GetItemAtIndex со значением @L3.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
Transpose (транспонирование) — это одна из основных функций при работе со списками списков. Как и в электронных таблицах, при транспонировании происходит перестановка столбцов и строк в структуре данных. Продемонстрируем это с помощью следующей базовой матрицы, а в следующем разделе покажем, как с помощью функции транспонирования создавать геометрические взаимосвязи.
Удалите узлы List.Count из предыдущего упражнения и перенесите их на геометрические объекты, чтобы увидеть, как структурированы данные.
Соедините узел PolyCurve.ByPoints с выходными данными узла Watch из узла Point.ByCoordinates.
На выходе отобразятся 5 сложных кривых, которые можно видеть в области предварительного просмотра Dynamo. Узел Dynamo выполняет поиск списка точек (в данном случае — списка списков точек) и создает из них одну сложную кривую. По сути, каждый список в структуре данных преобразован в кривую.
Узел List.Transpose переставляет все элементы со всеми списками в списке списков. Это может показаться сложным, но в Microsoft Excel используется точно такая же логическая схема транспонирования данных: перестановка столбцов со строками в структуре данных.
Обратите внимание на изменение в списках: после транспонирования структура, состоявшая из 5 списков с 3 элементами, изменилась на 3 списка с 5 элементами в каждом.
Кроме того, обратите внимание на изменение в геометрии: использование узла PolyCurve.ByPoints привело к появлению 3 сложных кривых в перпендикулярном направлении к исходным кривым.
Для определения списка в сокращенном языке блока кода используются квадратные скобки ([]). Это гораздо более быстрый и простой способ создания списков, чем с помощью узла List.Create. Узел Code Block подробно рассматривается в разделе Узлы Code Block и DesignScript. На изображении ниже показано, как можно задать список с несколькими выражениями с помощью блока кода.
Для упрощенного выбора определенных элементов, которые требуется извлечь из сложной структуры данных, в сокращенном языке узла Code Block используются квадратные скобки ([]). Узлы Code Block подробно рассматриваются в главе Узлы Code Block и DesignScript. На изображении ниже показано, как запросить список с несколькими типами данных с помощью блока кода.
Скачайте файл с примером, щелкнув ссылку ниже.
Полный список файлов с примерами можно найти в приложении.
В этом упражнении для редактирования поверхности используется логическая схема из предыдущего упражнения. Эту задачу можно решить интуитивным способом, однако при этом потребуется дополнительная навигация по структуре данных. Необходимо определить поверхность путем перемещения контрольной точки.
Начните со строки узлов выше. Создайте базовую поверхность, которая охватывает всю сетку Dynamo по умолчанию.
С помощью узла Code Block вставьте следующие две строки кода и соедините их с входными параметрами u и v узла Surface.PointAtParameter соответственно:
-50..50..#3;
-50..50..#5;
.Убедитесь, что для параметра Lacing (переплетение) узла Surface.PointAtParameter задано значение Cross Product (векторное произведение).
Узел Watch показывает, что имеется список из 3 списков, каждый из которых содержит 5 элементов.
На этом этапе следует запросить центральную точку в созданной сетке. Для этого выберите центральную точку в списке посередине. Логично, не так ли?
Чтобы убедиться в правильности выбора точки, можно щелкнуть элементы узла Watch для проверки правильности выбора элемента.
При помощи узла Code Block создайте базовую строку кода для запроса списка списков:
points[1][2];
С помощью функции Geometry.Translate переместите выбранную точку вверх в направлении оси Z на 20 единиц.
Кроме того, выберите ряд точек посередине с помощью узла List.GetItemAtIndex. Примечание. Как и при выполнении предыдущего шага, можно запросить список с помощью узла Code Block, используя строку
points[1];
.
Итак, мы успешно запросили центральную точку и переместили ее вверх. Теперь необходимо вставить эту перемещенную точку обратно в исходную структуру данных.
Сначала замените элемент списка, который был изолирован при выполнении предыдущего шага.
С помощью узла List.ReplaceItemAtIndex замените центральный элемент с помощью индекса 2 на замещающий элемент, соединенный с перемещенной точкой (Geometry.Translate).
Выходные данные показывают, что перемещенная точка была вставлена в набор входных данных элемента в середине списка.
После изменения списка необходимо вставить его обратно в исходную структуру данных — список списков.
Используя ту же логическую схему, заменим список в середине на измененный список с помощью узла List.ReplaceItemAtIndex.
Обратите внимание, что индекс этих двух узлов определяется узлами Code Block 1 и 2, что соответствует исходному запросу из узла Code Block (points[1][2]).
Если выбрать список с помощью index 1, то структура данных будет выделена в области предварительного просмотра Dynamo. Итак, мы успешно встроили перемещенную точку в исходную структуру данных.
Существует множество способов создания поверхности из этого набора точек. В данном случае необходимо создать поверхность за счет лофтинга кривых.
Создайте узел NurbsCurve.ByPoints и присоедините новую структуру данных для создания трех NURBS-кривых.
Соедините узел Surface.ByLoft с выходными данными из узла NurbsCurve.ByPoints. Получится модифицированная поверхность. Можно изменить исходное значение Z геометрии. Выполните преобразование и посмотрите, как изменится геометрия.