Listy są sposobem organizowania danych. W systemie operacyjnym komputera dostępne są pliki i foldery. W dodatku Dynamo można je traktować jako odpowiednio elementy i listy. Podobnie jak w systemie operacyjnym, istnieje wiele sposobów tworzenia, modyfikowania i przywoływania danych. W tym rozdziale omówimy sposób zarządzania listami w dodatku Dynamo.
Idąc dalej, możemy dodać jeszcze więcej poziomów do hierarchii. Struktura danych może znacznie wykraczać poza dwuwymiarową listę list. Ponieważ same listy również są elementami w dodatku Dynamo, możemy tworzyć dane z dowolnie dużą liczbą wymiarów.
Można to porównać do rosyjskich matrioszek. Każdą listę można traktować jako jeden pojemnik zawierający wiele elementów. Każda lista ma określone właściwości i sama w sobie jest traktowana jako obiekt.
Zestaw matrioszek (autor zdjęcia: Zeta) to dobra analogia dla list n-wymiarowych. Każda warstwa oznacza listę, a każda lista zawiera elementy. W dodatku Dynamo każdy pojemnik może zawierać wiele pojemników (elementów listy).
Listy n-wymiarowe trudno przedstawić wizualnie, ale w tym rozdziale przygotowaliśmy kilka ćwiczeń dotyczących pracy z listami wykraczającymi poza dwa wymiary.
Odwzorowywanie to zdecydowanie najbardziej złożona część zarządzania danymi w programie Dynamo, szczególnie istotna podczas pracy ze złożonymi hierarchiami list. W poniższych ćwiczeniach pokazano, kiedy używać odwzorowywania i kombinacji podczas pracy z wielowymiarowymi danymi.
Wstępne informacje o węzłach List.Map i List.Combine można znaleźć w poprzedniej sekcji. W ostatnim ćwiczeniu użyjemy tych węzłów w złożonej strukturze danych.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
To pierwsze z serii trzech ćwiczeń, które skupia się na artykulacji zaimportowanej geometrii. W każdej części tej serii ćwiczeń zwiększy się złożoność struktury danych.
Zacznijmy od pliku .sat w folderze plików ćwiczeniowych. Można przechwycić ten plik za pomocą węzła File Path.
Za pomocą węzła Geometry.ImportFromSAT geometria jest importowana do podglądu dodatku Dynamo jako dwie powierzchnie.
Aby uprościć to ćwiczenie, będziemy pracować z jedną z tych powierzchni.
Wybierzmy indeks 1, aby przechwycić górną powierzchnię. Służy do tego węzeł List.GetItemAtIndex.
Wyłącz podgląd geometrii w podglądzie Geometry.ImportFromSAT.
Kolejnym etapem jest podzielenie powierzchni na siatkę punktów.
1. Za pomocą węzła Code Block wstaw następujące dwa wiersze kodu:
0..1..#10;
0..1..#5;
2. W węźle Surface.PointAtParameter połącz te dwie wartości z węzła Code Block z elementami u i v. Zmień opcję skratowania tego węzła na „Iloczyn wektorowy”.
3. Wynik pokazuje strukturę danych, która jest również widoczna w podglądzie dodatku Dynamo.
Następnie użyto punktów z ostatniego kroku, aby wygenerować dziesięć krzywych wzdłuż powierzchni.
Aby zobaczyć, jak zorganizowana jest struktura danych, połączmy węzeł NurbsCurve.ByPoints z elementem wyjściowym węzła Surface.PointAtParameter.
Podgląd można na razie wyłączyć z poziomu węzła List.GetItemAtIndex, aby uzyskać bardziej czytelny wynik.
Podstawowa funkcja List.Transpose spowoduje zamianę kolumn i wierszy listy list.
Po połączeniu elementu wyjściowego węzła List.Transpose z węzłem NurbsCurve.ByPoints powstanie pięć krzywych biegnących poziomo na powierzchni.
Podgląd można wyłączyć z poziomu węzła NurbsCurve.ByPoints w poprzednim kroku, aby uzyskać ten sam wynik na obrazie.
Teraz zwiększmy złożoność. Załóżmy, że chcemy wykonać operację na krzywych utworzonych w poprzednim ćwiczeniu. Możemy na przykład powiązać te krzywe z inną powierzchnią i wykonać pomiędzy nimi wyciągnięcie. To wymaga zwrócenia większej uwagi na strukturę danych, ale podstawowa logika jest taka sama.
Rozpocznij od kroku z poprzedniego ćwiczenia, w którym wyizolowaliśmy górną powierzchnię zaimportowanej geometrii za pomocą węzła List.GetItemAtIndex.
Używając węzła Surface.Offset, odsuń tę powierzchnię o wartość 10.
Tak samo jak w poprzednim ćwiczeniu, zdefiniuj węzeł Code Block zawierający te dwa wiersze kodu:
0..1..#10;
0..1..#5;
Połącz te dane wyjściowe z dwoma węzłami Surface.PointAtParameter, każdy z opcją skratowania ustawioną na „Iloczyn wektorowy”. Jeden z tych węzłów jest połączony z pierwotną powierzchnią, a drugi z powierzchnią odsuniętą.
Wyłącz podgląd tych powierzchni.
Tak samo jak w poprzednim ćwiczeniu, połącz elementy wyjściowe z dwoma węzłami NurbsCurve.ByPoints. Wynik pokazuje krzywe odpowiadające dwóm powierzchniom.
Używając węzła List.Create, można połączyć oba zestawy krzywych w jedną listę list.
Jak widać w wyniku, otrzymaliśmy dwie listy zawierające po dziesięć elementów, odpowiadające obu połączonym zestawom krzywych NURBS.
Wykonując operację Surface.ByLoft, możemy wizualnie zinterpretować tę strukturę danych. Ten węzeł wyciąga wszystkie krzywe na każdej podliście.
Wyłącz podgląd z poziomu węzła Surface.ByLoft w poprzednim kroku.
Jak pamiętamy, używając węzła List.Transpose, zamieniamy wszystkie kolumny i wiersze. Ten węzeł umożliwia przekształcenie dwóch list po dziesięć krzywych w dziesięć list po dwie krzywe. Teraz każda krzywa NURBS jest powiązana z sąsiednią krzywą na drugiej powierzchni.
Po użyciu węzła Surface.ByLoft otrzymujemy żebrowaną strukturę.
Następnie zademonstrujemy alternatywny proces pozwalający osiągnąć ten wynik
Przed rozpoczęciem należy wyłączyć podgląd węzła Surface.ByLoft w poprzednim kroku, aby uniknąć pomyłek.
Alternatywą dla węzła List.Transpose jest użycie węzła List.Combine. Spowoduje to zastosowanie „kombinatora” do każdej podlisty.
W tym przypadku używamy węzła List.Create jako „kombinatora” w celu utworzenia listy dla każdego elementu na podlistach.
Po użyciu węzła Surface.ByLoft otrzymujemy takie same powierzchnie, jak w poprzednim kroku. W tym przypadku łatwiej jest użyć węzła Transpose, ale jeśli struktura danych jest jeszcze bardziej złożona, węzeł List.Combine będzie bardziej niezawodny.
Cofając się o kilka kroków, aby zmienić orientację krzywych w żebrowanej strukturze, należy użyć węzła List.Transpose przed połączeniem z węzłem NurbsCurve.ByPoints. Spowoduje to zamianę kolumn i wierszy, dając 5 poziomych żeber.
Teraz pójdziemy o krok dalej. W tym ćwiczeniu będziemy pracować z obiema zaimportowanymi powierzchniami, tworząc złożoną hierarchię danych. Będziemy jednak wykonywać tę samą operację z tą samą logiką.
Rozpocznij od zaimportowanego pliku z poprzedniego ćwiczenia.
Tak samo jak w poprzednim ćwiczeniu, użyj węzła Surface.Offset, aby wykonać odsunięcie o wartość 10.
Jak pokazuje wynik, przy użyciu węzła Offset utworzyliśmy dwie powierzchnie.
Tak samo jak w poprzednim ćwiczeniu, zdefiniuj węzeł Code Block zawierający te dwa wiersze kodu:
0..1..#20;
0..1..#20;
Połącz te dane wyjściowe z dwoma węzłami Surface.PointAtParameter, każdy z opcją skratowania ustawioną na „Iloczyn wektorowy”. Jeden z tych węzłów jest połączony z pierwotnymi powierzchniami, a drugi z powierzchniami odsuniętymi.
Tak samo jak w poprzednim ćwiczeniu, połącz elementy wyjściowe z dwoma węzłami NurbsCurve.ByPoints.
W danych wyjściowych węzła NurbsCurve.ByPoints widzimy, że jest to lista dwóch list, czyli bardziej złożona struktura niż w poprzednim ćwiczeniu. Dane są kategoryzowane według bazowej powierzchni, a więc dodaliśmy do struktury danych kolejny poziom.
Należy zauważyć, że sytuacja w węźle Surface.PointAtParameter się skomplikowała. Mamy już listę list list.
Przed przejściem dalej wyłącz podgląd z istniejących powierzchni.
Za pomocą węzła List.Create scalamy krzywe NURBS w jedną strukturę danych, tworząc listę list list.
Połączenie z węzłem Surface.ByLoft powoduje utworzenie nowej wersji pierwotnych powierzchni, z których każda pozostaje na osobnej liście utworzonej na podstawie początkowej struktury danych.
W poprzednim ćwiczeniu można było użyć węzła List.Transpose, aby utworzyć żebrowaną strukturę. W tym przypadku to nie zadziała. Transpozycję można stosować do listy dwuwymiarowej, a ponieważ mamy listę trójwymiarową, nie można tak łatwo „zamienić kolumn i wierszy”. Należy pamiętać, że listy to obiekty, a więc węzeł List.Transpose spowodowałby zamianę list z podlistami, ale nie zamianę krzywych NURBS na kolejnym poziomie hierarchii list.
W tym przypadku lepiej będzie działać węzeł List.Combine. Przechodząc do bardziej złożonych struktur danych, używamy węzłów List.Map i List.Combine.
Używając węzła List.Create jako „kombinatora”, tworzymy strukturę danych, która będzie lepiej przystosowana do naszego celu.
Struktura danych wymaga jeszcze transpozycji na niższym poziomie hierarchii. W tym celu użyjemy węzła List.Map. Działa on podobnie jak węzeł List.Combine, ale wymaga jednej listy wejściowej, a nie dwóch lub więcej.
Do węzła List.Map zastosujemy funkcję List.Transpose, która spowoduje zamianę kolumn i wierszy podlist na głównej liście.
Na koniec możemy wyciągnąć krzywe NURBS wraz z odpowiednią hierarchią danych, co daje żebrowaną strukturę.
Teraz dodamy głębię do tej geometrii za pomocą węzła Surface.Thicken z pokazanymi ustawieniami wejść.
Dobrze będzie dodać powierzchnię pokrywającą się z tą strukturą, dlatego dodaj kolejny węzeł Surface.ByLoft i jako wejścia użyj pierwszego wyjścia węzła NurbsCurve.ByPoints z wcześniejszego kroku.
Gdy podgląd staje się coraz mniej czytelny, wyłącz podgląd dla tych węzłów, klikając prawym przyciskiem myszy każdy z nich i anulując wybór pola podglądu („preview”), aby wyniki były czytelniejsze.
Po pogrubieniu wybranych powierzchni artykulacja jest gotowa.
Nie jest to może najwygodniejszy fotel bujany, ale zawiera dużo danych.
Na ostatnim etapie odwrócimy kierunek prążków. W poprzednim ćwiczeniu stosowaliśmy transpozycję. Tu zrobimy coś podobnego.
Ponieważ hierarchia ma jeszcze jeden poziom, należy użyć węzła List.Map z funkcją List.Transpose, aby zmienić kierunek krzywych NURBS.
Jeśli chcemy zwiększyć liczbę stopni, możemy zmienić węzeł Code Block następująco:
0..1..#20;
0..1..#30;
Pierwsza wersja fotela bujanego była bardziej elegancka, a nasz drugi model to wersja dla miłośników sportów ekstremalnych.
Dodajmy jeszcze jeden poziom do hierarchii. Jeśli weźmiemy talię kart z pierwszego przykładu i utworzymy pudełko z wieloma taliami, to pudełko reprezentuje listę talii, a każda talia reprezentuje listę kart. Tak działa lista list. Na potrzeby porównania w tej sekcji zakładamy, że ilustracja poniżej zawiera listę rolek monet, a każda rolka zawiera listę monet pensów.
Jakie zapytania możemy utworzyć względem listy list? Umożliwia to dostęp do istniejących właściwości.
Ile jest typów monet? 2.
Jakie są wartości typów monet? 0,01 USD i 0,25 USD.
Z czego składają się monety 0,25 USD? 75% miedzi i 25% niklu.
Z czego składają się monety 0,01 USD? 97,5% cynku i 2,5% miedzi.
Jakie działania możemy wykonać na liście list? Lista list ulegnie zmianie zależnie od zadanej operacji.
Wybranie określonego stosu monet 0,25 lub 0,01 USD.
Wybranie określonej monety.
Zmiana kolejności stosów monet 0,25 i 0,01 USD.
Wymieszanie stosów.
Dodatek Dynamo zawiera węzeł odpowiadający każdej z powyższych operacji. Pracujemy na danych abstrakcyjnych, a nie obiektach fizycznych, dlatego jest potrzebny zestaw reguł dotyczących poruszania się w hierarchii danych.
W przypadku list list dane są złożone i znajdują się na wielu warstwach. Taka reprezentacja pozwala wykonywać wiele przydatnych operacji parametrycznych. W poniższych lekcjach omówimy podstawy tego systemu i jeszcze kilka operacji.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
Najważniejsze założenie wynikające z tej sekcji jest takie, że dodatek Dynamo traktuje każdą listę jako obiekt. Taka hierarchia jest przydatna w przypadku programowania obiektowego. Zamiast wybierać elementy podrzędne przy użyciu poleceń takich jak List.GetItemAtIndex, dodatek Dynamo wybierze ten indeks na głównej liście struktury danych. Pod tym indeksem znajduje się kolejna lista. Przeanalizujemy ten mechanizm na przykładowej ilustracji:
W węźle Code Block zdefiniowaliśmy dwa zakresy:
0..2; 0..3;
Te zakresy są połączone z węzłem Point.ByCoordinates, gdzie skratowanie ustawiono na Iloczyn wektorowy. Powstaje w ten sposób siatka punktów, a na wyjściu jest generowana lista list.
Węzeł Watch wskazuje, że na każdej liście znajdują się 3 listy po 4 elementy.
W przypadku użycia węzła List.GetItemAtIndex z indeksem 0 dodatek Dynamo wybierze pierwszą listę z całą jej zawartością. Inne programy mogą wybrać pierwszy element każdej z list w strukturze danych, ale w dodatku Dynamo jest stosowana hierarchiczna obsługa danych.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
Węzeł Flatten usuwa wszystkie poziomy ze struktury danych. Jest to przydatne, gdy hierarchia danych nie jest potrzebna w danej operacji, ale też ryzykowne, gdyż powoduje usunięcie informacji. Poniższy przykład ilustruje skutek spłaszczenia listy danych.
Wstaw wiersz kodu, aby zdefiniować zakres w węźle Code Block:
-250..-150..#4;
Połączymy węzeł Code Block z danymi wejściowymi x i y węzła Point.ByCoordinates i ustawimy skratowanie na Iloczyn wektorowy, aby usunąć siatkę punktów.
Węzeł Watch wskazuje, że powstała lista list.
Węzeł PolyCurve.ByPoints będzie odnosił się do każdej z listy i utworzy odpowiadające im krzywe złożone. W podglądzie dodatku Dynamo widać, że istnieją cztery krzywe złożone (polycurve) reprezentujące poszczególne wiersze siatki.
Wstawiając funkcję Flatten (spłaszczenia) przed węzłem krzywej złożonej, utworzyliśmy pojedynczą listę zawierającą wszystkie punkty. Węzeł PolyCurve.ByPoints odnosi się do listy, aby utworzyć jedną krzywą. Ponieważ wszystkie punkty są na liście, uzyskujemy jedną, skomplikowaną krzywą złożoną zawierającą te punkty.
Można również spłaszczyć wybrane poziomy danych. Węzeł List.Flatten pozwala zdefiniować zestaw tych poziomów danych w hierarchii, które mają zostać spłaszczone. Jest to bardzo przydatne narzędzie podczas przetwarzania złożonych struktur danych, które nie są bezpośrednio powiązane z bieżącym procesem roboczym. Oprócz tego można użyć węzła spłaszczania jako funkcji węzła List.Map. Poniżej przedstawiono więcej informacji na temat węzła List.Map.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
Gdy model jest oparty na parametrach, czasami trzeba zmodyfikować strukturę danych istniejącej listy. Można to zrobić przy użyciu różnych węzłów, a węzeł podziału oferuje najprostszy mechanizm. Pozwala on podzielić listę na listy podrzędne o określonej liczbie elementów.
Polecenie Chop dzieli listy zależnie od długości listy wejściowej. W pewnym sensie dzielenie jest operacją odwrotną do spłaszczania: zamiast redukować strukturę danych, generuje nowe poziomy. Jest to przydatne narzędzie podczas pracy nad geometrią, tak jak na poniższym przykładzie.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
Węzeł List.Map/Combine stosuje zadaną funkcję do listy wejściowej, ale o jeden poziom niżej w hierarchii. Kombinacje działają analogicznie do map, ale mają wiele wejść odpowiadających wejściu zadanej funkcji.
Na wstępie przyjrzymy się węzłowi List.Count z poprzedniej sekcji.
Węzeł List.Count liczy wszystkie elementy na liście. Użyjemy go, aby zademonstrować działanie węzła List.Map.
Wstaw dwa wiersze kodu do węzła Code Block:
-50..50..#Nx; -50..50..#Ny;
Po wpisaniu tego kodu blok będzie tworzył dwie dane wejściowe: Nx i Ny.
Korzystając z dwóch suwaków Integer Slider, zdefiniuj wartości Nx i Ny przez połączenie ich z węzłem Code Block.
Połącz poszczególne wiersze węzła Code Block odpowiednio z danymi wejściowymi X i Y węzła Point.ByCoordinates. Kliknij węzeł prawym przyciskiem myszy, wybierz opcję Skratowanie i wybierz pozycję Iloczyn wektorowy. Zostanie utworzona siatka punktów. Ustawiliśmy zakres od –50 do 50, dlatego odpowiada to domyślnej siatce dodatku Dynamo.
Węzeł Watch ujawnia utworzone punkty. Przyjrzyjmy się strukturze danych. Powstała lista list. Każda lista odpowiada wierszowi punktów siatki.
Połącz węzeł List.Count z wyjściem węzła obserwacyjnego z poprzedniego kroku.
Połącz węzeł Watch z wyjściem węzła List.Count.
Węzeł List.Count generuje wartość 5. Jest to równe zmiennej Nx zdefiniowanej w bloku kodu. Dlaczego tak jest?
Najpierw węzeł Point.ByCoordinates używa wejścia „x” jako głównej wartości wejściowej podczas tworzenia list. Gdy wartość Nx wynosi 5, a Ny wynosi 3, powstaje lista 5 list po 3 elementy.
Dodatek Dynamo traktuje listy jako obiekty, dlatego węzeł List.Count jest stosowany do listy głównej w hierarchii. Daje to wynik 5, czyli liczbę list na liście głównej.
Przy użyciu węzła List.Map przejdziemy niżej w hierarchii i wykonamy pewną funkcję na tym poziomie.
Węzeł List.Count nie ma żadnych wejść. Jest używany jako funkcja. Oznacza to, że węzeł List.Count jest stosowany do każdej z listy na niższym poziomie w hierarchii. Puste wejście węzła List.Count odpowiada liście wyjściowej węzła List.Map.
Jako wynik węzła List.Count otrzymujemy teraz listę 5 elementów, każdy o wartości 3. Odpowiada to długości poszczególnych podlist.
W tym ćwiczeniu użyjemy węzła List.Combine, aby zademonstrować, jak można użyć go do zastosowania funkcji w oddzielnych listach obiektów.
Zacznij od przygotowania dwóch list punktów.
Użyj węzła Sequence, aby wygenerować 10 wartości, z których każda będzie miała przyrost 10-krokowy.
Połącz wynik z wejściem x węzła Point.ByCoordinates. Spowoduje to utworzenie listy punktów w dodatku Dynamo.
Dodaj drugi węzeł Point.ByCoordinates do obszaru roboczego, użyj tego samego wyjścia Sequence co w przypadku wejścia x, ale jako wejścia y użyj Interger Slider i ustaw jego wartość na 31 (może to być dowolna wartość, o ile nie będzie zachodzić na pierwszy zestaw punktów), tak aby 2 zestawy punktów nie nakładały się na siebie.
Następnie użyjemy węzła List.Combine, aby zastosować funkcję do obiektów na 2 osobnych listach. W tym przypadku będzie to prosta funkcja rysowania linii.
Dodaj węzeł List.Combine do obszaru roboczego i połącz 2 zestawy punktów jako wejścia list0 i list1.
Użyj Line.ByStartPointEndPoint jako funkcji wejściowej dla węzła List.Combine.
Po zakończeniu te 2 zestawy punktów są spakowane/sparowane za pomocą funkcji Line.ByStartPointEndPoint i powodują zwrócenie 10 linii w dodatku Dynamo.
Zapoznaj się z ćwiczeniem w części dotyczącej list n-wymiarowych, aby zobaczyć inny przykład użycia węzła List.Combine.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
Funkcja List@Level jest preferowana względem węzła List.Map. Umożliwia ona bezpośrednie wybranie poziomu listy, który ma być przetwarzany — wprost na porcie wejściowym węzła. Tę funkcję można zastosować do dowolnego wejścia przychodzącego węzła, aby uzyskać dostęp do poziomów list szybciej i łatwiej niż w przypadku innych metod. Wystarczy wskazać węzłowi, który poziom listy ma być używany jako wejście, a węzeł zrobi resztę.
W tym ćwiczeniu użyjemy funkcji List@Level, aby odizolować określony poziom danych.
Zaczniemy od prostej trójwymiarowej siatki punktów.
Siatka jest tworzona przy użyciu zakresów X, Y i Z, dlatego wiemy, że struktura danych ma trzy poziomy: listy X, Y i Z.
Dane istnieją na różnych poziomach. Poziomy są wskazywane u dołu podglądu. Kolumny poziomów list odpowiadają danym na powyższych listach, co ułatwia identyfikację poziomu, który ma być przetwarzany.
Lista poziomów jest uporządkowana w odwrotnej kolejności — najniższy poziom danych na niej to zawsze poziom L1. Gwarantuje to odpowiednie działanie wykresów, nawet jeśli zostaną zmienione w przyszłości.
Aby użyć funkcji List@Level, kliknij przycisk >. W tym menu znajdują się dwa pola wyboru.
Użyj poziomów — powoduje to włączenie funkcji List@Level. Po kliknięciu tej opcji można klikać, aby wybierać poziomy list wejściowych, których ma używać węzeł. To menu pozwala szybko wypróbować różne opcje dotyczące poziomów, klikając strzałki w górę lub w dół.
Zachowaj strukturę listy — gdy ta opcja jest włączona, można zachować strukturę poziomów danych wejściowych. Czasami dane są celowo uporządkowane na podlistach. Zaznaczenie tej opcji pozwala zachować porządek list i uniknąć utraty informacji.
Dzięki prostej siatce 3D można otwierać i wizualizować strukturę list, przełączając różne poziomy list. Każda kombinacja poziomu list i indeksu zwraca inny zestaw punktów z oryginalnego zestawu 3D.
Filtr „@L2” w kodzie DesignScript umożliwia wybranie samej listy na poziomie 2. Lista na poziomie 2 z indeksem 0 zawiera tylko pierwszy zestaw punktów Y — zwracana jest siatka na płaszczyźnie XZ.
Jeśli zmienimy filtr poziomów na „L1”, uzyskamy dostęp do wszystkich danych na pierwszym poziomie list. Lista na poziomie 1 z indeksem 0 jest płaską listą z wszystkimi punktami 3D.
Filtr „L3” udostępnia tylko punkty z trzeciego poziomu list. Lista na poziomie 3 z indeksem 0 zawiera tylko pierwszy zestaw punktów Z — zwracana jest siatka na płaszczyźnie XY.
Filtr „L4” udostępnia tylko punkty z trzeciego poziomu list. Lista na poziomie 4 z indeksem 0 zawiera tylko pierwszy zestaw punktów X — zwracana jest siatka na płaszczyźnie YZ.
Choć dane z tego przykładu można uzyskać przy użyciu węzła List.Map, funkcja List@Level zdecydowanie upraszcza te interakcje, przez co ułatwia dostęp do danych węzła. Poniżej przedstawiono porównanie metod List.Map i List@Level:
Choć obie metody pozwalają uzyskać dostęp do tych samych punktów, funkcja List@Level ułatwia wybranie odpowiednich warstw danych w jednym węźle.
Aby użyć siatki punktów za pomocą węzła List.Map, trzeba użyć węzła List.GetItemAtIndex w połączeniu z węzłem List.Map. Każde przejście na niższy poziom listy wymaga użycia dodatkowego węzła List.Map. Zależnie od złożoności używanych list uzyskanie dostępu do odpowiednich informacji może wymagać dodania wielu węzłów List.Map do wykresu.
W tym przykładzie węzeł List.GetItemAtIndex połączony z węzłem List.Map zwraca ten sam zestaw punktów z tą samą strukturą list co węzeł List.GetItemAtIndex z wybraną opcją „@L3”.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
Transpozycja jest podstawową funkcją obsługi list zawierających listy. Podobnie jak w arkuszach kalkulacyjnych, transpozycja polega na zamianie węzłów z kolumnami w strukturze danych. Zademonstrujemy to na prostej macierzy poniżej. W kolejnej sekcji przedstawimy sposób tworzenia relacji geometrycznych przy użyciu transpozycji.
Usuniemy węzły List.Count z poprzednich ćwiczeń i przeniesiemy je do geometrii, aby sprawdzić strukturę danych.
Połącz węzeł PolyCurve.ByPoints z wyjściem węzła obserwacyjnego węzła Point.ByCoordinates.
Wyjście wskazuje 5 krzywych złożonych i widzimy te krzywe w podglądzie dodatku Dynamo. Węzeł Dynamo wyszukuje listę punktów (w tym przypadku jest to lista list punktów) i tworzy z nich pojedynczą krzywą złożoną. Każda z tych list jest konwertowana na krzywą w strukturze danych.
Węzeł List.Transpose zamieni wszystkie elementy z wszystkimi listami na liście list. Choć brzmi to jak złożona operacja, działa tak samo jak transpozycja w programie Microsoft Excel: zamienia kolumny z wierszami w strukturze danych.
Wynik abstrakcyjny: Transpozycja zmieniła strukturę listy. Zamiast 5 list po 3 elementy otrzymujemy 3 listy po 5 elementów.
Wynik geometryczny: przy użyciu węzła PolyCurve.ByPoints otrzymujemy 3 krzywe złożone biegnące prostopadle do oryginalnych krzywych.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
W tym ćwiczeniu zmienimy powierzchnię przy użyciu logiki zdefiniowanej w poprzednim ćwiczeniu. Tutaj nasz cel jest intuicyjny, ale nawigacja w strukturze danych wymaga więcej uwagi. Chcemy poruszyć powierzchnią, przesuwając punkt kontrolny.
Zacznij od powyższego ciągu węzłów. Tworzymy prostą powierzchnię obejmującą domyślą siatkę dodatku Dynamo.
Przy użyciu węzła Code Block wstaw te dwa wiersze kodu i połącz blok z wejściami u i v węzła Surface.PointAtParameter:
-50..50..#3;
-50..50..#5;
Pamiętaj, aby ustawić skratowanie węzła Surface.PointAtParameter na Iloczyn wektorowy.
Węzeł Watch wskazuje, że powstały 3 listy po 5 elementów.
W tym kroku chcemy pobrać punkt środkowy utworzonej siatki. Aby to zrobić, wybierzemy środkowy punkt środkowej listy. To naprawdę proste.
Aby upewnić się, że to właściwy punkt, można też klikać w węźle Watch, aby sprawdzić, czy używamy odpowiedniego elementu.
Przy użyciu węzła Code Block napiszemy prosty kod pobierający listę list:
points[1][2];
Przy użyciu węzła Geometry.Translate przesuniemy wybrany punkt w kierunku Z o 20 jednostek.
Wybierzmy też środkowy wiersz punktów, używając węzła List.GetItemAtIndex. Uwaga: podobnie jak w poprzednim kroku, możemy pobrać elementy listy przy użyciu węzła Code Block zawierającego wiersz
points[1];
Pobraliśmy punkt środkowy i przesunęliśmy go w górę. Teraz chcemy wstawić przesunięty punkt z powrotem do struktury danych.
Najpierw chcemy zastąpić odizolowany w poprzednim kroku element listy.
Zastąpimy środkowy element przy użyciu węzła List.ReplaceItemAtIndex. Użyjemy indeksu 2, a zastępujący go element będzie połączony z przesuniętym punktem (Geometry.Translate).
W danych wyjściowych widzimy, że wprowadziliśmy przesunięty punkt jako środkowy element listy.
Mając zmodyfikowaną listę, musimy wstawić ją z powrotem do oryginalnej struktury danych: listy list.
W analogiczny sposób użyjemy węzła List.ReplaceItemAtIndex, aby wstawić naszą listę w miejsce środkowej listy.
Węzły Code Block definiujące indeks tych dwóch węzłów mają numery 1 i 2, co odpowiada oryginalnemu zapytaniu w węźle Code Block (points[1][2]).
Po wybraniu listy o indeksie 1 zobaczymy tę strukturę danych podświetloną w podglądzie dodatku Dynamo. Pomyślnie scaliliśmy przesunięty punkt z oryginalną strukturą danych.
Istnieją różne sposoby uzyskania powierzchni z tego zestawu punktów. W tym przypadku utworzymy ją przez wyciągnięcie połączonych krzywych.
Utwórz węzeł NurbsCurve.ByPoints i połącz z nim nową strukturę danych, aby utworzyć trzy krzywe NURBS.
Połącz węzeł Surface.ByLoft z wyjściem węzła NurbsCurve.ByPoints. Otrzymaliśmy zmodyfikowaną powierzchnię. Możemy zmienić oryginalną wartość Z geometrii. Użyj translacji i zobacz, jak zostanie zaktualizowana geometria.
Ustaliliśmy już, czym jest lista. Omówmy teraz operacje, które możemy na niej wykonać. Wyobraź sobie listę jako talię kart do gry. Talia jest listą, a każda karta reprezentuje element.
Jakie zapytania możemy wykonać z poziomu listy? Umożliwia to dostęp do istniejących właściwości.
Liczba kart w talii? 52.
Liczba kolorów? 4.
Materiał? Papier.
Długość? 3,5" lub 89 mm.
Szerokość? 2,5" lub 64 mm.
Jakie działania możemy wykonać na liście list? Umożliwia to zmianę listy w oparciu o daną operację.
Możemy potasować talię.
Możemy posortować talię według wartości.
Możemy posortować talię według kolorów.
Możemy podzielić talię.
Możemy rozdać karty w talii.
Możemy wybrać określoną kartę w talii.
Dla wszystkich operacji wymienionych powyżej istnieją analogiczne węzły Dynamo do pracy z listami danych ogólnych. W poniższych lekcjach przedstawiono niektóre z podstawowych operacji, które można wykonywać na listach.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
Poniższy rysunek przedstawia wykres bazowy, na którym rysujemy linie między dwoma okręgami, aby przedstawić podstawowe operacje na listach. Przeanalizujemy sposób zarządzania danymi na liście i przedstawimy wyniki wizualne za pomocą poniższych operacji na liście.
Rozpocznij od węzła Code Block o wartości
500;
Połącz wejście x z węzłem Point.ByCoordinates.
Podłącz węzeł z poprzedniego kroku do wejścia origin węzła Plane.ByOriginNormal.
Za pomocą węzła Circle.ByPlaneRadius podłącz węzeł z poprzedniego kroku do wejścia plane.
Używając węzła Code Block, oznacz wartość
50;
dla pozycji radius. To pierwszy okrąg, który utworzymy.Za pomocą węzła Geometry.Translate przesuń okrąg w górę o 100 jednostek w kierunku Z.
Za pomocą węzła Code Block zdefiniuj zakres dziesięciu liczb z zakresu od 0 do 1 przy użyciu tego wiersza kodu:
0..1..#10;
Wstaw blok kodu z poprzedniego kroku do wejścia param dwóch węzłów Curve.PointAtParameter. Podłącz węzeł Circle.ByPlaneRadius do wejścia curve górnego węzła i węzeł Geometry.Translate do wejścia curve węzła poniżej.
Za pomocą węzła Line.ByStartPointEndPoint połącz dwa węzły Curve.PointAtParameter.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
Węzeł List.Count jest prosty: zlicza wartości na liście i zwraca ich liczbę. Jego działanie jest nieco bardziej złożone podczas pracy z listami list, ale zilustrujemy to w późniejszych sekcjach.
Węzeł **List.Count ****** zwraca liczbę linii w węźle Line.ByStartPointEndPoint. W tym przypadku wynosi ona 10, co odpowiada liczbie punktów utworzonych z oryginalnego węzła Code Block.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
Węzeł List.GetItemAtIndex zapewnia podstawowy sposób stosowania zapytania dotyczącego elementu listy.
Najpierw kliknij prawym przyciskiem myszy węzeł Line.ByStartPointEndPoint, aby wyłączyć jego podgląd.
Za pomocą węzła List.GetItemAtIndex wybieramy indeks „0”, czyli pierwszy element na liście linii.
Zmień wartość suwaka na od 0 do 9, aby wybrać inny element za pomocą węzła List.GetItemAtIndex.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
Węzeł List.Reverse odwraca kolejność wszystkich elementów na liście.
Aby poprawnie zwizualizować odwróconą listę linii, utwórz więcej linii, zmieniając węzeł Code Block na
0..1..#50;
Powiel węzeł Line.ByStartPointEndPoint oraz wstaw węzeł List.Reverse między węzłem Curve.PointAtParameter i drugim węzłem Line.ByStartPointEndPoint
Użyj węzłów Watch3D, aby wyświetlić podgląd dwóch różnych wyników. Pierwszy pokazuje wynik bez odwróconej listy. Linie łączą się pionowo z sąsiednimi punktami. Natomiast odwrócona lista powoduje połączenie wszystkich punktów w kolejności odwrotnej na drugiej liście.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
Węzeł List.ShiftIndices jest dobrym narzędziem do tworzenia skrętów lub wzorców śrubowych albo do innych podobnych manipulacji danymi. Ten węzeł przesuwa elementy na liście o podaną wartość indeksu.
W tym samym procesie, w którym występuje odwrócona lista, wstaw węzeł List.ShiftIndices do węzłów Curve.PointAtParameter i Line.ByStartPointEndPoint.
Używając węzła Code Block, określ wartość „1”, aby przesunąć listę o jeden indeks.
Zauważmy, że zmiana jest subtelna, ale wszystkie linie w dolnym węźle Watch3D przesunęły się o jeden indeks podczas łączenia się z drugim zestawem punktów.
Po zmianie wartości w węźle Code Block na większą, na przykład „30”, zauważamy znaczną różnicę w liniach ukośnych. W tym przypadku przesunięcie działa jak obiektyw aparatu, tworząc skręt w oryginalnej formie walcowej.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
Węzeł List.FilterByBooleanMask usuwa niektóre elementy w oparciu o listę wartości logicznych lub wartości odczytywanych jako „true” lub „false”.
Aby utworzyć listę wartości odczytywanych jako „true” lub „false”, musimy wykonać nieco więcej pracy.
Używając węzła Code Block, zdefiniuj wyrażenie ze składnią:
0..List.Count(list);
. Połącz węzeł Curve.PointAtParameter z wejściem list. Przeanalizujemy tę konfiguracje dokładniej w rozdziale dotyczącym węzła Code Block, ale wiersz kodu w tym przypadku tworzy listę reprezentującą każdy indeks węzła Curve.PointAtParameter.Używając węzła %** (moduł)**, połącz wyjście węzła Code Block z wejściem x oraz wartość 4 z wejściem y. Spowoduje to zwrócenie reszty z dzielenia listy indeksów przez 4. Węzeł modułu jest bardzo przydatny podczas tworzenia szyku. Wszystkie wartości będą odczytywane jako możliwe reszty z dzielenia przez 4, czyli 0, 1, 2 i 3.
Na podstawie węzła %** (moduł)** wiemy, że wartość 0 oznacza, iż indeks jest podzielny przez 4 (0, 4, 8 itd...). Za pomocą węzła == możemy sprawdzić tę dzielność, testując tę pozycję pod kątem wartości „0”.
Węzeł Watch pokazuje tylko, że mamy wzorzec true/false, który wygląda następująco: true,false,false,false....
Używając tego wzorca true/false, utwórz połączenie z wejściem mask dwóch węzłów List.FilterByBooleanMask.
Połącz węzeł Curve.PointAtParameter z każdym wejściem list węzła List.FilterByBooleanMask.
Wyjścia węzła Filter.ByBooleanMask to „in” oraz „out”. Wyjście „in” reprezentuje wartości, które miały wartość maski „true”, a wyjście „out” — wartość maski „false”. Podłączając wyjścia „in” do wejść startPoint i endPoint węzła Line.ByStartPointEndPoint, utworzyliśmy przefiltrowaną listę linii.
Węzeł Watch3D pokazuje, że mamy mniej linii niż punktów. Wybraliśmy tylko 25% węzłów, filtrując tylko wartości true.
Lista to zbiór elementów. Weźmy na przykład kiść bananów. Każdy banan jest elementem listy (czyli kiści). Łatwiej jest chwycić kiść bananów niż zbierać pojedyncze banany — i tak samo jest w przypadku grupowania elementów według zależności parametrycznych w strukturze danych.
Robiąc zakupy, wkładamy wszystkie kupione artykuły do torby. Taka torba również jest listą. Jeśli chcemy upiec chleb bananowy, potrzebujemy 3 kiści bananów (robimy dużo chleba bananowego). Torba to lista kiści bananów, a każda kiść to lista bananów. Torba jest więc listą list (dwuwymiarową), a kiść bananów jest listą (jednowymiarową).
W dodatku Dynamo dane list są uporządkowane, a pierwszy element na każdej liście ma indeks „0”. Poniżej omówiono sposób definiowania list w dodatku Dynamo oraz to, jak listy wiążą się ze sobą nawzajem.
Jedno, co może z początku wydawać się dziwne, to fakt, że pierwszy indeks listy zawsze ma wartość 0, a nie 1. Gdy zatem mówimy o pierwszym elemencie listy, oznacza to tak naprawdę element odpowiadający indeksowi 0.
Jeśli na przykład liczymy palce prawej dłoni, najprawdopodobniej ponumerujemy je od 1 do 5. Gdybyśmy jednak umieścili te palce na liście, w dodatku Dynamo otrzymałyby indeksy od 0 do 4. Chociaż początkującym programistom może się to wydawać trochę dziwne, indeksowanie od zera stanowi standardową praktykę w większości systemów obliczeniowych.
Należy pamiętać, że lista wciąż zawiera 5 elementów, po prostu korzystamy z systemu liczenia od zera. Elementy na liście nie muszą być liczbami. Mogą to być dane dowolnego typu obsługiwanego przez dodatek Dynamo, takie jak punkty, krzywe, powierzchnie, rodziny itp.
a. Indeks
b. Punkt
c. Element
Często najprostszym sposobem na sprawdzenie typu danych przechowywanych na liście jest połączenie węzła Watch z elementem wyjściowym innego węzła. Domyślnie węzeł Watch automatycznie wyświetla wszystkie indeksy po lewej stronie listy, a elementy danych po prawej stronie.
Indeksy są kluczowym elementem podczas pracy z listami.
W odniesieniu do list dane wejściowe i wyjściowe różnią się w zależności od używanego węzła Dynamo. Możemy na przykład użyć listy 5 punktów i połączyć jej elementy wyjściowe z dwoma różnymi węzłami Dynamo, PolyCurve.ByPoints i Circle.ByCenterPointRadius:
Element wejściowy points węzła PolyCurve.ByPoints wyszukuje wartości „Point[]”. Reprezentuje listę punktów.
Elementem wyjściowym węzła PolyCurve.ByPoints jest jedna krzywa PolyCurve utworzona na podstawie listy pięciu punktów.
Element wejściowy centerPoint węzła Circle.ByCenterPointRadius wymaga wartości „Point”.
Elementem wyjściowym węzła Circle.ByCenterPointRadius jest lista pięciu okręgów, których środki odpowiadają pierwotnej liście punktów.
Dane wejściowe dla węzłów PolyCurve.ByPoints i Circle.ByCenterPointRadius są takie same, ale węzeł Polycurve.ByPoints pozwala uzyskać jedną krzywą PolyCurve, a węzeł Circle.ByCenterPointRadius — 5 okręgów ze środkami w poszczególnych punktach. Jest to intuicyjnie zrozumiałe: krzywa PolyCurve jest rysowana jako łuk łączący 5 punktów, a okręgi tworzone są w każdym punkcie osobno. Co zatem dzieje się z danymi?
Po ustawieniu kursora myszy na elemencie wejściowym points węzła Polycurve.ByPoints widzimy, że wyszukuje on wartości „Point[]”. Zwróć uwagę na nawiasy na końcu. To oznacza listę punktów, a do utworzenia krzywej PolyCurve potrzebne są dane wejściowe w postaci listy. Ten węzeł będzie więc sumował każdą listę w jedną krzywą PolyCurve.
Natomiast element wejściowy centerPoint węzła Circle.ByCenterPointRadius wymaga wartości „Point”. W tym węźle wyszukiwany jest jeden punkt, czyli element, w celu zdefiniowania środka okręgu. Dlatego otrzymujemy pięć okręgów z danych wejściowych. Zrozumienie tej różnicy w danych wejściowych w dodatku Dynamo pomaga lepiej zrozumieć działanie węzłów podczas zarządzania danymi.
Dopasowywanie danych stanowi problem bez idealnego rozwiązania. Ma on miejsce, gdy węzeł ma dostęp do danych wejściowych o różnych rozmiarach. Zmiana algorytmu dopasowywania danych może prowadzić do uzyskania całkiem różnych wyników.
Wyobraź sobie węzeł służący do tworzenia odcinków między punktami (Line.ByStartPointEndPoint). Ma on dwa parametry wejściowe, określające współrzędne obu punktów:
Najprostszym sposobem jest łączenie elementów wejściowych pojedynczo, aż jeden ze strumieni się wyczerpie. Jest to tak zwany algorytm „najkrótszej listy”. Jest to domyślne działanie węzłów Dynamo:
Algorytm „najdłuższa lista” kontynuuje łączenie elementów wejściowych i ponownie używa elementów do momentu, aż wszystkie strumienie się wyczerpią:
Metoda iloczynu wektorowego służy do wykonania wszystkich możliwych połączeń:
Jak widać, istnieją różne sposoby rysowania linii między tymi zbiorami punktów. Opcje skratowania można znaleźć, klikając prawym przyciskiem myszy środek węzła i wybierając menu „Skratowanie”.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
Aby zademonstrować poniżej operacje skratowania, użyjemy tego pliku bazowego do zdefiniowania najkrótszej listy, najdłuższej listy i iloczynu wektorowego.
Zmienimy skratowanie w węźle Point.ByCoordinates, ale nie zmienimy żadnych innych elementów na wykresie powyżej.
Wybierając opcję najkrótsza lista jako opcję skratowania (jest to również opcja domyślna), otrzymujemy podstawową linię ukośną złożoną z pięciu punktów. Pięć punktów to długość krótszej listy, a więc skratowanie według najkrótszej listy zatrzymuje się po dotarciu do końca tej listy.
Po zmianie skratowania na opcję najdłuższa lista otrzymujemy linię ukośną, która dalej przebiega pionowo. Tak samo jak na diagramie koncepcyjnym, ostatni element z listy 5 elementów będzie używany ponownie do momentu osiągnięcia długości dłuższej listy.
Po zmianie opcji skratowania na iloczyn wektorowy otrzymujemy wszystkie kombinacje wszystkich list, co daje siatkę punktów 5x10. Jest to struktura danych równoważna iloczynowi wektorowemu pokazanemu na powyższym diagramie koncepcyjnym, z tą różnicą, że dane stanowią teraz listę list. Po połączeniu w krzywą PolyCurve widzimy, że każda lista jest zdefiniowana przez wartość X, co daje rząd pionowych linii.
Zdjęcie autorstwa .
Uwaga: to ćwiczenie utworzono we wcześniejszej wersji dodatku Dynamo. Wiele funkcji węzła List.Map przestało być potrzebnych po wprowadzeniu funkcji List@Level. Więcej informacji można znaleźć w sekcji poniżej.
Uwaga: to ćwiczenie utworzono we wcześniejszej wersji dodatku Dynamo. Wiele funkcji węzła List.Combine przestało być potrzebnych po wprowadzeniu funkcji List@Level. Więcej informacji można znaleźć w sekcji poniżej.
W kodzie bloku można użyć zapisu „[]”, aby utworzyć listę. Jest to szybsze i wygodniejsze niż użycie węzła List.Create. Węzeł Code Block jest bardziej szczegółowo opisany w rozdziale . Na poniższej ilustracji przedstawiono, jak zdefiniować w bloku kodu listę zawierającą wiele wyrażeń.
W węźle Code Block można użyć zapisu „[]”, aby szybko wybrać określone elementy ze złożonej struktury danych. Węzły Code Block są bardziej szczegółowo opisane w rozdziale . Na poniższej ilustracji przedstawiono, jak w bloku kodu uzyskać dostęp do listy zawierającej wiele typów danych.
Autor zdjęcia:
Autor zdjęcia: .