Ta strona informacyjna stanowi rozszerzenie wzorców postępowania omówionych w strategiach dotyczących skryptów, zapewniając więcej szczegółów na temat bibliotek kodu, etykiet i stylów. Będziemy używać języka Python, aby zilustrować poniższe koncepcje, lecz te same zasady miałyby zastosowanie w języku Python i C# (Zerotouch), ale w innej składni.
Biblioteki standardowe są zewnętrzne wobec dodatku Dynamo i są obecne w językach programowania Python i C# (Zerotouch). Dodatek Dynamo zawiera również własny zestaw bibliotek bezpośrednio odpowiadających hierarchii węzłów, umożliwiając użytkownikowi tworzenie dowolnego kodu, który może zostać utworzony za pomocą węzłów i przewodów. Poniżej przedstawiono wskazówki na temat tego, do czego każda biblioteka Dynamo zapewnia dostęp i kiedy należy używać standardowej.
Biblioteki standardowe i biblioteki Dynamo
Biblioteki standardowe z języka Python i języka C# mogą być używane do tworzenia zaawansowanych struktur danych i przepływów w środowisku dodatku Dynamo.
Biblioteki Dynamo bezpośrednio odpowiadają hierarchii węzłów w celu tworzenia geometrii i innych obiektów Dynamo.
Biblioteki Dynamo
ProtoGeometry*
Funkcjonalność: łuk, ramka ograniczająca, okrąg, stożek, układ współrzędnych, prostopadłościan, krzywa, walec, krawędź, elipsa, łuk eliptyczny, powierzchnia, geometria, helisa, grupa indeksu, linia, siatka, krzywa nurbs, powierzchnia nurbs, płaszczyzna, punkt, wielobok, prostokąt, bryła, sfera, powierzchnia, topologia, T-splajn, UV, wektor, wierzchołek.
Sposób importowania: import Autodesk.DesignScript.Geometry
``
DSCoreNodes
Funkcjonalność: kolor, zakres kolorów 2D, data i godzina, przedział czasu, IO, formuła, logika, lista, matematyka, drzewo czwórkowe, ciąg, gwint.
Sposób importowania: import DSCore
Mozaikowatość
Funkcjonalność: powłoka wypukła, Delaunay, Woronoj.
Sposób importowania: import Tessellation
DSOffice
Funkcjonalność: Excel.
Sposób importowania: import DSOffice
*Uwaga: podczas używania obiektu ProtoGeometry za pomocą języka Python lub C# tworzone są obiekty niezarządzane, które wymagają ręcznego zarządzania pamięcią — więcej informacji znajduje się w poniższej sekcji: Obiekty niezarządzane.
Podczas tworzenia skryptów ciągle wykorzystujemy identyfikatory do oznaczania takich elementów, jak zmienne, typy, funkcje i inne elementy. Poprzez ten system symbolicznej notacji podczas tworzenia algorytmów można wygodnie korzystać z informacji poprzez etykiety — zwykle składające się z sekwencji znaków. Nazewnictwo odgrywa ważną rolę w pisaniu kodu, który jest czytelny i zrozumiały dla jego twórcy i dla innych. Poniżej przedstawiono kilka wskazówek, o których należy pamiętać podczas nazywania elementów w skrypcie:
Używanie skrótów jest dozwolone, ale należy je objaśniać za pomocą komentarzy:
Unikaj nadmiarowego etykietowania:
W nazwach zmiennych używaj logiki dodatniej zamiast logiki ujemnej:
Preferuj „notację odwrotną”:
Jest sensowniejsza pod względem strukturalnym.
Do skracania zbyt długich i często powtarzanych łańcuchów powinny być używane aliasy:
Stosowanie aliasów może szybko doprowadzić do bardzo mylących i niestandardowych programów.
Używaj tylko niezbędnych słów:
„Wszystko powinno zostać tak uproszczone, jak to tylko możliwe, ale nie bardziej” — Albert Einstein
Ogólnie rzecz biorąc, istnieje więcej niż jeden sposób na zaprogramowanie praktycznie wszystkiego, a zatem „osobisty styl” tworzenia skryptów jest wynikiem niezliczonych małych decyzji podejmowanych (lub nie) w całym procesie. Jednocześnie czytelność i możliwości konserwacji kodu są bezpośrednio wynikiem jego wewnętrznej spójności, a także przestrzegania ogólnych konwencji stylistycznych. Według ogólnej zasady kod, który wygląda tak samo w dwóch miejscach, powinien także działać tak samo. Poniżej przedstawiono kilka wskazówek dotyczących pisania przejrzystego i spójnego kodu.
Konwencje nazewnictwa: (wybierz jedną z poniższych konwencji dla każdego typu elementu w kodzie i trzymaj się jej).
Zmienne, funkcje, metody, pakiety, moduły:
lower_case_with_underscores
Klasy i wyjątki:
CapWords
Metody chronione i funkcje wewnętrzne:
_single_leading_underscore(self, ...)
Metody prywatne:
__double_leading_underscore(self, ...)
Stałe:
ALL_CAPS_WITH_UNDERSCORES
Wskazówka: unikaj zmiennych jednoliterowych (szczególnie l, O, I) z wyjątkiem w bardzo krótkich blokach, kiedy ich znaczenie jest wyraźnie widoczne z bezpośredniego kontekstu.
Używaj pustych wierszy:
Otaczaj definicje funkcji i klas najwyższego poziomu dwoma pustymi wierszami.
Definicje metod wewnątrz klas są otoczone pojedynczym pustym wierszem.
Dodatkowe puste wiersze mogą być używane (sporadycznie) do oddzielenia grup powiązanych funkcji.
Unikaj zbędnych odstępów:
Bezpośrednio wewnątrz nawiasów okrągłych, kwadratowych i klamrowych:
Bezpośrednio przed przecinkiem, średnikiem lub dwukropkiem:
Bezpośrednio przed nawiasem otwierającym, który rozpoczyna listę argumentów wywołania funkcji:
Bezpośrednio przed nawiasem otwierającym, który rozpoczyna indeksowanie lub fragmentowanie:
Zawsze otaczaj te operatory binarne pojedynczym odstępem po obu stronach:
Przestrzegaj ograniczeń długości wiersza:
Nie twórz wierszy dłuższych niż około 79 znaków.
Ograniczenie wymaganej szerokości okna edytora umożliwia otwarcie kilku plików jednocześnie obok siebie i dobrze sprawdza się podczas używania narzędzi weryfikacji kodu, które prezentują dwie wersje w sąsiednich kolumnach.
Długie wiersze można dzielić na wiele wierszy, ujmując wyrażenia w nawiasy:
Unikaj oczywistych i nadmiarowych komentarzy:
Czasami mniejsza liczba komentarzy zapewnia większą czytelność kodu. Zwłaszcza jeśli wymusza to używanie znaczących nazw symboli.
Przyjęcie dobrych nawyków kodowania zmniejsza zależność od komentarzy:
Wskazówka: komentarze informują „dlaczego”, kod informuje „jak”.
Sprawdź kod typu Open Source:
Projekty typu Open Source są wynikiem wspólnych wysiłków wielu programistów. W tych projektach trzeba utrzymywać wysoki poziom czytelności kodu, aby zespół mógł jak najsprawniej współpracować. Dlatego dobrze jest przeglądać kod źródłowy tych projektów, aby obserwować, co robią ci programiści.
Popraw konwencje:
Analizuj, czy dana konwencja dobrze sprawdza się w odniesieniu do konkretnych potrzeb.
Czy nie pogarsza funkcjonalności/wydajności?
Zapoznaj się z poniższymi stronami wiki, aby uzyskać wskazówki dotyczące pisania kodu C# dla narzędzia Zerotouch i rozwijania dodatku Dynamo:
Na tej stronie wiki opisano niektóre ogólne standardy kodowania służące do dokumentowania i testowania kodu: https://github.com/DynamoDS/Dynamo/wiki/Coding-Standards
Na tej stronie wiki opisano szczegółowo standardy nazewnictwa bibliotek, kategorii, nazw węzłów, nazw portów i skrótów: https://github.com/DynamoDS/Dynamo/wiki/Naming-Standards
Obiekty niezarządzane:
W przypadku używania biblioteki geometrii dodatku Dynamo (ProtoGeometry) z języka Python lub geometrii C# utworzone obiekty nie będą zarządzane przez maszynę wirtualną, a pamięć wielu z tych obiektów będzie musiała zostać wyczyszczona ręcznie. Aby wyczyścić natywne lub niezarządzane obiekty, można użyć metody Dispose lub słowa kluczowego using. Na tej stronie wiki przedstawiono omówienie: https://github.com/DynamoDS/Dynamo/wiki/Zero-Touch-Plugin-Development#dispose--using-statement.
Wystarczy usunąć zasoby niezarządzane, które nie są zwracane w wykresie ani do których nie są zapisywane odwołania. W pozostałej części tej sekcji określamy te obiekty jako geometrię pośrednią. Przykład tej klasy obiektów można zobaczyć w poniższym przykładzie kodu. Ta funkcja singleCube w języku C# (Zerotouch) zwraca pojedynczy sześcian, ale podczas wykonywania generuje 10000 dodatkowych sześcianów. Możemy udawać, że ta druga geometria została użyta jako pewnego rodzaju pośrednia geometria konstrukcji.
Ta funkcja Zerotouch najprawdopodobniej spowoduje awarię dodatku Dynamo. Jest tak dlatego, że utworzyliśmy 10 000 brył, ale tylko jedną z nich zapisaliśmy i tę właśnie zwróciliśmy. Zamiast tego powinniśmy usunąć wszystkie sześciany pośrednie z wyjątkiem tego, który zwracamy. Nie chcemy usuwać tego, który zwracamy, ponieważ zostanie on propagowany do wykresu i będzie używany przez inne węzły.
Kod stały może wyglądać następująco:
Ogólnie rzecz biorąc, konieczność usuwania występuje tylko w przypadku takiej geometrii, jak Surfaces
, Curves
i Solids
. Jednak najlepiej jest usuwać wszystkie typy geometrii (Vectors
, Points
, CoordinateSystems
).
Ta część przewodnika ma postać dziennika „wzorców postępowania”. Zaprezentowano w niej kilka strategii, które dzięki doświadczeniom i badaniom, uznano za najbardziej sprzyjające wysokiej jakości parametrycznym procesom roboczym. Dla projektantów i programistów miara jakości jest przede wszystkim związana z możliwościami obsługi, niezawodnością, funkcjonalnością i wydajnością narzędzi. Choć te wzorce postępowania zaprezentowano na konkretnych przykładach skryptów wizualnych lub tekstowych, te zasady mają zastosowanie do wszystkich środowisk programowania i można na nich opierać wiele obliczeniowych procesów roboczych.
Praca z procesem programowania wizualnego może być bardzo wydajna i twórcza, ale przepływ programu i kluczowe dane wejściowe użytkownika mogą bardzo szybko zostać przesłonięte przez złożoność i układ obszaru roboczego. Przyjrzyjmy się niektórym wzorcom postępowania dotyczącym zarządzania programem.
Po dodaniu więcej niż kilku węzłów do obszaru roboczego może zajść potrzeba przeorganizowania układu węzłów, aby zwiększyć czytelność całości. Po wybraniu więcej niż jednego węzła i kliknięciu prawym przyciskiem myszy obszaru roboczego w oknie podręcznym zostanie wyświetlone menu Dopasuj wybór z opcjami wyrównania i dystrybucji na osiach X i Y.
Wybierz więcej niż jeden węzeł
Kliknij prawym przyciskiem myszy obszar roboczy
Użyj opcji Dopasuj wybór
Po nabraniu pewnego doświadczenia użytkownik może „odczytywać” program wizualny, przeglądając nazwy węzłów i podążając za przepływem programu. W przypadku użytkowników na wszystkich poziomach zaawansowania zaleca się również umieszczanie etykiet i opisów w prostym języku. Dodatek Dynamo zawiera przeznaczony do tego celu węzeł Notes z edytowalnym polem tekstowym. Opisy można dodawać do obszaru roboczego na dwa sposoby:
Przejdź do menu Edycja > Utwórz notatkę
Użyj skrótu klawiaturowego Ctrl+W
Po dodaniu notatki do obszaru roboczego zostanie wyświetlone pole tekstowe umożliwiające edycję tekstu w notatce. Po utworzeniu notatki można ją edytować, klikając dwukrotnie lub klikając prawym przyciskiem myszy węzeł Note.
Gdy program wizualny stanie się duży, pomocne będzie zidentyfikowanie zawartych w nim większych kroków. Można wyróżnić większe kolekcje węzłów jako grupę, aby oznaczyć je etykietą z kolorowym prostokątem w tle i tytułem. Istnieją trzy sposoby utworzenia grupy z więcej niż jednym wybranym węzłem:
Przejdź do menu Edycja > Utwórz grupę
Użyj skrótu klawiaturowego Ctrl+G
Kliknij prawym przyciskiem myszy obszar roboczy i wybierz polecenie „Utwórz grupę”
Po utworzeniu grupy można edytować jej ustawienia, takie jak tytuł i kolor.
Wskazówka: używanie zarówno notatek, jak i grup jest skutecznym sposobem opisywania pliku i zwiększania jego czytelności.
Oto przykład programu z dodanymi notatkami i grupami:
Notatka: „Parametry siatki”
Notatka: „Punkty siatki”
Grupa: „Utwórz siatkę punktów”
Grupa: „Utwórz punkt przyciągania”
Notatka: „Kalibracja wartości odległości”
Notatka: „Zmienna siatka okręgów”
Przed tym rozdziałem w tym elementarzu omówiono sposób korzystania z zaawansowanych funkcji skryptów wizualnych dostępnych w dodatku Dynamo. Zrozumienie tego systemu jest ważnym wstępem do pracy nad niezawodnymi programami wizualnymi. Kiedy programy wizualne są używane w środowisku produkcyjnym, udostępniane współpracownikom oraz badane w celu usunięcia błędów lub zbadania ich ograniczeń, powstają dodatkowe problemy wymagające rozwiązania. Jeśli opracowany program będzie używany przez inne osoby lub zamierzasz go otworzyć za kilka miesięcy, jego układ graficzny i logika muszą być od razu czytelne. Dodatek Dynamo zawiera szereg narzędzi ułatwiających obsługę złożonych programów. W tym rozdziale wyjaśniono, kiedy należy ich używać.
Podczas pracy w programie Dynamo i testowania pomysłów wykres może szybko przybrać duży rozmiar. Choć uzyskanie działającego programu jest ważne, należy też pamiętać, że powinien on być możliwie prosty. Dzięki temu wykres będzie działać szybciej, w bardziej przewidywalny sposób, a przyszli użytkownicy łatwiej zrozumieją jego logikę. Poniżej opisano kilka metod poprawiania czytelności logiki wykresu.
Grupy umożliwiają tworzenie części o oddzielnych funkcjach podczas pracy nad programem.
Grupy umożliwiają przenoszenie dużych części programów z zachowaniem podziału na moduły i rozkładu.
Można zmienić kolor grupy, aby wyróżnić grupy realizujące różne działania (obsługujące dane wejściowe lub funkcje).
Grupy pozwalają rozpocząć porządkowanie wykresu w celu usprawnienia pracy nad węzłami niestandardowymi.
Kolory w tym programie wskazują przeznaczenie poszczególnych grup. Ta strategia pozwala wprowadzić hierarchię opracowywanych standardów graficznych (szablonów).
Grupa funkcji (niebieskie)
Grupa danych wejściowych (pomarańczowe)
Grupa skryptów (zielone)
Informacje o korzystaniu z grup można znaleźć w artykule Zarządzanie programem.
Czasami przy użyciu węzła Code Block można szybko wpisać numer lub metodę węzła, zamiast wyszukiwać tę informację (Point.ByCoordinates, Number, String, Formula).
Węzły Code Block są przydatne, gdy trzeba zdefiniować funkcje niestandardowe w skrypcie DesignScript w celu ograniczenia liczby węzłów wykresu.
Bloki 1 i 2 realizują tę samą funkcję. Szybciej jest napisać kilka wierszy kodu niż wyszukiwać i dodawać poszczególne węzły. Blok kodu jest też krótszy.
Kod DesignScript w bloku kodu
Równoważny program w węzłach
Informacje o korzystaniu z węzłów Code Block można znaleźć w artykule Co to jest węzeł Code Block.
Aby zmniejszyć złożoność wykresu, można przekonwertować węzły na kod. Kolekcja prostych węzłów zostanie przekształcona w jeden węzeł Code Block z odpowiadającym im kodem DesignScript.
Konwersja węzłów na kod pozwala** skondensować kod z zachowaniem czytelności programu**
Poniżej wymieniono zalety konwersji węzłów na kod:
Kod można łatwo skondensować w jeden komponent, który nadal jest dostępny do edycji.
Pozwala uprościć znaczną część wykresu.
Jest przydatna, gdy powstający miniprogram nie będzie często edytowany.
Ułatwia integrowanie elementów innych bloków kodu, na przykład funkcji.
Poniżej wymieniono wady konwersji węzłów na kod:
Nazwy ogólne pogarszają czytelność wykresu.
Utrudnia innym użytkownikom zrozumienie wykresu.
Nie można łatwo przywrócić wersji wizualnej programu.
Istniejący program
Blok kodu utworzony przez konwersję węzłów na kod
Informacje o konwersji węzłów na kod można znaleźć w artykule Składnia języka DesignScript.
Funkcja List@Level umożliwia ograniczenie złożoności wykresu przez zastąpienie węzłów List.Map i List.Combine, które mogą zajmować dużo miejsca na obszarze projektowania.
Funkcja List@Level oferuje** szybszą metodę tworzenia logiki węzłów niż węzły List.Map/List.Combine**. Umożliwia ona uzyskiwanie dostępu do danych na każdym poziomie listy wprost z poziomu portu wejściowego węzła.
Można zweryfikować, ile wartości True z których list zwraca funkcja BoundingBox.Contains, aktywując funkcję List@Level dla wejścia „list” (lista) modułu CountTrue. Funkcja List@Level pozwala użytkownikowi określić, z jakiego poziomu danych wejściowych są pobierane dane. Korzystanie z funkcji List@Level jest elastyczne, efektywne i zalecane jako metoda skuteczniejsza niż stosowanie węzłów List.Map i List.Combine.
Liczenie wartości True na poziomie 2 listy
Liczenie wartości True na poziomie 3 listy
Sposób korzystania z funkcji List@Level omówiono w artykule Listy list.
Oprócz uproszczenia i poprawienia efektywności wykresu należy pamiętać o jego czytelności graficznej. Choć staramy się, aby wykres był intuicyjny w oparciu o grupy logiczne, relacje między węzłami mogą nie być oczywiste. Czasami dodanie prostej notatki w grupie lub zmiana nazwy suwaka pozwala wyeliminować nieporozumienia, jakie powstają podczas przeglądania wykresu. Poniżej omówiono kilka sposobów zachowywania spójności graficznej w obrębie wykresu i pomiędzy wykresami.
Aby ograniczyć nakłady pracy po zakończeniu tworzenia wykresu, warto zadbać o czytelność układu węzłów przez ich częste wyrównywanie podczas tworzenia wykresu.
Jeśli inne osoby będą pracowały nad tym samym wykresem, należy zagwarantować płynny przepływ połączeń między węzłami przed dostarczeniem wykresu.
Aby w prosty sposób wyrównać wykres, można użyć funkcji Wyczyść układ węzłów, która robi to automatycznie (choć mniej dokładnie niż człowiek).
Nieuporządkowany wykres
Wyrównany wykres
Informacje o wyrównywaniu węzłów można znaleźć w artykule Zarządzanie programem.
Zmieniając nazwy danych wejściowych, można poprawić czytelność wykresu, szczególnie jeśli elementy połączone z wejściami znajdują się poza ekranem.
Należy ostrożnie podchodzić do zmian nazw węzłów innych niż wejściowe. Zamiast tego można utworzyć węzeł niestandardowy ze zbioru węzłów i zmienić jego nazwę. Pozwoli to wskazać, że ten węzeł zawiera coś innego.
Dane wejściowe modyfikacji powierzchni
Dane wejściowe parametrów architektonicznych
Dane wejściowe skryptu symulacji odwadniania
Aby zmienić nazwę węzła, kliknij ją prawym przyciskiem myszy i wybierz opcję „Zmień nazwę węzła”.
Dodaj notatkę, jeśli część wykresu wymaga wyjaśnienia prostym językiem, a węzeł tego nie wyraża.
Dodaj notatkę, jeśli zbiór lub grupa węzłów zawiera wiele elementów lub osiąga taką złożoność, że utrudnia szybkie zrozumienie programu.
Notatka opisująca część programu, która zwraca pierwotne odległości przekształcenia
Notatka opisująca kod odwzorowujący te wartości na falę sinusoidalną
Informacje o sposobie dodawania notatek można znaleźć w artykule Zarządzanie programem.
Podczas tworzenia skryptu wizualnego ważne jest weryfikowanie, że zwracane dane są zgodne z oczekiwaniami. Nie każdy błąd lub problem powoduje natychmiastową awarię programu. Szczególnie wartości null i zerowe mogą generować błędy dopiero w innych, zależnych węzłach. Tę strategię omówiono również w kontekście skryptów tekstowych w artykule Strategie dotyczące skryptów. Poniższa procedura pozwala zagwarantować, że zawsze powstają dane zgodne z oczekiwaniami.
Węzły obserwacyjne (Watch) i podglądy pozwalają podczas tworzenia programu** weryfikować, że ważne dane wyjściowe są zwracane zgodnie z oczekiwaniami**
Węzły Watch umożliwiają porównywanie:
pierwotnych odległości przekształcenia,
wartości przekazywanych przez równanie sinusoidy.
Informacje o korzystaniu z węzła Watch można znaleźć w Bibliotece.
Jest bardzo prawdopodobne, że kiedyś inna osoba otworzy nasz program, nawet jeśli pracujemy niezależnie. Powinno wtedy być możliwe szybkie zrozumienie wymagań i wyników programu na podstawie jego wejść i wyjść. Jest to szczególnie istotne podczas programowania węzła niestandardowego, który zostanie udostępniony w społeczności Dynamo do użytku w cudzych programach. Te procedury pozwalają tworzyć niezawodne, gotowe do ponownego użycia programy i węzły.
Aby zagwarantować czytelność i skalowalność programu, należy używać jak najmniejszej liczby wejść i wyjść.
O ile to możliwe, należy rozważyć strukturę logiczną i opracować ogólną logikę algorytmu przed dodaniem jakichkolwiek węzłów w obszarze projektowania. Podczas opracowywania ogólnego algorytmu należy sprawdzić, które wejścia i wyjścia będą stosowane w skryptach.
Jeśli wykres powinien zawierać pewne opcje lub warunki, szybki dostęp do nich zapewniają ustawienia wstępne.
Ustawienia wstępne pozwalają też ograniczyć złożoność wykresu przez buforowanie określonych wartości suwaków, gdy czas działania wykresu jest długi.
Informacje o korzystaniu z ustawień wstępnych można znaleźć w artykule Zarządzanie danymi przy użyciu ustawień wstępnych.
Użyj węzła niestandardowego, jeśli program można umieścić w pojedynczym kontenerze.
Użyj węzła niestandardowego, jeśli część wykresu będzie często używana ponownie w innych programach.
Użyj węzła niestandardowego, jeśli pewne funkcje mają być udostępniane w społeczności Dynamo.
Umieszczenie całego programu przekształcającego punkty w węźle niestandardowym pozwala uzyskać niezawodny, unikalny i przenośny program, który jest o wiele łatwiejszy do zrozumienia. Odpowiednio nazwane porty wejściowe pomagają użytkownikom w zrozumieniu sposobu użycia węzła. Warto dodać opisy i podać wymagane typy poszczególnych wejść.
Istniejący program punktu przyciągania
Węzeł niestandardowy zawierający ten program — PointGrid
Informacje o korzystaniu z węzłów niestandardowych można znaleźć w artykule Wstęp do węzłów niestandardowych.
Tworząc szablony, można budować standardy graficzne obejmujące wszystkie wykresy. Spójność wizualna ułatwia współpracownikom zrozumienie wykresu.
W ramach szablonu można ustalić standardowe kolory i rozmiary czcionek grup, które ułatwiają klasyfikację typów procesów roboczych i działań na danych.
Tworząc szablon, można nawet określić standardowe etykiety, kolory lub różnice stylów między procesami roboczymi (dostępnymi dla użytkownika) a wewnętrznymi na wykresie.
Interfejs programu (elementy dostępne dla użytkownika) — nazwa projektu, suwaki danych wejściowych i importowana geometria.
Elementy wewnętrzne programu.
Kategorie kolorów grup (projekt ogólny, dane wejściowe, skrypty Python, importowana geometria).
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
Ustaliliśmy kilka wzorców postępowania, które teraz zastosujemy do utworzonego naprędce programu. Choć program poprawnie generuje dach, jego wykres jest równie złożony jak myśli autora. Nie jest w żaden sposób uporządkowany i nie zawiera opisu sposobu użycia. Stosując wzorce postępowania, uporządkujemy, opiszemy i przeanalizujemy ten program, tak aby inni użytkownicy wiedzieli, jak z niego korzystać.
Program działa, ale jego wykres nie jest uporządkowany.
Zaczniemy od określenia, jakie są dane i jaką geometrię zwraca program.
Zrozumienie najważniejszych zmian w danych jest kluczowe w celu ustalenia podziałów logicznych (podziału na moduły). Spróbuj zbadać resztę programu przy użyciu węzłów obserwacyjnych, aby ustalić podział na grupy przed kolejnym krokiem.
Ten węzeł Code Block zawierający równanie matematyczne wygląda na istotny element programu. Węzeł Watch wskazuje, że zwraca on listę odległości przekształcenia.
Przeznaczenie tego obszaru nie jest oczywiste. Rozkład wartości True na poziomie listy L2 uzyskanym z funkcji BoundingBox.Contains oraz użycie funkcji List.FilterByBoolMask wskazują, że próbkujemy część siatki punktów.
Teraz wiemy, co robią podstawowe części programu. Umieścimy je w grupach.
Grupy pomagają użytkownikom wizualnie odróżniać części programu.
Importowanie modelu 3D
Przekształcanie siatki punktów przy użyciu równania sinusoidy
Próbkowanie części siatki punktów
Tworzenie architektonicznej powierzchni dachu
Tworzenie szklanej ściany osłonowej
Po ustaleniu grup rozmieścimy węzły tak, aby wykres zawierał ciągły przepływ działań.
Ciągłość wizualna ułatwia użytkownikowi zrozumienie przepływu programu i domniemanych relacji między węzłami.
Program będzie czytelniejszy, gdy dodamy kolejną warstwę ulepszeń graficznych. Dodaj notatki, aby opisać działanie danej części programu. Nadaj niestandardowe nazwy danym wejściowym. Przypisz kolory różnym typom grup.
Te ulepszenia graficzne powiedzą użytkownikom więcej o działaniu programu. Różne kolory grup ułatwiają odróżnianie danych wejściowych od funkcji.
Notatki
Opisowe nazwy danych wejściowych
Zanim przystąpimy do kondensowania programu, musimy wybrać strategiczną lokalizację, w której zostanie wstawiony skrypt Python symulujący odwadnianie. Podłącz dane wyjściowe pierwszej skalowanej powierzchni dachu do odpowiedniego wejścia skryptu.
Podjęliśmy decyzję, że skrypt zostanie zintegrowany z programem w tym miejscu, tak aby symulację odwadniania było można uruchamiać na oryginalnej, pojedynczej powierzchni dachu. Ta powierzchnia nie jest objęta podglądem, ale dzięki temu nie musimy wybierać górnej powierzchni z fazowanej polipowierzchni.
Geometria źródłowa danych wejściowych skryptu
Węzeł Python
Suwaki danych wejściowych
Przełącznik wł./wył.
Teraz mamy potrzebne informacje, więc możemy uprościć wykres.
Skondensowanie kodu przy użyciu konwersji węzłów na kod i węzłów niestandardowych pozwoliło znacznie zmniejszyć rozmiar wykresu. Grupy generujące powierzchnię dachu i ściany zostały przekonwertowane na kod, ponieważ są specyficzne dla tego programu. Grupa przekształcenia punktów jest zawarta w węźle niestandardowym, gdyż może zostać użyta w innym programie. W pliku przykładowym utwórz własny węzeł niestandardowy z grupy przekształcenia punktów.
Węzeł niestandardowy, który będzie zawierał grupę „Przekształcenie siatki punktów”
Konwersja węzłów na kod w celu skondensowania grup „Tworzenie architektonicznej powierzchni dachu i ściany osłonowej”
W ostatnim kroku utwórz ustawienia wstępne przykładowych form dachu.
Przede wszystkim od tych danych wejściowych zależy forma dachu. Dzięki nim użytkownicy rozumieją potencjał programu.
Nasz program z widokami przy dwóch ustawieniach wstępnych.
Wzory odwodnienia dachu udostępniają użytkownikom widok analityczny poszczególnych ustawień wstępnych.
Skrypty tekstowe opracowywane środowisku wizualnym pozwalają na korzystanie z zaawansowanych, wizualnych powiązań przy użyciu języków DesignScript, Python i ZeroTouch (C#). Można dzięki nim udostępniać elementy takie jak suwaki danych wejściowych, umieszczać całe złożone operacje w skryptach DesignScript, a także korzystać z zaawansowanych narzędzi i bibliotek Python oraz C# — wszystko to w tym samym obszarze roboczym. Efektywne stosowanie tych strategii umożliwia dostosowywanie, poprawianie czytelności i zwiększanie wydajności programu. Poniżej zebrano wskazówki, które pomagają w pracy nad skryptami wizualnymi i tekstowymi.
Skrypty tekstowe pozwalają tworzyć relacje o wyższej złożoności niż programowanie wizualne, choć obie techniki mają wiele podobnych funkcji. Dzieje się tak, ponieważ węzły to w praktyce wstępnie spakowany kod. Prawdopodobnie można napisać cały program Dynamo w języku DesignScript lub Python. Stosujemy jednak skrypty wizualne, ponieważ interfejs oparty na węzłach i połączeniach między nimi pozwala w intuicyjny, graficzny sposób prezentować przepływ informacji. Wiedza o tym, kiedy skrypty tekstowe dają więcej możliwości niż wizualne, jest bardzo przydatna — ułatwia podjęcie decyzji, czy warto zrezygnować z intuicyjnej wizualizacji połączonych węzłów. Poniższe wskazówki pomagają określić, kiedy użyć skryptu i który język wybrać.
Zastosowania skryptów tekstowych:
Pętle
Rekursja
Dostęp do bibliotek zewnętrznych
Wybór języka:
Materiały referencyjne dotyczące skryptów zawierają listę funkcji wszystkich bibliotek dodatku Dynamo.
Podczas tworzenia skryptów w dodatku Dynamo, który jako środowisko jest oparty na parametrach, warto stosować konstrukcje kodu dostosowane do platformy węzłów i połączeń, na której kod będzie działać. Węzeł zawierający skrypt tekstowy należy traktować jako każdy inny węzeł programu — obiekt zawierający określone wejścia, funkcję i oczekiwane dane wyjściowe. W ten sposób kod znajdujący się w węźle od początku zawiera kilka zmiennych, które może przetwarzać. Tak powstaje czysty system parametryczny. Poniższe wskazówki ułatwiają integrację kodu z programem wizualnym.
Identyfikacja zmiennych zewnętrznych:
Postaraj się określić parametry związane z danym problemem projektowym, aby utworzyć model bezpośrednio oparty na tych danych.
Zanim napiszesz kod, zidentyfikuj te zmienne:
Minimalny zestaw danych wejściowych
Zamierzone dane wyjściowe
Stałe
Wiele zmiennych jest znanych przed przystąpieniem do pisania kodu.
Powierzchnia, na której będziemy symulować opady deszczu.
Żądana liczba kropli deszczu (agentów).
Odległość, jaką mają przebywać krople deszczu.
Przełącznik między zejściem najbardziej stromą ścieżką a trawersem po powierzchni.
Węzeł Python zawierający odpowiednią liczbę wejść.
Blok kodu powodujący, że zwracane krzywe są niebieskie.
Projektowanie relacji wewnętrznych:
Parametry (zmienne) można edytować, aby zmienić te informacje lub wynik równania albo dane wyjściowe systemu.
Gdy elementy skryptu mają związek logiczny, warto zdefiniować je jako wzajemnie zależne funkcje. Dzięki temu modyfikacja jednego elementu spowoduje proporcjonalną aktualizację drugiego.
Należy ograniczyć liczbę wejść, udostępniając tylko najważniejsze parametry:
Jeśli zestaw parametrów można obliczyć na podstawie innych parametrów nadrzędnych, wystarczy udostępnić same parametry nadrzędne jako wejścia skryptu. Ułatwia to korzystanie ze skryptu, gdyż upraszcza jego interfejs.
„Moduły” kodu z przykładu w artykule Węzeł Python.
Wejścia.
Zmienne wewnętrzne skryptu.
Pętla realizująca funkcję skryptu przy użyciu tych danych i zmiennych.
Wskazówka: warto zająć się całym procesem równie uważnie jak samym rozwiązaniem.
Gdy ten sam proces można opisać w skrypcie na różne sposoby, powielone reprezentacje z czasem zaczynają się różnić, co może znacznie utrudnić konserwację i analizę kodu, a nawet doprowadzić do jego wewnętrznej sprzeczności.
Reguła DRY („don't repeat yourself" — nie powtarzaj się) zaleca, aby każdy element informacji miał w systemie pojedynczą, jednoznaczną i ustaloną reprezentację:
Poprawne stosowanie tej reguły powoduje, że wszystkie powiązane elementy skryptu zmieniają się w przewidywalny, spójny sposób, a między niepowiązanymi elementami nie powstają żadne relacje logiczne.
Wskazówka: zanim powielisz elementy skryptu (na przykład stałą w powyższym przykładzie), zastanów się, czy można zamiast tego użyć połączenia z elementem źródłowym.
Z czasem kod staje się dłuższy i bardziej złożony, a jego ogólny zarys (główny algorytm) — nieczytelny. Coraz trudniej jest też sprawdzać, co i gdzie się dzieje, wykrywać błędy, integrować inny kod czy przypisywać zadania programistyczne. Aby uniknąć tych problemów, zalecane jest pisanie kodu w modułach. Taka strategia porządkowania polega na rozdzielaniu kodu na części wykonujące różne zadania. Poniżej przedstawiono wskazówki ułatwiające zarządzanie kodem przez stosowanie modułów.
Pisanie kodu w modułach:
Moduł jest to zgrupowany kod wykonujący określone zadanie, analogicznie do węzła Dynamo w przestrzeni roboczej.
Może to obejmować wszelkie zadania, które powinny być wizualnie oddzielone od sąsiadującego kodu (funkcje, klasy, grupy danych wejściowych czy importowane biblioteki).
Pisanie kodu w modułach pozwala korzystać z intuicyjnego, wizualnego mechanizmu węzłów, a jednocześnie uzyskiwać złożone relacje dostępne tylko za pośrednictwem skryptów.
Te pętle wywołują klasę o nazwie „agent”, którą zaprogramujemy w ramach ćwiczenia.
Moduł kodu definiujący punkt początkowy każdego agenta.
Moduł kodu aktualizujący agenta.
Moduł kodu rysujący ślad do ścieżki dla agenta.
Rozpoznawanie możliwości ponownego użycia kodu:
Jeśli okaże się, że kod wykonuje te same (lub bardzo podobne) działania w kilku miejscach, warto zebrać go w funkcję, którą będzie można wywoływać.
Funkcje zarządzające sterują przepływem programu i zawierają przede wszystkim wywołania funkcji roboczych, które wykonują zadania niskiego poziomu, takie jak przenoszenie danych między konstrukcjami.
Ten przykładowy kod tworzy kule o promieniach i kolorach zależnych od wartości Z punktów środkowych.
Zawiera dwie nadrzędne robocze funkcje: jedną tworzącą kule o zadanych promieniach i jedną wyświetlającą kolory zależnie od wartości Z punktów środkowych.
Nadrzędna funkcja zarządzająca łączy obie funkcje robocze. Jej wywołanie powoduje wywołanie obu zawartych w niej funkcji.
Wyświetlanie tylko tego, co powinno być widoczne:
Interfejs modułu określa, jakie elementy są podawane i wymagane przez moduł.
Po zdefiniowaniu interfejsów między jednostkami można oddzielnie pracować nad szczegółowym projektem każdej jednostki.
Rozdzielność i możliwość zastąpienia:
Moduły nie wiedzą nic o innych i nie zależą od nich.
Ogólne sposoby podziału na moduły:
Grupowanie kodu:
Funkcje:
Klasy:
Podczas pracy nad skryptami tekstowymi w dodatku Dynamo warto w sposób ciągły sprawdzać, czy tworzony kod odpowiada oczekiwaniom. Dzięki temu nieprzewidziane problemy, takie jak błędy składni, niezgodności logiczne, niedokładne wartości czy nieprawidłowe dane wyjściowe, są szybko wykrywane i rozwiązywane — nie pozostają ukryte do samego końca pracy. Skrypty tekstowe istnieją w węzłach na obszarze projektowania, dlatego są już zintegrowane z przepływem danym programu wizualnego. Ułatwia to ciągłe monitorowanie skryptu. Wystarczy przypisać mu oczekiwane dane wyjściowe, uruchomić program i sprawdzić wyjście skryptu przy użyciu węzła obserwacyjnego (Watch). Poniższe wskazówki ułatwiają badanie skryptów podczas ich tworzenia.
Ciągłe testowanie:
Zawsze po ukończeniu pracy nad grupą funkcji:
Sprawdź ogólny zarys kodu.
Przemyśl to krytycznie. Czy współpracownik zrozumie, co ten kod robi? Czy ten kod jest potrzebny? Czy tę funkcję można wykonać wydajniej? Czy powstają niepotrzebne duplikaty lub zależności?
Wykonaj krótki test, aby sprawdzić, czy zwracane dane mają sens.
Przypisz dane, które ostatnio przetwarzał skrypt, jako wyjściowe, tak aby węzeł zawsze generował odpowiednie dane w razie aktualizacji skryptu:
Sprawdź, czy wszystkie krawędzie bryły są zwracane jako krzywe do tworzenia ramki ograniczającej.
Sprawdź, czy liczniki wejściowe są prawidłowo konwertowane na zakresy.
Sprawdź, czy układ współrzędnych został poprawnie przeniesiony i obrócony w tej pętli.
Przewidywanie przypadków brzegowych:
Podczas pracy nad skryptem podaj minimalne i maksymalne wartości danych wejściowych (leżące w ich domenie), aby sprawdzić, czy program nadal działa w warunkach ekstremalnych.
Nawet jeśli program działa w takiej sytuacji, sprawdź czy zwraca niezamierzone wartości null, puste lub zero.
Czasami tylko przypadki brzegowe pozwalają wykryć błędy wskazujące na ukryty problem w skrypcie.
Po zbadaniu, co wywołało błąd, można zdecydować, czy należy rozwiązać go wewnętrznie, czy trzeba zmienić definicję domeny parametrów w celu jego uniknięcia.
Wskazówka: zawsze należy zakładać, że użytkownik użyje wszystkich kombinacji wszystkich wartości wejściowych, do których ma dostęp. Zapobiega to przykrym niespodziankom.
Debugowanie jest to proces usuwania błędów ze skryptu. Oprócz oczywistych błędów obejmuje to problemy z wydajnością i dokładnością, a także wszelkie niezamierzone skutki działania skryptu. Czasami usunięcie błędu wymaga tylko poprawienia pisowni nazwy zmiennej, ale niekiedy trzeba zmienić całą strukturę skryptu. W sytuacji idealnej ciągłe sprawdzanie skryptu podczas pracy nad nim pozwala wcześnie wykrywać problemy. Nie daje to jednak gwarancji braku błędów. Poniżej omówiono szereg z powyższych wzorców postępowania w sposób ułatwiający systematyczne usuwanie błędów.
Używanie podglądu:
Warto sprawdzać dane zwracane w różnych miejscach kodu, przypisując je do zmiennej wyjściowej (w sposób podobny do sprawdzania możliwości programu).
Pisanie zrozumiałych komentarzy:
Debugowanie modułu kodu jest o wiele łatwiejsze, gdy jasno opisano jego zamierzony wynik.
W normalnej sytuacji generuje to nadmiar komentarzy i pustych wierszy, ale podczas debugowania warto podzielić algorytm na łatwe w obsłudze fragmenty.
Wykorzystanie kodu modułowego:
Jako źródło problemu można wskazać określone moduły.
Po wykryciu wadliwego modułu rozwiązanie problemu staje się o wiele prostsze.
Gdy trzeba zmodyfikować program, można łatwiej zmienić kod umieszczony w modułach:
Nowe lub debugowane moduły można wstawić do istniejącego programu bez ryzyka modyfikacji reszty programu.
Debugowanie przykładowego pliku z artykułu Węzeł Python.
Geometria wejściowa zwraca ramkę ograniczającą większą niż ta geometria, co widać po przypisaniu zmiennych xDist i yDist jako wyjściowych.
Krzywe krawędzi geometrii wejściowej zwracają prawidłową ramkę ograniczającą z poprawnymi odległościami xDist i yDist.
Moduł kodu wstawiony w celu rozwiązania problemu z wartościami xDist i yDist.
Pobierz plik przykładowy, klikając poniższe łącze.
Pełna lista plików przykładowych znajduje się w załączniku.
Pamiętając o wzorcach postępowania pisania skryptów tekstowych, napiszemy skrypt symulujący deszcz. Zastosowaliśmy wzorce postępowania do zdezorganizowanego programu w ramach strategii dotyczących wykresu, ale praca nad skryptami tekstowymi jest trudniejsza. Relacje logiczne zdefiniowane w skryptach tekstowych nie są tak widoczne i często są ściśle powiązane ze skomplikowanym kodem. Skrypty tekstowe oferują zaawansowane możliwości, ale wymagają też więcej uwagi w organizacji. Przyjrzymy się wszystkim krokom i zastosujemy do nich wzorce postępowania.
Nasz skrypt wprowadził powierzchnię zdeformowaną przy użyciu punktu przyciągania.
Na samym początku musimy zaimportować wymagane biblioteki dodatku Dynamo. Zapewni to globalny dostęp do funkcji dodatku Dynamo w kodzie Python.
Tutaj należy zaimportować wszystkie biblioteki, których zamierzamy użyć.
Następnie musimy zdefiniować dane wejściowe i wyjściowe skryptu, które będą widoczne jako porty wejściowe węzła. Na tych zewnętrznych danych wejściowych opiera się nasz skrypt. Dzięki nim tworzymy środowisko parametryczne.
Musimy zdefiniować dane wejściowe odpowiadające zmiennym skryptu Python i określić oczekiwane dane wyjściowe:
Powierzchnia, po której chcemy wykonać zejście.
Liczba poruszających się agentów.
Maksymalna liczba kroków, jakie mogą wykonać agenty.
Przełącznik przejścia najkrótszą ścieżką w dół powierzchni lub jej trawersowania.
Identyfikatory wejść węzła Python odpowiadające danym wejściowym skryptu (IN[0], IN[1]).
Krzywe wyjściowe, które można wyświetlić w innym kolorze.
Teraz zastosujemy metodę modularności i utworzymy treść skryptu. Symulowanie najkrótszej ścieżki w dół powierzchni z wielu punktów początkowych to złożone zadanie, które będzie wymagało wielu funkcji. Zamiast wywoływać różne funkcje w całym skrypcie, możemy podzielić kod na moduły — zebrać je w jednej klasie, naszym agencie. Poszczególne funkcje tej klasy (modułu) można wywoływać z różnymi zmiennymi. Można też użyć ich ponownie w innym skrypcie.
Musimy zdefiniować klasę, która stanowi schemat agenta mającego przechodzić po powierzchni, przy każdym kroku wybierając najbardziej stromy kierunek:
Nazwa.
Atrybuty globalne, które mają wszystkie agenty.
Atrybuty wystąpienia, które są unikalne dla każdego agenta.
Funkcja wykonywania kroku.
Funkcja katalogowania położenia każdego kroku na liście śladów.
Zainicjujemy agenty, definiując ich położenie początkowe. Teraz warto sprawdzić skrypt i upewnić się, że klasa agenta działa.
Musimy utworzyć wystąpienia wszystkich agentów, które chcemy obserwować na ich drodze w dół powierzchni, a także zdefiniować ich atrybuty początkowe:
Nowa, pusta lista śladów.
Miejsce rozpoczęcia przemieszczania na powierzchni.
Przypisaliśmy listę agentów jako wyjście, aby sprawdzić, co skrypt zwraca w tym miejscu. Jest zwracana prawidłowa liczba agentów, ale musimy jeszcze raz sprawdzić skrypt później, aby zweryfikować zwracaną geometrię.
Aktualizowanie każdego agenta przy każdym kroku. Następnie musimy wprowadzić pętlę zagnieżdżoną, która dla każdego agenta przy każdym kroku aktualizuje i rejestruje jego położenie na liście śladów. Na każdym kroku musimy też upewnić się, że agent nie osiągnął punktu powierzchni, z którego nie może wykonać następnego kroku w dół. Jeśli ten warunek jest spełniony, kończymy podróż agenta.
Teraz nasze agenty są w pełni zaktualizowane. Zwrócimy reprezentującą je geometrię. Gdy wszystkie agenty osiągną limit podróży w dół lub maksymalną liczbę kroków, utworzymy krzywą złożoną łączącą wszystkie punkty na ich liście śladów i wygenerujemy wyjście zawierające ślady krzywych złożonych.
Nasz skrypt wykrywający najbardziej strome ścieżki.
Ustawienie wstępne symulujące padanie deszczu na oryginalną powierzchnię.
Zamiast wykrywania najbardziej stromej ścieżki, agenty można przełączyć w tryb trawersowania powierzchni.
Cały skrypt tekstowy Python.
Pętle
Rekursja
Kondensowanie węzłów
Biblioteki zewnętrzne
Krótka składnia
DesignScript
Tak
Tak
Tak
Nie
Tak
Python
Tak
Tak
Częściowo
Tak
Nie
ZeroTouch (C#)
Nie
Nie
Nie
Tak
Nie