arrow-left

All pages
gitbookPowered by GitBook
1 of 22

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Codierung in Dynamo

Dynamo ist eine hervorragende Möglichkeit, um mit der Programmierung für den AEC-Bereich zu beginnen. Sie sind vielleicht an einigen dieser Abschnitte interessiert, um selbst mit dem Coding zu beginnen:

  • Codeblöcke und DesignScript

  • Geometrie mit DesignScript

Python

​Python ist eine häufig verwendete Programmiersprache, die sich aufgrund ihrer Syntax großer Beliebtheit erfreut. Sie ist leicht zu lesen und damit leichter zu erlernen als viele andere Sprachen. Python unterstützt Module und Pakete und kann in bestehende Anwendungen eingebettet werden. Eine geeignete Ressource für den Einstieg in Python finden Sie auf der Seite Getting Startedarrow-up-right auf Python.orgarrow-up-right.

Python

Was ist ein Codeblock?

Codeblöcke geben Zugang zu DesignScript, der Programmiersprache, die Dynamo zugrunde liegt. DesignScript ist eine völlig neu entwickelte, leicht lesbare und knappe Programmiersprache speziell für experimentelle Arbeitsabläufe, die sowohl sofortiges Feedback für kleine Codeabschnitte als auch Skalierungsmöglichkeiten für umfangreiche und komplexe Interaktionen bietet. DesignScript ist zugleich das Kernstück der Engine, die die meisten Funktionen von Dynamo "hinter den Kulissen" steuert. Für fast jede Funktion in Dynamo-Blöcken und -Interaktionen ist eine entsprechende Funktion in der Skriptsprache vorhanden. Aus diesem Grund stehen einzigartige Möglichkeiten für einen nahtlosen Übergang zwischen Block-Interaktionen und Skripterstellung zur Verfügung.

Blöcke können automatisch in Textsyntax konvertiert werden, etwa um Anfängern den Einstieg in DesignScript zu erleichtern oder um ganz einfach größere Abschnitte eines Diagramms auf kleinerem Raum zusammenzufassen. Hierfür steht die Funktion Block zu Code zur Verfügung, die im Abschnitt DesignScript-Syntax genauer beschrieben wird. Benutzer mit umfassender Erfahrung können in Codeblöcken unter Verwendung vieler Standardparadigmen der Codeerstellung benutzerdefinierte Mashups bestehender Funktionen sowie eigene Beziehungen erstellen. Benutzer, die über einige Erfahrung verfügen, aber keine Experten sind, finden zahlreiche Shortcuts und Codeabschnitte, mit deren Hilfe sie schneller an ihren Entwürfen arbeiten können. Der Begriff "Codeblock" mag zwar für Benutzer ohne Programmierkenntnisse etwas zu fachspezifisch wirken, die Codeblöcke selbst sind jedoch benutzerfreundlich und robust. Für den Einstieg können Codeblöcke mit einem Minimum an Codeerstellung effizient eingesetzt werden, während Benutzer mit fortgeschrittenen Kenntnissen Skriptdefinitionen definieren und gegebenenfalls an anderer Stelle in einer Dynamo-Definition erneut aufrufen können.

hashtag
Codeblock: Ein kurzer Überblick

Codeblöcke sind, kurz zusammengefasst, eine Oberfläche für Textskripts innerhalb einer Umgebung für visuelles Skripting. Sie können für Zahlen, Zeichenfolgen, Formeln und andere Datentypen verwendet werden. Die Codeblock-Funktion wurde für Dynamo entwickelt. Sie können daher beliebige Variable im Codeblock definieren, die anschließend automatisch den Eingaben des Blocks hinzugefügt werden:

Bei Codeblöcken kann der Benutzer flexibel entscheiden, wie die Eingaben festgelegt werden sollen. Die folgenden Abbildungen zeigen verschiedene Möglichkeiten zum Erstellen eines einfachen Punkts mit den Koordinaten (10, 5, 0):

Während Sie weitere Funktionen aus der Bibliothek kennenlernen, erweist sich eventuell die Eingabe von "Point.ByCoordinates" als leichter und schneller als die Suche nach dem passenden Block in der Bibliothek. Wenn Sie beispielsweise Point. eingeben, zeigt Dynamo eine Liste möglicher Funktionen an, die für Punkte angewendet werden können. Dadurch gestaltet sich die Skripterstellung intuitiver und die Anwendung von Funktionen in Dynamo ist leichter zu erlernen.

hashtag
Erstellen von Codeblock-Blöcken

Der Codeblock befindet sich unter Core > Input > Actions > Code Block. Sie können den Codeblock jedoch auch wesentlich schneller durch einfaches Doppelklicken im Ansichtsbereich aufrufen. Dieser Block wird so häufig verwendet, dass ihm uneingeschränkte Doppelklickfunktionen zugewiesen wurden.

hashtag
Zahlen, Zeichenfolgen und Formeln

Codeblöcke können auch flexibel für unterschiedliche Datentypen eingesetzt werden. Die Benutzer können rasch Zahlen, Zeichenfolgen und Formeln definieren und der Codeblock liefert die gewünschte Ausgabe.

Die folgende Abbildung zeigt, dass der "herkömmliche" Ablauf für diese Angaben etwas umständlich ist: Der Benutzer sucht in der Benutzeroberfläche nach dem gewünschten Block, fügt diesen im Ansichtsbereich hinzu und gibt die Daten ein. Einen Codeblock hingegen kann der Benutzer durch Doppelklicken im Ansichtsbereich aufrufen, um anschließend den benötigten Datentyp in der entsprechenden Syntax einzugeben.

Die Nummern- und Zeichenfolgenblöcke sind zwei Beispiele für Dynamo-Blöcke, die im Vergleich zum Codeblock als veraltet betrachtet werden könnten.

  1. Traditionell

  2. Codeblöcke

Codeblöcke und DesignScript

Codeblöcke sind eine spezielle Funktion in Dynamo, die eine dynamische Verbindung zwischen visueller und textbasierter Programmierumgebung darstellt. In einem Codeblock haben Sie Zugriff auf sämtliche Dynamo-Blöcke und können ein komplettes Diagramm in einem einzigen Block definieren. Lesen Sie die Informationen in diesem Kapitel sorgfältig, da Codeblöcke zu den wichtigsten Komponenten von Dynamo gehören.

DesignScript-Geometriegrundlagen

hashtag
Punkt

Das einfachste geometrische Objekt in der Dynamo-Bibliothek für Standardgeometrie ist ein Punkt. Jegliche Geometrie wird mit speziellen Funktionen namens Konstruktoren erstellt, die jeweils ein neues Exemplar dieses bestimmten Geometrietyps zurückgeben. In Dynamo beginnen Konstruktoren mit dem Namen des Objekttyps, in diesem Fall Point, gefolgt von der Konstruktionsmethode. Zum Erstellen eines dreidimensionalen Punkts, der durch die kartesischen Koordinaten x, y und z angegeben wird, verwenden Sie den Konstruktor ByCoordinates:

Konstruktoren in Dynamo sind normalerweise mit dem Präfix By

Geometrie mit DesignScript

In diesem Abschnitt finden Sie eine Reihe von Lektionen zur Geometrieerstellung mit DesignScript. Machen Sie mit, indem Sie die DesignScript-Beispiele in Dynamo-Codeblöcke kopieren.

// copy this code into a Code Block
// to start writing DesignScript

x = "Let's create some geometry!";
gekennzeichnet, und wenn Sie diese Funktionen aufrufen, geben sie ein neu erstelltes Objekt des betreffenden Typs zurück. Dieses neu erstellte Objekt wird in der Variablen mit dem Namen gespeichert, der links vom Gleichheitszeichen steht.

Die meisten Objekte verfügen über viele verschiedene Konstruktoren, und mit dem Konstruktor BySphericalCoordinates können wir einen Punkt erstellen, der auf einer Kugel liegt und durch den Radius der Kugel, einen ersten Drehwinkel sowie einen zweiten Drehwinkel (in Grad) angegeben wird:

hashtag
Von Punkt zu Linie

Punkte können verwendet werden, um höherdimensionale Geometrien wie z. B. Linien zu erstellen. Mit dem Konstruktor ByStartPointEndPoint können wir ein Linienobjekt zwischen zwei Punkten erstellen:

hashtag
Von Linie zu Oberfläche

In ähnlicher Weise können mit Linien wiederum höherdimensionale Oberflächengeometrien erstellt werden, beispielsweise mit dem Konstruktor Loft, der aus einer Reihe von Linien oder Kurven eine Oberfläche zwischen diesen interpoliert.

hashtag
Von Oberfläche zu Volumenkörper

Auch Oberflächen können zum Erstellen höherdimensionaler Volumenkörper-Geometrien genutzt werden, zum Beispiel durch Verdicken der Oberfläche um einen gegebenen Abstand. Vielen Objekten sind Funktionen zugewiesen, die Methoden genannt werden, und mit denen Programmierer Befehle für das jeweilige Objekt ausführen können. Methoden, die allen Geometrien gemein sind, sind z. B. Translate und Rotate, die die Geometrie um einen bestimmten Wert verschieben oder drehen. Oberflächen haben eine Methode namens Thicken, die einen einzelnen Eingabewert (Nummer) akzeptiert, der die neue Dicke der Oberfläche angibt.

hashtag
Schneiden

Mit den Intersection-Befehlen können niedrigerdimensionale Geometrien aus höherdimensionalen Objekten extrahiert werden. Diese extrahierte niedrigerdimensionale Geometrie kann als Grundlage für eine höherdimensionale Geometrie in einem zyklischen Prozess des geometrischen Erstellens, Extrahierens und erneuten Erstellens dienen. In diesem Beispiel verwenden wir den generierten Volumenkörper, um eine Oberfläche zu erstellen, und nutzen anschließend die Oberfläche, um eine Kurve zu erstellen.

// create a point with the following x, y, and z
// coordinates:
x = 10;
y = 2.5;
z = -6;

p = Point.ByCoordinates(x, y, z);
// create a point on a sphere with the following radius,
// theta, and phi rotation angles (specified in degrees)
radius = 5;
theta = 75.5;
phi = 120.3;
cs = CoordinateSystem.Identity();

p = Point.BySphericalCoordinates(cs, radius, theta,
    phi);
// create two points:
p1 = Point.ByCoordinates(3, 10, 2);
p2 = Point.ByCoordinates(-15, 7, 0.5);

// construct a line between p1 and p2
l = Line.ByStartPointEndPoint(p1, p2);
// create points:
p1 = Point.ByCoordinates(3, 10, 2);
p2 = Point.ByCoordinates(-15, 7, 0.5);

p3 = Point.ByCoordinates(5, -3, 5);
p4 = Point.ByCoordinates(-5, -6, 2);

p5 = Point.ByCoordinates(9, -10, -2);
p6 = Point.ByCoordinates(-11, -12, -4);

// create lines:
l1 = Line.ByStartPointEndPoint(p1, p2);
l2 = Line.ByStartPointEndPoint(p3, p4);
l3 = Line.ByStartPointEndPoint(p5, p6);

// loft between cross section lines:
surf = Surface.ByLoft([l1, l2, l3]);
p1 = Point.ByCoordinates(3, 10, 2);
p2 = Point.ByCoordinates(-15, 7, 0.5);

p3 = Point.ByCoordinates(5, -3, 5);
p4 = Point.ByCoordinates(-5, -6, 2);

l1 = Line.ByStartPointEndPoint(p1, p2);
l2 = Line.ByStartPointEndPoint(p3, p4);

surf = Surface.ByLoft([l1, l2]);

// true indicates to thicken both sides of the Surface:
solid = surf.Thicken(4.75, true);
p1 = Point.ByCoordinates(3, 10, 2);
p2 = Point.ByCoordinates(-15, 7, 0.5);

p3 = Point.ByCoordinates(5, -3, 5);
p4 = Point.ByCoordinates(-5, -6, 2);

l1 = Line.ByStartPointEndPoint(p1, p2);
l2 = Line.ByStartPointEndPoint(p3, p4);

surf = Surface.ByLoft([l1, l2]);

solid = surf.Thicken(4.75, true);

p = Plane.ByOriginNormal(Point.ByCoordinates(2, 0, 0),
    Vector.ByCoordinates(1, 1, 1));

int_surf = solid.Intersect(p);

int_line = int_surf.Intersect(Plane.ByOriginNormal(
    Point.ByCoordinates(0, 0, 0),
    Vector.ByCoordinates(1, 0, 0)));

Kurzschreibweisen

hashtag
Kurzschreibweisen

Für Codeblöcke stehen einige einfache Kurzschreibweisen zur Verfügung, die, einfach ausgedrückt, die Arbeit mit den Daten erheblich erleichtern. Im Folgenden werden die Grundlagen genauer erläutert und beschrieben, wie die jeweilige Kurzschreibweise zum Erstellen und Abfragen von Daten verwendet werden kann.

Datentyp

Dynamo-Standarddarstellung

Codeblock-Entsprechung

hashtag
Zusätzliche Syntax

hashtag
Bereiche und Folgen

Die Methoden zum Definieren von Bereichen und Sequenzen können in einfachen Kurzschreibweisen ausgedrückt werden. Die folgende Abbildung bietet eine Anleitung zum Definieren einer Liste mit numerischen Daten mithilfe der Syntax ".." in Codeblöcken. Nachdem Sie sich mit dieser Notation vertraut gemacht haben, können Sie numerische Daten äußerst effizient erstellen:

  1. In diesem Beispiel wird ein Zahlenbereich durch einfache Codeblock-Syntax mit Angaben für beginning..end..step-size; ersetzt. In numerischer Darstellung erhalten wir die Werte: 0..10..1;

  2. Beachten Sie, dass die Syntax 0..10..1; der Syntax 0..10; entspricht. Die Schrittgröße 1 ist der Vorgabewert für die Kurzschreibweise. Mit 0..10;

hashtag
Erweiterte Bereiche

Indem Sie erweiterte Bereiche erstellen, können Sie auf einfache Weise mit Listen von Listen arbeiten. In den Beispielen unten wird eine Variable aus der Darstellung der primären Liste isoliert und ein weiterer Bereich aus dieser Liste erstellt.

1. Vergleichen Sie die Notation mit und ohne #-Zeichen bei der Erstellung verschachtelter Bereiche. Dabei gilt dieselbe Logik wie bei einfachen Bereichen, die Angaben sind jedoch etwas komplexer.

2. Sie können an beliebiger Stelle des primären Bereichs einen Unterbereich erstellen. Es ist auch möglich, zwei Unterbereiche zu verwenden.

3. Mithilfe des Werts für end in einem Bereich erstellen Sie weitere Bereiche unterschiedlicher Länge.

Vergleichen Sie als Übung zu dieser Logik die beiden oben gezeigten Kurzschreibweisen und testen Sie, wie Unterbereiche und das #-Zeichen sich auf das Ergebnis auswirken.

hashtag
Erstellen von Listen und Abrufen von Einträgen aus Listen

Sie können Listen nicht nur mithilfe von Kurzschreibweisen, sondern auch ad hoc erstellen. Solche Listen können eine Vielfalt von Elementtypen enthalten und können abgefragt werden (da Listen ihrerseits Objekte sind). Kurz zusammengefasst: Mit einem Codeblock erstellen Sie Listen, und zum Abfragen der Listen verwenden Sie eckige Klammern:

1. Sie können Listen schnell aus Zeichenfolgen erstellen und über die Indizes der Einträge abfragen.

2. Sie können Listen mit Variablen erstellen und sie über die Kurzschreibweisen für Bereiche abfragen.

Verschachtelte Listen werden auf ähnliche Weise verwaltet. Beachten Sie dabei die Reihenfolge der Listen und verwenden Sie mehrere Paare eckiger Klammern:

1. Definieren Sie eine Liste von Listen.

2. Fragen Sie eine Liste mit einer Angabe in eckigen Klammern ab.

3. Fragen Sie einen Eintrag mit zwei Angaben in eckigen Klammern ab.

hashtag
Übung: Sinusoberfläche

Laden Sie die Beispieldatei herunter, indem Sie auf den folgenden Link klicken.

Eine vollständige Liste der Beispieldateien finden Sie im Anhang.

In dieser Übung wenden Sie Ihre Kenntnisse der Kurzschreibweise an und erstellen eine originelle gewölbte Oberfläche, die Sie mithilfe von Bereichen und Formeln definieren. Beachten Sie in dieser Übung, wie Codeblöcke und bestehende Dynamo-Blöcke zusammenwirken: Für umfangreiche Datenverarbeitungen kommen Codeblöcke zum Einsatz, durch die visuelle Darstellung der Dynamo-Blöcke ist die Definition leichter zu lesen.

Erstellen Sie zunächst eine Oberfläche, indem Sie die oben gezeigten Blöcke verbinden. Verwenden Sie zum Definieren der Breite und Länge keinen Number-Block, sondern doppelklicken Sie in den Ansichtsbereich und geben Sie den Wert 100; in einen Codeblock ein.

  1. Definieren Sie einen Bereich zwischen 0 und 1 mit 50 Unterteilungen, indem Sie 0..1..#50 in einen Codeblock eingeben.

  2. Verbinden Sie den Bereich mit Surface.PointAtParameter. Dieser Block benötigt u- und v-Werte zwischen 0 und 1 für die gesamte Oberfläche. Sie müssen die Vergitterung in Kreuzprodukt ändern. Klicken Sie dazu mit der rechten Maustaste auf den Surface.PointAtParameter-Block.

In diesem Schritt verschieben Sie das Raster aus Punkten mithilfe der ersten Funktion in z-Richtung nach oben. Dieses Raster steuert die zu erstellende Oberfläche anhand der zugrunde liegenden Funktion. Fügen Sie neue Blöcke hinzu, wie in der folgenden Abbildung gezeigt.

  1. Wir verwenden einen Codeblock mit folgender Zeile: (0..Math.Sin(x*360)..#50)*5;. Dadurch definieren Sie, kurz zusammengefasst, einen Bereich, der eine Formel enthält. Diese Formel ist die Sinusfunktion. Da für die Sinusfunktion in Dynamo Werte in Grad eingegeben werden müssen, multiplizieren Sie die x-Werte (d. h. den eingegebenen Bereich zwischen 0 und 1) mit 360, um eine vollständige Sinuskurve zu erhalten. Als Nächstes wird dieselbe Anzahl Unterteilungen als Rastersteuerpunkte für die einzelnen Reihen benötigt. Definieren Sie daher 50 Unterteilungen mit #50. Der Multiplikator 5 schließlich verstärkt die Verschiebung, sodass deren Wirkung in der Dynamo-Vorschau deutlich zu sehen ist.

  1. Der zuvor verwendete Codeblock erfüllte seine Funktion, war jedoch nicht vollständig parametrisch. Die Parameter sollen dynamisch gesteuert werden. Ersetzen Sie daher die Zeile aus dem vorherigen Schritt durch (0..Math.Sin(x*360*cycles)..#List.Count(x))*amp;. Dadurch erhalten Sie die Möglichkeit, diese Werte anhand Ihrer Eingaben zu definieren.

Indem Sie die Werte der Schieberegler (zwischen 0 und 10) ändern, erhalten Sie interessante Ergebnisse.

  1. Indem Sie Transpose auf den Zahlenbereich anwenden, kehren Sie die Richtung der Wellen um: transposeList = List.Transpose(sineList);

  1. Durch Addieren von sineList und tranposeList erhalten Sie eine verzerrte Hülle: eggShellList = sineList+transposeList;

Ändern Sie die unten angegebenen Schiebereglerwerte, um den Algorithmus etwas ausgeglichener zu gestalten.

In dieser letzten Übung fragen wir isolierte Teile der Daten mithilfe eines Codeblocks ab. Fügen Sie den oben gezeigten Codeblock zwischen dem Geometry.Translate- und dem NurbsSurface.ByPoints-Block ein, um die Oberfläche aus einem bestimmten Bereich von Punkten neu zu erstellen. Der Codeblock enthält die folgende Textzeile: sineStrips[0..15..1];. Dadurch werden die ersten 16 (von 50) Punktreihen ausgewählt. Wenn die Oberfläche neu erstellt wird, ist zu erkennen, dass ein isolierter Teil des Punktrasters generiert wurde.

  1. Im letzten Schritt erweitern Sie den Codeblock um parametrische Funktionen, indem Sie einen Schieberegler mit dem Bereich von 0 bis 1 zur Steuerung der Abfrage verwenden. Dies geschieht mit der folgenden Codezeile: sineStrips[0..((List.Count(sineStrips)-1)*u)];. Dies mag etwas verwirrend wirken. Diese Codezeile ermöglicht jedoch eine schnelle Skalierung der Länge der Liste über einen Multiplikator zwischen 0 und 1.

Mithilfe des Werts 0.53 im Schieberegler erstellen Sie eine Oberfläche, die sich knapp über die Mitte des Rasters hinaus erstreckt.

Mit dem Wert 1 im Schieberegler wird erwartungsgemäß eine Oberfläche aus dem gesamten Punktraster erstellt.

Im visuellen Diagramm können Sie die einzelnen Codeblöcke markieren und ihre Funktionen sehen.

1. Der erste Codeblock ersetzt den Number-Block.

2. Der zweite Codeblock ersetzt den Number Range-Block.

3. Der dritte Codeblock ersetzt die Blöcke List.Transpose, List.Count und Number Range.

4. Der vierte Codeblock ruft eine Liste von Listen ab und ersetzt den List.GetItemAtIndex-Block.

Einrichten einer eigenen Python-Vorlage

In Dynamo 2.0 haben Sie die Möglichkeit eine Standardvorlage (.py extension) festzulegen, die verwendet wird, wenn Sie das Python-Fenster zum ersten Mal öffnen. Entwickler haben sich diese Funktion schon lange gewünscht, da sie die Verwendung von Python innerhalb von Dynamo beschleunigt. Durch die Verwendung einer Vorlage stehen uns vorgabemäßige Imports jederzeit einsatzbereit zur Verfügung, wenn wir ein benutzerdefiniertes Python-Skript entwickeln möchten.

Die Vorlage befindet sich im Ordner APPDATA Ihrer Dynamo-Installation.

Dies ist in der Regel wie folgt ( %appdata%\Dynamo\Dynamo Core\{version}\ ).

hashtag
Einrichten der Vorlage

Um diese Funktion nutzen zu können, müssen wir unserer Datei DynamoSettings.xml die folgende Zeile hinzufügen. (in Editor bearbeiten)

Ersetzen Sie alle Vorkommen von <PythonTemplateFilePath /> durch das Folgende:

circle-exclamation

Anmerkung: Ersetzen Sie CURRENTUSER durch Ihren Benutzernamen

Als Nächstes müssen wir eine Vorlage mit den Funktionen erstellen, die wir integrieren möchten. In diesem Fall können wir die Revit-bezogenen Importe und einige andere typische Elemente einbetten, die wir bei der Arbeit mit Revit verwenden.

Sie können mit einem leeren Editor-Dokument beginnen und den folgenden Code einfügen:

Anschließend speichern Sie diese Datei als PythonTemplate.py am Speicherort APPDATA.

hashtag
Das Verhalten des Python-Skripts danach

Nach dem Definieren der Python-Vorlage sucht Dynamo jedes Mal danach, wenn Sie einen Python-Block einfügen. Wenn sie nicht gefunden wird, wird das vorgabemäßige Python-Fenster angezeigt.

Wenn die Python-Vorlage gefunden wird (beispielsweise für Revit), werden alle vorgegebenen Elemente angezeigt, die Sie integriert haben.

Weitere Informationen zu dieser großartigen Ergänzung (von Radu Gidei) finden Sie hier. https://github.com/DynamoDS/Dynamo/pull/8122

Oberflächen: Interpolation, Steuerpunkte, Erhebung, Drehung

Die zweidimensionale Entsprechung zur NurbsCurve ist die NurbsSurface, und wie die Freiform-NurbsCurve können NurbsSurfaces mit zwei grundlegenden Methoden konstruiert werden: durch Eingabe eines Satzes von Basispunkten, zwischen denen Dynamo interpoliert, oder durch explizites Angeben der Steuerpunkte der Oberfläche. Ebenso wie Freiformkurven sind interpolierte Oberflächen nützlich, wenn ein Konstrukteur die präzise Form kennt, die eine Oberfläche aufweisen soll, oder ein Entwurf erfordert, dass die Oberfläche durch Abhängigkeitspunkte führt. Mit Steuerpunkten erstellte Oberflächen wiederum können dann nützlich sein, wenn es um experimentelle Entwürfe mit unterschiedlichen Glättungsgraden geht.

hashtag
Interpolierte Oberfläche

Zum Erstellen einer interpolierten Oberfläche generieren Sie einfach eine zweidimensionale Punktsammlung als Annäherung an die Form einer Oberfläche. Die Sammlung muss rechteckig sein, also nicht gezackt. Die Methode

<PythonTemplateFilePath>
<string>C:\Users\CURRENTUSER\AppData\Roaming\Dynamo\Dynamo Core\2.0\PythonTemplate.py</string>
</PythonTemplateFilePath>
import clr

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import *

clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *

clr.AddReference('System')
from System.Collections.Generic import List

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

#Preparing input from dynamo to revit
element = UnwrapElement(IN[0])

#Do some action in a Transaction
TransactionManager.Instance.EnsureInTransaction(doc)

TransactionManager.Instance.TransactionTaskDone()

OUT = element
erhalten wir daher eine Folge von 0 bis 10 mit der Schrittgröße 1.
  • Das Beispiel für die Folge ist ähnlich, allerdings wird hier mithilfe eines #-Zeichens angegeben, dass die Liste nicht beim Wert 15 enden, sondern 15 Werte enthalten soll. In diesem Fall wird Folgendes definiert: beginning..#ofSteps..step-size:. Die tatsächliche Syntax für die Sequenz lautet: 0..#15..2

  • Platzieren Sie das #-Zeichen aus dem vorigen Schritt jetzt im Bereich für die Schrittgröße der Syntax. Damit haben Sie einen Zahlenbereich vom Anfang zum Ende erstellt. Die Notation für die Schrittgröße verteilt die angegebene Anzahl Werte gleichmäßig zwischen diesen beiden Angaben: beginning..end..#ofSteps

  • Zahlen

    Zeichenfolgen

    Sequenzen

    Bereiche

    Eintrag an Indexposition abrufen

    Liste erstellen

    Zeichenfolgen verketten

    Bedingungsanweisungen

    Block/Blöcke

    Codeblock-Entsprechung

    Anmerkung

    Beliebiger Operator (+, &&, >=, Not, usw.)

    +, &&, >=, !, usw.

    Beachten Sie, dass "Not" (Nicht) durch "!" ersetzt wird, der Block jedoch zur Unterscheidung von "Fakultät" nach wie vor "Not" heißt.

    Boolescher Wert True

    true;

    Anmerkung: Kleinbuchstaben

    Boolescher Wert False

    false;

    Anmerkung: Kleinbuchstaben

    file-download
    20KB
    Obsolete-Nodes_Sine-Surface.dyn
    arrow-up-right-from-squareOpen
    NurbsSurface.ByPoints
    erstellt eine Oberfläche aus diesen Punkten.

    hashtag
    Steuerpunktoberfläche

    Freiform-NurbsSurfaces können auch erstellt werden, indem die zugrunde liegenden Steuerpunkte einer Oberfläche angegeben werden. Wie bei NurbsCurves kann man sich die Steuerpunkte als Darstellung eines vierseitigen Netzes mit geraden Segmenten vorstellen, das je nach dem Grad der Oberfläche zur endgültigen Oberflächenform geglättet wird. Um eine NurbsSurface aus Steuerpunkten zu erstellen, schließen Sie zwei zusätzliche Parameter in NurbsSurface.ByPoints ein, die den Grad der zugrunde liegenden Kurven in beide Richtungen der Oberfläche angeben.

    Wir können den Grad der NurbsSurface erhöhen, um die resultierende Oberflächengeometrie zu ändern:

    hashtag
    Erhabene Fläche

    Genauso wie Oberflächen durch Interpolation zwischen einer Reihe eingegebener Punkte erstellt werden können, können sie auch durch Interpolation zwischen einem Satz von Basiskurven erstellt werden. Dieser Ansatz wird als Erhebung bezeichnet. Eine Erhebungskurve wird mit dem Konstruktor Surface.ByLoft und einer Sammlung von Eingabekurven als einzigem Parameter erstellt.

    hashtag
    Drehen von Flächen

    Rotationsflächen sind ein weiterer Typ von Oberflächen, die durch Sweeping einer Basiskurve um eine Mittelachse erstellt werden. Wenn interpolierte Oberflächen zweidimensional analog zu interpolierten Kurven sind, dann sind Rotationsflächen zweidimensional analog zu Kreisen und Bogen.

    Rotationsflächen werden definiert durch eine Basiskurve, die die Kante der Oberfläche darstellt, einen Achsenursprung, der den Basispunkt der Oberfläche bildet, eine Achsenrichtung, die die Kernrichtung vorgibt, einen Sweeping-Startwinkel sowie einen Sweeping-Endwinkel. Diese Parameter werden als Eingabe für den Konstruktor Surface.Revolve verwendet.

    Vektormathematik

    Objekte in computergestützten Entwürfen werden selten explizit in ihrer endgültigen Position und Form erstellt, meist werden sie verschoben, gedreht und anderweitig anhand von bestehender Geometrie positioniert. Die Vektormathematik dient als eine Art geometrisches Gerüst, um der Geometrie Richtung und Ausrichtung zu verleihen sowie Bewegungen durch den dreidimensionalen Raum ohne visuelle Darstellung zu konzeptuieren.

    In seiner einfachsten Form stellt ein Vektor eine Position im dreidimensionalen Raum dar. Man stellt sich ihn oft als Endpunkt eines Pfeils zwischen der Position (0, 0, 0) und der gegebenen Position vor. Vektoren können unter Verwendung des Konstruktors ByCoordinates erstellt werden, wobei die x-, y- und z-Position des neu erstellten Vektorobjekts angegeben wird. Beachten Sie, dass Vektoren keine geometrischen Objekte sind und nicht im Dynamo-Fenster angezeigt werden. Informationen zu einem neu erstellten oder geänderten Vektor können jedoch im Konsolenfenster gedruckt werden:

    Für Vektoren ist ein Satz von mathematischen Operationen definiert, sodass Sie Objekte im dreidimensionalen Raum genauso addieren, subtrahieren, multiplizieren und anderweitig verschieben können wie reelle Zahlen im eindimensionalen Raum auf einer Zahlengeraden.

    hashtag
    Vektoraddition

    Vektoraddition ist definiert als die Summe der Komponenten von zwei Vektoren. Man kann sie sich so vorstellen, dass der resultierende Vektor aus zwei mit der Spitze des einen am Ende des anderen platzierten Vektoren entsteht. Vektoraddition wird mit der Methode Add durchgeführt und wird im Diagramm auf der linken Seite abgebildet.

    hashtag
    Vektorsubtraktion

    Gleichermaßen können zwei Vektorobjekte mit der Methode Subtract voneinander subtrahiert werden. Vektorsubtraktion kann man sich als die Richtung vom ersten zum zweiten Vektor vorstellen.

    hashtag
    Vektormultiplikation

    Vektormultiplikation kann man sich so vorstellen, dass der Endpunkt eines Vektors in seiner eigenen Richtung um einen angegebenen Skalierungsfaktor verschoben wird.

    hashtag
    Vektorlänge normalisieren

    Häufig ist beim Skalieren eines Vektors erwünscht, dass die Länge des resultierenden Vektors genau gleich dem skalierten Betrag ist. Dies wird einfach erreicht, indem zuerst ein Vektor normalisiert wird, also die Länge des Vektors auf genau eins festgelegt wird.

    c weist weiterhin in dieselbe Richtung wie (1, 2, 3), hat jetzt jedoch eine Länge genau gleich 5.

    hashtag
    Kreuzprodukt

    In der Vektormathematik gibt es zwei weitere Methoden, die keine eindeutigen Parallelen zur eindimensionalen Mathematik aufweisen, das Kreuzprodukt und das Skalarprodukt. Das Kreuzprodukt ist eine Methode zum Erstellen eines Vektors, der sich im rechten Winkel (90 Grad) zu zwei vorhandenen Vektoren befindet. Beispielsweise ist das Kreuzprodukt der x- und y-Achsen die Z-Achse, auch wenn die beiden Eingabevektoren nicht orthogonal zueinander sein müssen. Ein Kreuzproduktvektor wird mit der Methode Cross berechnet.

    hashtag
    Punktprodukt

    Eine weitere, wenn auch fortgeschrittenere Funktion der Vektormathematik ist das Skalarprodukt. Das Skalarprodukt zwischen zwei Vektoren ist eine reelle Zahl (kein Vektorobjekt), die mit dem Winkel zwischen zwei Vektoren zusammenhängt, jedoch nicht exakt diesem Winkel entspricht. Ein hilfreiche Eigenschaft des Skalarprodukts besteht darin, dass das Skalarprodukt zweier Vektoren nur genau dann 0 ist, wenn sie lotrecht zueinander stehen. Das Skalarprodukt wird mit der Methode Dot berechnet.

    Verschiebung, Drehung und andere Transformationen

    Bestimmte geometrische Objekte können erstellt werden, indem Sie die x-, y- und z-Koordinaten im dreidimensionalen Raum explizit angeben. Häufiger wird die Geometrie jedoch mithilfe von geometrischen Transformationen auf das Objekt selbst oder auf das zugrunde liegende Koordinatensystem in ihre endgültige Position verschoben.

    hashtag
    Translation

    Die einfachste geometrische Transformation ist eine Verschiebung, bei der ein Objekt um eine bestimmte Anzahl von Einheiten in x-, y- und z-Richtung verschoben wird.

    hashtag
    Drehung

    Zwar können alle Objekte in Dynamo durch Anhängen der Methode .Translate ans Ende des Objektnamens verschoben werden, jedoch erfordern komplexere Transformationen, dass das Objekt von einem zugrunde liegenden Koordinatensystem in ein neues Koordinatensystem überführt wird. Um beispielsweise ein Objekt um 45 Grad um die X-Achse zu drehen, können wir das Objekt aus seinem bisherigen Koordinatensystem ohne Drehung in ein Koordinatensystem überführen, das mit der Methode .Transform um 45 Grad um die X-Achse gedreht wurde:

    hashtag
    Skalieren

    Zusätzlich zu den Möglichkeiten, Koordinatensysteme zu verschieben und zu drehen, können sie auch skaliert oder geschert erstellt werden. Ein Koordinatensystem kann mit der Methode .Scale skaliert werden:

    Gescherte Koordinatensysteme werden erstellt, indem nicht-orthogonale Vektoren in den Konstruktor CoordinateSystem eingegeben werden.

    Skalieren und Scheren sind erheblich komplexere geometrische Transformationen als Drehen und Verschieben, daher können sie nicht auf alle Dynamo-Objekte angewendet werden. Die folgende Tabelle gibt Aufschluss darüber, welche Dynamo-Objekte ungleichmäßig skalierte sowie gescherte Koordinatensysteme aufweisen können.

    Klasse
    Ungleichmäßig skaliertes Koordinatensystem
    Geschertes Koordinatensystem

    DesignScript-Syntax

    Die Namen von Blöcken in Dynamo weisen ein gemeinsames Merkmal auf: Sie enthalten einen Punkt "." ohne Leerzeichen. Der Grund dafür ist, dass als Text oben in jedem Block dessen Syntax in der Skriptsprache angegeben wird. Der Punkt (".") in der sogenannten Punktnotation trennt dabei das Element von den möglichen Methoden, die für dieses aufgerufen werden können. Dies vermittelt auf einfache Weise zwischen visueller und textbasierter Skripterstellung.

    NodeNames

    Zur allgemeinen Veranschaulichung der Punktnotation dient hier die parametrische Behandlung eines Apfels in Dynamo. Im Folgenden werden einige "Methoden" betrachtet, die Sie für den Apfel ausführen können (bevor Sie ihn essen). (Anmerkung: Diese Methoden sind keine echten Dynamo-Methoden.)

    Von Menschen lesbar.
    Punktnotation
    Ausgabe

    Die Ausgabedaten in der Tabelle lassen darauf schließen, dass dieser Apfel schmackhaft ist. Ich glaube, ich Apfel.Essen().

    hashtag
    Punktnotation in Codeblöcken

    Behalten Sie dieses anschauliche Beispiel im Gedächtnis, wenn jetzt anhand von Point.ByCoordinates gezeigt wird, wie Sie mithilfe von Codeblöcken einen Punkt erstellen können.

    Die Code Block-Syntax Point.ByCoordinates(0,10); gibt dasselbe Ergebnis aus wie der Point.ByCoordinates-Block in Dynamo, allerdings genügt ein Block, um den Punkt zu erstellen. Dieses Verfahren ist effizienter als die Verbindung separater Blöcke mit x und y.

    1. Indem Sie Point.ByCoordinates im Codeblock verwenden, legen Sie die Eingabewerte in derselben Reihenfolge fest wie im vorgegebenen Block (x, y).

    hashtag
    Aufrufen von Blöcken – Erstellen, Aktionen, Abfragen

    Sie können beliebige Blöcke aus der Bibliothek mithilfe eines Codeblocks aufrufen. Ausgenommen hiervon sind spezielle Blöcke für die Benutzeroberfläche, d. h. Blöcke mit einer speziellen Funktion in der Benutzeroberfläche. So können Sie beispielsweise Circle.ByCenterPointRadius aufrufen; einen Watch 3D-Block aufzurufen, wäre jedoch wenig sinnvoll.

    Es gibt generell drei Typen normaler Blöcke (dies umfasst die meisten Blöcke in der Bibliothek). Die Bibliothek ist anhand dieser Kategorien geordnet. Methoden bzw. Blöcke dieser drei Typen werden beim Aufruf in einem Codeblock unterschiedlich behandelt.

    1. Erstellen: Erstellt bzw. konstruiert ein Objekt.

    2. Aktion: Führt einen Vorgang für ein Objekt aus.

    3. Abfrage: Ruft eine Eigenschaft eines bestehenden Objekts ab.

    hashtag
    Erstellen

    Mit Blöcken aus der Kategorie Erstellen wird völlig neue Geometrie konstruiert. Die Werte werden von links nach rechts in den Codeblock eingegeben. Dabei wird dieselbe Reihenfolge für die Eingaben eingehalten wie im eigentlichen Block von oben nach unten.

    Der Vergleich des Line.ByStartPointEndPoint-Blocks und der entsprechenden Syntax im Codeblock zeigt, dass Sie dieselben Ergebnisse erhalten.

    hashtag
    Aktion

    Eine Aktion ist ein Vorgang, den Sie für ein Objekt des gegebenen Typs ausführen. In Dynamo wird die vielen Programmiersprachen gemeinsame Punktnotation zum Anwenden von Aktionen auf Objekte verwendet. Dabei geben Sie zuerst das Objekt, dann einen Punkt und schließlich den Namen der Aktion ein. Die Eingabewerte für Aktionsmethoden werden genau wie bei Erstellungsmethoden in Klammern gesetzt, wobei Sie jedoch die erste Eingabe aus dem entsprechenden Block nicht angeben müssen. Stattdessen geben Sie das Element an, für Sie die Aktion durchführen:

    1. Der Point.Add-Block ist ein Aktionsblock, d. h., die Syntax funktioniert anders als zuvor.

    2. Die Eingaben sind: 1. der point und 2. der hinzuzufügende vector. Im Code Block hat der Punkt (das Objekt) die Bezeichnung "pt". Um einen Vektor *"vec" * zu "pt" hinzuzufügen, müssen Sie pt.Add(vec) schreiben, oder: Objekt, Punkt, Aktion. Die Aktion Add benötigt nur eine Eingabe, d. h. alle Eingaben aus dem Point.Add-Block ausgenommen die erste. Die erste Eingabe für den Point.Add-Block ist der Punkt selbst.

    hashtag
    Abfrage

    Abfragemethoden rufen eine Eigenschaft eines Objekts ab. Da das Objekt selbst die Eingabe ist, müssen Sie keine weiteren Eingaben angeben. Es sind keine Klammern erforderlich.

    hashtag
    Wie funktioniert die Vergitterung?

    Die Funktionsweise der Vergitterung in Blöcken unterscheidet sich von derjenigen in Codeblöcken. In Blöcken klickt der Benutzer mit der rechten Maustaste auf den jeweiligen Block und wählt die benötigte Vergitterungsoption. Codeblöcke bieten wesentlich mehr Kontrolle über die Strukturierung der Daten. In der Codeblock-Kurzschreibweise wird die Zuordnung mehrerer eindimensionaler Listen mithilfe von Replikationsanleitungen festgelegt,. Die Hierarchie innerhalb der resultierenden verschachtelten Liste wird durch Zahlen in spitzen Klammern "< >" definiert: <1>,<2>,<3> usw.

    1. In diesem Beispiel werden mithilfe der Kurzschreibweise zwei Bereiche definiert. (Genauere Informationen zu Kurzschreibweisen erhalten Sie im folgenden Abschnitt dieses Kapitels.) Kurz gesagt, 0..1; entspricht {0,1} und -3..-7 entspricht {-3,-4,-5,-6,-7}. Als Ergebnis erhalten Sie Listen mit zwei x- und 5 y-Werten. Ohne Replikationsanleitungen wird aus diesen nicht übereinstimmenden Listen eine Liste mit zwei Punkten erstellt, was der Länge der kürzesten Liste entspricht. Mithilfe der Replikationsanleitungen werden sämtliche möglichen Kombinationen aus zwei und fünf Koordinaten (d. h. ihr Kreuzprodukt) ermittelt.

    Diese Notation ermöglicht es außerdem, welche der Listen der anderen übergeordnet sein soll, d. h., ob zwei Listen mit fünf Einträgen oder fünf Listen mit zwei Einträgen ausgegeben werden sollen. In diesem Beispiel bewirkt die Änderung der Reihenfolge der Replikationsanleitungen, dass als Ergebnis eine Liste entweder mit Zeilen von Punkten oder mit Spalten von Punkten ausgegeben wird.

    hashtag
    Block zu Code

    Für die oben beschriebenen Codeblock-Methoden ist eventuell eine gewisse Einarbeitung nötig. In Dynamo steht die Funktion Block zu Code zur Verfügung, die dies erleichtert. Um diese Funktion zu verwenden, wählen Sie eine Gruppe von Blöcken in Ihrem Dynamo-Diagramm aus, klicken mit der rechten Maustaste in den Ansichtsbereich und wählen Block zu Code. Dynamo fasst daraufhin diese Blöcke einschließlich aller Ein- und Ausgaben in einem Codeblock zusammen. Dies ist nicht nur ideal zum Erlernen von Codeblock, sondern ermöglicht darüber hinaus die Arbeit mit effizienteren und stärker parametrischen Dynamo-Diagrammen. Die unten folgende Übungslektion wird mit einem Abschnitt zu Block zu Code abgeschlossen. Sie sollten sie daher vollständig bearbeiten.

    hashtag
    Übung: Oberflächenattraktor

    Laden Sie die Beispieldatei herunter, indem Sie auf den folgenden Link klicken.

    Eine vollständige Liste der Beispieldateien finden Sie im Anhang.

    Zur Demonstration der Effizienz von Codeblock wird hier eine bestehende Definition eines Attraktorfelds in Codeblockform übertragen. Die Verwendung einer bestehenden Definition zeigt die Beziehung zwischen Codeblock und visuellem Skript und erleichtert das Erlernen der Design Script-Syntax.

    Erstellen Sie zuerst die in der Abbildung oben gezeigte Definition (oder öffnen Sie die Beispieldatei).

    1. Als Vergitterung für Point.ByCoordinates wurde Kreuzprodukt eingestellt.

    2. Die einzelnen Punkte eines Rasters werden in Abhängigkeit von ihrer Entfernung zum Referenzpunkt in z-Richtung nach oben verschoben.

    3. Eine Oberfläche wird erstellt und verdickt, sodass die Geometrie relativ zur Entfernung vom Referenzpunkt ausgebeult wird.

    1. Wir beginnen mit der Definition des Referenzpunkts: Point.ByCoordinates(x,y,0); Wir verwenden dieselbe Point.ByCoordinates-Syntax wie oben im Referenzpunkt-Block angegeben.

    2. Die Variablen x und y werden in den Codeblock eingefügt, sodass sie mithilfe von Schiebereglern dynamisch aktualisiert werden können.

    1. Definieren Sie in der zweiten Zeile des Codeblocks eine Kurzschreibweise, um den Nummernsequenz-Block zu ersetzen: coordsXY = (-50..50..#11);Dies wird im nächsten Abschnitt genauer beschrieben. Halten Sie zunächst fest, dass diese Kurzschreibweise dem Number Sequence-Block im visuellen Skript entspricht.

    1. Als Nächstes erstellen Sie ein Raster aus Punkten aus der coordsXY-Folge. Hierfür soll die Syntax Point.ByCoordinates verwendet werden, Sie müssen jedoch außerdem genau wie im visuellen Skript das Kreuzprodukt aus der Liste erstellen. Dazu geben Sie die folgende Zeile ein: gridPts = Point.ByCoordinates(coordsXY<1>,coordsXY<2>,0); Die spitzen Klammern geben die Referenz auf das Kreuzprodukt an.

    2. Im Watch3D-wird jetzt ein Raster von Punkten über das gesamte Dynamo-Raster angezeigt.

    1. Jetzt folgt der schwierige Teil: Die Punkte des Rasters sollen in Abhängigkeit von ihrer Entfernung zum Referenzpunkt nach oben verschoben werden. Diese neue Punktgruppe soll den Namen transPts erhalten. Eine Verschiebung ist eine Aktion, die für ein bestehendes Element durchgeführt wird. Daher verwenden wir nicht Geometry.Translate... sondern gridPts.Translate.

    2. Im Block, der im Ansichtsbereich gezeigt wird, sind drei Eingaben zu sehen. Die zu verschiebende Geometrie ist bereits deklariert, da die Aktion für dieses Element durchgeführt wird (mithilfe von gridPts.Translate). Die beiden verbleibenden Eingaben werden in die Klammern der Funktion eingegeben: direction und distance

    1. Damit haben Sie ein Raster aus Punkten mit einer geeigneten Datenstruktur zum Erstellen einer Nurbs-Oberfläche erstellt. Wir erstellen die Oberfläche mithilfe von srf = NurbsSurface.ByControlPoints(transPts);.

    1. Schließlich fügen Sie der Oberfläche Tiefe hinzu: Dazu konstruieren Sie mithilfe von solid = srf.Thicken(5); einen Volumenkörper. In diesem Fall wurde die Oberfläche im Code um 5 Einheiten verdickt, dies kann jedoch jederzeit auch als Variable (etwa mit dem Namen thickness) deklariert werden, deren Wert durch einen Schieberegler gesteuert wird.

    hashtag
    Vereinfachen des Diagramms mit Block zu Code

    Die Funktion Block zu Code führt die gesamte eben behandelte Übung durch einen einfachen Mausklick aus. Sie ermöglicht damit nicht nur die Erstellung benutzerdefinierter Definitionen und wiederverwendbarer Codeblöcke, sondern ist auch ein äußerst nützliches Hilfsmittel beim Erlernen der Skripterstellung in Dynamo:

    1. Beginnen Sie mit dem bestehenden visuellen Skript aus Schritt 1 dieser Übungslektion. Wählen Sie sämtliche Blöcke aus, klicken Sie mit der rechten Maustaste in den Ansichtsbereich und wählen Sie Block zu Code. Dieser einfache Schritt genügt.

    Dynamo hat automatisch eine Textversion des visuellen Diagramms einschließlich Vergitterung und aller anderen Angaben erstellt. Probieren Sie dies mit Ihren visuellen Skripts aus und schöpfen Sie die Möglichkeiten von Codeblöcken voll aus!

    Kurven: Interpolierte Punkte und Steuerpunkte

    Es gibt zwei grundlegende Methoden zum Erstellen von Freiform-Kurven in Dynamo: Die Angabe einer Sammlung von Punkten, zwischen denen Dynamo eine glatte Kurve interpoliert, oder eine einfachere Methode, bei der die zugrunde liegenden Steuerpunkte einer Kurve mit einem bestimmten Grad angegeben werden. Interpolierte Kurven sind nützlich, wenn ein Konstrukteur genau weiß, welche Form eine Linie annehmen soll, oder wenn der Entwurf bestimmte Beschränkungen aufweist, wo die Kurve verlaufen kann und wo nicht. Mit Steuerpunkten angegebene Kurven sind im Wesentlichen eine Reihe gerader Liniensegmente, die über einen Algorithmus in die endgültige Kurvenform geglättet werden. Das Festlegen einer Kurve mit Steuerpunkten eignet sich zum Experimentieren mit unterschiedlichen Kurvenformen mit verschiedenen Glättungsgraden, oder wenn glatte Übergänge zwischen Kurvensegmenten erforderlich sind.

    hashtag
    Interpolierte Kurve

    Zum Erstellen einer interpolierten Kurve übergeben Sie einfach eine Sammlung von Punkten an die Methode NurbsCurve.ByPoints.

    Die generierte Kurve schneidet jeden der eingegebenen Punkte und beginnt dabei am ersten und endet am letzten Punkt der Sammlung. Mit einem optionalen periodischen Parameter kann eine periodische Kurve erstellt werden, die geschlossen ist. Dynamo füllt das fehlende Segment automatisch aus, sodass kein duplizierter (mit dem Startpunkt identischer) Endpunkt erforderlich ist.

    hashtag
    Steuerpunktekurve

    NurbsCurves werden in ähnlicher Weise erstellt, wobei die Eingabepunkte die Endpunkte eines geraden Liniensegments darstellen und ein zweiter Parameter den Betrag und die Art der Glättung der Kurve angibt, was als Grad bezeichnet wird.* Eine Kurve mit dem Grad 1 ist nicht geglättet, sondern eine Polylinie.

    Eine Kurve mit dem Grad 2 wird so geglättet, dass die Kurve den Mittelpunkt der Polyliniensegmente schneidet und tangential zu diesem ist:

    Dynamo unterstützt NURBS-Kurven (Non-Uniform Rational B-Spline) bis zu 20 Grad. Das folgende Skript veranschaulicht die Auswirkungen steigender Glättungsstufen auf die Form einer Kurve:

    Beachten Sie, dass Sie mindestens einen Steuerpunkt mehr angeben müssen als der Grad, den die Kurve aufweist.

    Ein weiterer Vorteil der Kurvenerstellung mittels Steuerscheitelpunkten ist die Möglichkeit, Tangentialität zwischen einzelnen Kurvensegmenten beizubehalten. Dies erfolgt durch Extrahieren der Richtung zwischen den letzten beiden Steuerpunkten, und Fortsetzen dieser Richtung mit den ersten beiden Steuerpunkten der folgenden Kurve. Im folgenden Beispiel werden zwei getrennte NURBS-Kurven erstellt, die so glatt wie eine einzige Kurve sind:

    circle-info

    *Dies ist eine sehr einfache Beschreibung der NURBS-Kurvengeometrie. Eine präzisere und detailliertere Erläuterung finden Sie bei Pottmann et al. 2007 (siehe Referenzen).

    Geometrische Parametrisierung

    Bei computergestützten Entwürfen werden Kurven und Oberflächen häufig als zugrunde liegendes Gerüst verwendet, auf dem die spätere Geometrie konstruiert wird. Damit diese erste Geometrie als Grundlage für spätere Geometrien genutzt werden kann, muss das Skript fähig sein, Merkmale wie Position und Ausrichtung über das gesamte Objekt hinweg extrahieren zu können. Sowohl Kurven als auch Oberflächen unterstützen diese Extraktion, die als Parametrisierung bezeichnet wird.

    Alle Punkte auf einer Kurve kann man sich so vorstellen, dass sie einen eindeutigen Parameter zwischen 0 und 1 aufweisen. Wenn wir eine NurbsCurve basierend auf mehreren Steuerpunkten oder interpolierten Punkten erstellen möchten, hat der erste Punkt den Parameter 0 und der letzte Punkt den Parameter 1. Es ist nicht möglich, im Voraus wissen, welchen genauen Parameter ein Zwischenpunkt aufweist. Dies kann wie eine schwerwiegende Einschränkung klingen, wird jedoch durch eine Reihe von nützlichen Funktionen aufgewogen. Oberflächen weisen eine ähnliche Parametrisierung wie Kurven auf, allerdings mit zwei Parametern statt nur einem, die als u und v bezeichnet werden. Wenn wir eine Oberfläche aus den folgenden Punkten erstellen möchten, gilt:

    pts = [ [p1, p2, p3],
            [p4, p5, p6],
            [p7, p8, p9] ];

    p1 hat die Parameter u = 0 v = 0, während p9 die Parameter u = 1 v = 1 aufweist.

    Parametrisierung ist nicht sehr hilfreich, wenn Sie Punkte zum Erstellen von Kurven ermitteln möchten. Der Hauptzweck liegt darin, die Positionen der Zwischenpunkte zu bestimmen, die von den Konstruktoren NurbsCurve und NurbsSurface generiert werden.

    Kurven haben die Methode PointAtParameter, die ein einzelnes double-Argument zwischen 0 und 1 annimmt und das Punktobjekt an diesem Parameter zurückgibt. Dieses Skript ermittelt beispielsweise die Punkte an den Parametern 0, .1, .2, .3, .4, .5, .6, .7, .8, .9 und 1:

    Analog dazu haben Oberflächen eine Methode PointAtParameter, die zwei Argumente annimmt, nämlich die u- und v-Parameter des generierten Punkts.

    Das Extrahieren einzelner Punkte auf einer Kurve und Oberfläche kann nützlich sein, Skripte erfordern jedoch häufig die genauen geometrischen Merkmale an einem Parameter, z. B., in welche Richtung die Kurve bzw. Oberfläche gewandt ist. Die Methode CoordinateSystemAtParameter findet nicht nur die Position, sondern ein ausgerichtetes Koordinatensystem am Parameter einer Kurve oder Oberfläche. Beispielsweise extrahiert das folgende Skript ausgerichtete Koordinatensysteme entlang einer Rotationsfläche und verwendet die Ausrichtung der Koordinatensysteme, um Linien zu generieren, die senkrecht zur Oberfläche stehen:

    Wie bereits erwähnt, erfolgt die Parametrisierung nicht immer gleichmäßig über die Länge einer Kurve oder Oberfläche hinweg, was bedeutet, dass der Parameter 0.5 nicht immer dem Mittelpunkt und 0.25 nicht immer einem Viertel der Länge entlang einer Kurve oder Oberfläche entspricht. Um diese Einschränkung zu umgehen, verfügen Kurven über einen zusätzlichen Satz von Parametrisierungsbefehlen, mit denen Sie einen Punkt mit einer bestimmten Länge entlang einer Kurve finden können.

    Geometrische boolesche Operationen

    Intersect, Trim und SelectTrim werden hauptsächlich für niedrigerdimensionale Geometrien wie Punkte, Kurven und Oberflächen genutzt. Volumenkörper-Geometrie verfügt über einen zusätzlichen Satz von Methoden zum Ändern der Form nach ihrer Erstellung, sowohl durch Subtraktion von Material, ähnlich wie Trim, als auch durch Kombination von Elementen zu einem größeren Ganzen.

    hashtag
    Union

    Die Methode Union nimmt zwei Volumenkörper-Objekte und erstellt ein einzelnes Volumenkörper-Objekt aus dem Raum, der von beiden Objekten abgedeckt wird. Der Überlappungsbereich zwischen den einzelnen Objekten wird zur endgültigen Form kombiniert. In diesem Beispiel werden eine Kugel und ein Quader in einer einzigen Volumenkörper-Kugel-Quader-Form kombiniert:

    hashtag
    Difference

    Die Methode Difference subtrahiert ähnlich wie Trim die Inhalte des eingegebenen Werkzeug-Volumenkörpers vom Basis-Volumenkörper. In diesem Beispiel kerben wir eine Kugel leicht ein:

    hashtag
    Intersect

    Die Methode Intersect gibt den überlappenden Volumenkörper zwischen zwei Eingabe-Volumenkörpern zurück. Im folgenden Beispiel wurde Difference in Intersect geändert, und der resultierende Volumenkörper entspricht dem ursprünglich eingekerbten Leerraum:

    // python_points_1 is a set of Points generated with
    // a Python script found in Chapter 12, Section 10
    
    surf = NurbsSurface.ByPoints(python_points_1);
    // python_points_1 is a set of Points generated with
    // a Python script found in Chapter 12, Section 10
    
    // create a surface of degree 2 with smooth segments
    surf = NurbsSurface.ByPoints(python_points_1, 2, 2);
    // python_points_1 is a set of Points generated with
    // a Python script found in Chapter 12, Section 10
    
    // create a surface of degree 6
    surf = NurbsSurface.ByPoints(python_points_1, 6, 6);
    // python_points_2, 3, and 4 are generated with
    // Python scripts found in Chapter 12, Section 10
    
    c1 = NurbsCurve.ByPoints(python_points_2);
    c2 = NurbsCurve.ByPoints(python_points_3);
    c3 = NurbsCurve.ByPoints(python_points_4);
    
    loft = Surface.ByLoft([c1, c2, c3]);
    pts = {};
    pts[0] = Point.ByCoordinates(4, 0, 0);
    pts[1] = Point.ByCoordinates(3, 0, 1);
    pts[2] = Point.ByCoordinates(4, 0, 2);
    pts[3] = Point.ByCoordinates(4, 0, 3);
    pts[4] = Point.ByCoordinates(4, 0, 4);
    pts[5] = Point.ByCoordinates(5, 0, 5);
    pts[6] = Point.ByCoordinates(4, 0, 6);
    pts[7] = Point.ByCoordinates(4, 0, 7);
    
    crv = NurbsCurve.ByPoints(pts);
    
    axis_origin = Point.ByCoordinates(0, 0, 0);
    axis = Vector.ByCoordinates(0, 0, 1);
    
    surf = Surface.ByRevolve(crv, axis_origin, axis, 0,
        360);
    // construct a Vector object
    v = Vector.ByCoordinates(1, 2, 3);
    
    s = v.X + " " + v.Y + " " + v.Z;
    // create a point at x = 1, y = 2, z = 3
    p = Point.ByCoordinates(1, 2, 3);
    
    // translate the point 10 units in the x direction,
    // -20 in y, and 50 in z
    // p2’s new position is x = 11, y = -18, z = 53
    p2 = p.Translate(10, -20, 50);

    100 km

    Mit der Syntax Point.ByCoordinates(x_vals<1>,y_vals<2>); erhalten Sie zwei Listen mit je fünf Einträgen.
  • Mit der Syntax Point.ByCoordinates(x_vals<2>,y_vals<1>); erhalten Sie fünf Listen mit je zwei Einträgen.

  • Fügen Sie Schieberegler für die Eingaben im Codeblock hinzu, mit denen Bereiche von -50 bis 50 definiert werden. Dies erstreckt sich über das gesamte Vorgaberaster von Dynamo.
    .
  • Die Richtung ist leicht anzugeben: Sie geben Vector.ZAxis() für die vertikale Verschiebung an.

  • Die Abstände zwischen dem Referenzpunkt und den einzelnen Rasterpunkten müssen jedoch noch berechnet werden. Dies erreichen Sie auf dieselbe Weise wie zuvor durch eine Aktion für den Referenzpunkt: refPt.DistanceTo(gridPts)

  • Die letzte Codezeile enthält die verschobenen Punkte: transPts=gridPts.Translate(Vector.ZAxis(),refPt.DistanceTo(gridPts));

  • Welche Farbe hat der Apfel?

    Apfel.Farbe

    Rot

    Ist der Apfel reif?

    Apfel.istReif

    Wahr

    Wie viel wiegt der Apfel?

    Apfel.Gewicht

    170 g

    Woher kommt der Apfel?

    Apfel.Übergeordnet

    Baum

    Was kann aus dem Apfel entstehen?

    Apfel.Untergeordnet

    Kerne

    Wurde der Apfel hier in der Gegend angebaut?

    file-download
    14KB
    Dynamo-Syntax_Attractor-Surface.dyn
    arrow-up-right-from-squareOpen

    Apfel.EntfernungVonObstgarten

    Nein

    No

    Linie

    Ja

    Ja

    Ebene

    Nein

    No

    Punkt

    Ja

    Ja

    Polygon

    Nein

    No

    Volumenkörper

    Nein

    No

    Oberfläche

    Nein

    No

    Text

    Nein

    No

    Bogen

    Nein

    No

    NurbsCurve

    Ja

    Ja

    NurbsSurface

    Nein

    No

    Kreis

    a = Vector.ByCoordinates(5, 5, 0);
    b = Vector.ByCoordinates(4, 1, 0);
    
    // c has value x = 9, y = 6, z = 0
    c = a.Add(b);
    a = Vector.ByCoordinates(5, 5, 0);
    b = Vector.ByCoordinates(4, 1, 0);
    
    // c has value x = 1, y = 4, z = 0
    c = a.Subtract(b);
    a = Vector.ByCoordinates(4, 4, 0);
    
    // c has value x = 20, y = 20, z = 0
    c = a.Scale(5);
    a = Vector.ByCoordinates(1, 2, 3);
    a_len = a.Length;
    
    // set the a's length equal to 1.0
    b = a.Normalized();
    c = b.Scale(5);
    
    // len is equal to 5
    len = c.Length;
    a = Vector.ByCoordinates(1, 0, 1);
    b = Vector.ByCoordinates(0, 1, 1);
    
    // c has value x = -1, y = -1, z = 1
    c = a.Cross(b);
    a = Vector.ByCoordinates(1, 2, 1);
    b = Vector.ByCoordinates(5, -8, 4);
    
    // d has value -7
    d = a.Dot(b);
    cube = Cuboid.ByLengths(CoordinateSystem.Identity(),
        10, 10, 10);
    
    new_cs = CoordinateSystem.Identity();
    new_cs2 = new_cs.Rotate(Point.ByCoordinates(0, 0),
        Vector.ByCoordinates(1,0,0.5), 25);
    
    // get the existing coordinate system of the cube
    old_cs = CoordinateSystem.Identity();
    
    cube2 = cube.Transform(old_cs, new_cs2);
    cube = Cuboid.ByLengths(CoordinateSystem.Identity(),
        10, 10, 10);
    
    new_cs = CoordinateSystem.Identity();
    new_cs2 = new_cs.Scale(20);
    
    old_cs = CoordinateSystem.Identity();
    
    cube2 = cube.Transform(old_cs, new_cs2);
    new_cs = CoordinateSystem.ByOriginVectors(
        Point.ByCoordinates(0, 0, 0),
    	Vector.ByCoordinates(-1, -1, 1),
    	Vector.ByCoordinates(-0.4, 0, 0));
    
    old_cs = CoordinateSystem.Identity();
    
    cube = Cuboid.ByLengths(CoordinateSystem.Identity(),
        5, 5, 5);
    
    new_curves = cube.Transform(old_cs, new_cs);
    num_pts = 6;
    
    s = Math.Sin(0..360..#num_pts) * 4;
    
    pts = Point.ByCoordinates(1..30..#num_pts, s, 0);
    
    int_curve = NurbsCurve.ByPoints(pts);
    pts = Point.ByCoordinates(Math.Cos(0..350..#10),
        Math.Sin(0..350..#10), 0);
    
    // create an closed curve
    crv = NurbsCurve.ByPoints(pts, true);
    
    // the same curve, if left open:
    crv2 = NurbsCurve.ByPoints(pts.Translate(5, 0, 0),
        false);
    num_pts = 6;
    
    pts = Point.ByCoordinates(1..30..#num_pts,
        Math.Sin(0..360..#num_pts) * 4, 0);
    
    // a B-Spline curve with degree 1 is a polyline
    ctrl_curve = NurbsCurve.ByControlPoints(pts, 1);
    num_pts = 6;
    
    pts = Point.ByCoordinates(1..30..#num_pts,
        Math.Sin(0..360..#num_pts) * 4, 0);
    
    // a B-Spline curve with degree 2 is smooth
    ctrl_curve = NurbsCurve.ByControlPoints(pts, 2);
    num_pts = 6;
    
    pts = Point.ByCoordinates(1..30..#num_pts,
        Math.Sin(0..360..#num_pts) * 4, 0);
    
    def create_curve(pts : Point[], degree : int)
    {
    	return = NurbsCurve.ByControlPoints(pts,
            degree);
    }
    
    ctrl_crvs = create_curve(pts, 1..11);
    pts_1 = {};
    
    pts_1[0] = Point.ByCoordinates(0, 0, 0);
    pts_1[1] = Point.ByCoordinates(1, 1, 0);
    pts_1[2] = Point.ByCoordinates(5, 0.2, 0);
    pts_1[3] = Point.ByCoordinates(9, -3, 0);
    pts_1[4] = Point.ByCoordinates(11, 2, 0);
    
    crv_1 = NurbsCurve.ByControlPoints(pts_1, 3);
    
    pts_2 = {};
    
    pts_2[0] = pts_1[4];
    end_dir = pts_1[4].Subtract(pts_1[3].AsVector());
    
    pts_2[1] = Point.ByCoordinates(pts_2[0].X + end_dir.X,
        pts_2[0].Y + end_dir.Y, pts_2[0].Z + end_dir.Z);
    
    pts_2[2] = Point.ByCoordinates(15, 1, 0);
    pts_2[3] = Point.ByCoordinates(18, -2, 0);
    pts_2[4] = Point.ByCoordinates(21, 0.5, 0);
    
    crv_2 = NurbsCurve.ByControlPoints(pts_2, 3);
    pts = {};
    pts[0] = Point.ByCoordinates(4, 0, 0);
    pts[1] = Point.ByCoordinates(6, 0, 1);
    pts[2] = Point.ByCoordinates(4, 0, 2);
    pts[3] = Point.ByCoordinates(4, 0, 3);
    pts[4] = Point.ByCoordinates(4, 0, 4);
    pts[5] = Point.ByCoordinates(3, 0, 5);
    pts[6] = Point.ByCoordinates(4, 0, 6);
    
    crv = NurbsCurve.ByPoints(pts);
    
    pts_at_param = crv.PointAtParameter(0..1..#11);
    
    // draw Lines to help visualize the points
    lines = Line.ByStartPointEndPoint(pts_at_param,
        Point.ByCoordinates(4, 6, 0));
    pts = {};
    pts[0] = Point.ByCoordinates(4, 0, 0);
    pts[1] = Point.ByCoordinates(3, 0, 1);
    pts[2] = Point.ByCoordinates(4, 0, 2);
    pts[3] = Point.ByCoordinates(4, 0, 3);
    pts[4] = Point.ByCoordinates(4, 0, 4);
    pts[5] = Point.ByCoordinates(5, 0, 5);
    pts[6] = Point.ByCoordinates(4, 0, 6);
    pts[7] = Point.ByCoordinates(4, 0, 7);
    
    crv = NurbsCurve.ByPoints(pts);
    
    axis_origin = Point.ByCoordinates(0, 0, 0);
    axis = Vector.ByCoordinates(0, 0, 1);
    
    surf = Surface.ByRevolve(crv, axis_origin, axis, 90,
        140);
    
    cs_array = surf.CoordinateSystemAtParameter(
        (0..1..#7)<1>, (0..1..#7)<2>);
    
    def make_line(cs : CoordinateSystem) {
    	lines_start = cs.Origin;
        lines_end = cs.Origin.Translate(cs.ZAxis, -0.75);
    
        return = Line.ByStartPointEndPoint(lines_start,
            lines_end);
    }
    
    lines = make_line(Flatten(cs_array));
    s1 = Sphere.ByCenterPointRadius(
        CoordinateSystem.Identity().Origin, 6);
    
    s2 = Sphere.ByCenterPointRadius(
        CoordinateSystem.Identity().Origin.Translate(4, 0,
        0), 6);
    
    combined = s1.Union(s2);
    s = Sphere.ByCenterPointRadius(
        CoordinateSystem.Identity().Origin, 6);
    
    tool = Sphere.ByCenterPointRadius(
        CoordinateSystem.Identity().Origin.Translate(10, 0,
        0), 6);
    
    result = s.Difference(tool);
    s = Sphere.ByCenterPointRadius(
        CoordinateSystem.Identity().Origin, 6);
    
    tool = Sphere.ByCenterPointRadius(
        CoordinateSystem.Identity().Origin.Translate(10, 0,
        0), 6);
    
    result = s.Intersect(tool);

    Python-Punkt-Generatoren

    Die folgenden Python-Skripte erstellen Punktgruppen für verschiedene Beispiele. Fügen Sie sie wie folgt in einen Python-Skript-Block ein:

    python_points_1

    out_points = []
    
    for i in range(11):
    	sub_points = []
    	for j in range(11):
    		z = 0
    		if (i == 5 and j == 5):
    			z = 1
    		elif (i == 8 and j == 2):
    			z = 1
    		sub_points.append(Point.ByCoordinates(i, j, z))
    	out_points.append(sub_points)
    
    OUT = out_points

    python_points_2

    out_points = []
    
    for i in range(11):
    	z = 0
    	if (i == 2):
    		z = 1
    	out_points.append(Point.ByCoordinates(i, 0, z))
    
    OUT = out_points

    python_points_3

    out_points = []
    
    for i in range(11):
    	z = 0
    	if (i == 7):
    		z = -1
    	out_points.append(Point.ByCoordinates(i, 5, z))
    
    OUT = out_points

    python_points_4

    python_points_5

    out_points = []
    
    for i in range(11):
    	z = 0
    	if (i == 5):
    		z = 1
    	out_points.append(Point.ByCoordinates(i, 10, z))
    
    OUT = out_points
    out_points = []
    
    for i in range(11):
    	sub_points = []
    	for j in range(11):
    		z = 0
    		if (i == 1 and j == 1):
    			z = 2
    		elif (i == 8 and j == 1):
    			z = 2
    		elif (i == 2 and j == 6):
    			z = 2
    		sub_points.append(Point.ByCoordinates(i, j, z))
    	out_points.append(sub_points)
    
    OUT = out_points

    Geometrische Grundkörper

    hashtag
    Koordinatensystem

    Zwar ist Dynamo in der Lage, eine Reihe komplexer geometrischer Formen zu erstellen, jedoch bilden einfache geometrische Grundkörper die Grundlage jedes computergestützten Entwurfs: entweder als direkter Ausdruck in der endgültigen Entwurfsform oder als Gerüst für die Erstellung einer komplexeren Geometrie.

    Ein Koordinatensystem ist streng genommen kein Geometrieobjekt, dient jedoch als wichtiges Hilfsmittel zum Erstellen von Geometrie. Ein CoordinateSystem-Objekt verfolgt Positions- und Geometrietransformationen wie Drehen, Scheren und Skalieren.

    Zum Erstellen eines an einem Punkt mit x = 0, y = 0, z = 0 zentrierten Koordinatensystems ohne Rotations-, Skalierungs- oder Schertransformationen kann einfach der Konstruktor Identity aufgerufen werden:

    Koordinatensysteme mit geometrischen Transformationen gehen über den Umfang dieses Kapitels hinaus, auch wenn Sie mit einem anderen Konstruktor, namentlich CoordinateSystem.ByOriginVectors, ein Koordinatensystem an einem bestimmten Punkt erstellen können:

    hashtag
    Punkt

    Der einfachste geometrische Grundkörper ist ein Punkt, der eine nulldimensionale Position im dreidimensionalen Raum darstellt. Wie bereits erwähnt gibt es verschiedene Möglichkeiten zum Erstellen eines Punkts in einem bestimmten Koordinatensystem: Point.ByCoordinates erstellt einen Punkt mithilfe der angegebenen Koordinaten x, y und z, Point.ByCartesianCoordinates erstellt einen Punkt mithilfe der angegebenen Koordinaten x, y und z in einem bestimmten Koordinatensystem, Point.ByCylindricalCoordinates erstellt einen Punkt, der auf einem Zylinder mit angegebenen Werten für Radius, Drehwinkel und Höhe liegt, und Point.BySphericalCoordinates erstellt einen Punkt auf einer Kugel mit einem angegebenen Radius und zwei Drehwinkeln.

    Dieses Beispiel zeigt Punkte, die in unterschiedlichen Koordinatensystemen erstellt wurden:

    hashtag
    Linie

    Der nächsthöherdimensionale Dynamo-Grundkörper ist ein Liniensegment, das eine unendliche Anzahl von Punkten zwischen zwei Endpunkten darstellt. Linien können erstellt werden, indem Sie die beiden Grenzpunkte mit dem Konstruktor Line.ByStartPointEndPoint explizit angeben, oder durch Angabe eines Startpunkts, einer Richtung und Länge in dieser Richtung mittels Line.ByStartPointDirectionLength.

    hashtag
    3D-Grundkörper - Quader, Kegel, Zylinder, Kugel usw.

    Dynamo verfügt über Objekte, die grundlegende Typen geometrischer Grundkörper in drei Dimensionen darstellen: Quader, erstellt mit Cuboid.ByLengths; Kegel, erstellt mit Cone.ByPointsRadius und Cone.ByPointsRadii; Zylinder, erstellt mit Cylinder.ByRadiusHeight sowie Kugeln, erstellt mit Sphere.ByCenterPointRadius.

    Funktionen

    Funktionen können in einem Codeblock erstellt und an anderer Stelle in einer Dynamo-Definition erneut aufgerufen werden. Dadurch erhalten Sie eine weitere Steuerungsmöglichkeit in parametrischen Dateien. Sie stellt eine Textversion eines benutzerdefinierten Blocks dar. In diesem Fall ist der übergeordnete Block problemlos verfügbar und kann sich an beliebiger Stelle im Diagramm befinden. Hierfür sind keine Verbindungen erforderlich.

    hashtag
    Übergeordneter Block

    Die erste Zeile besteht aus dem Schlüsselwort "def" und dem Namen der Funktion mit den Namen der Eingaben in Klammern. Der Hauptteil der Funktion wird in geschweiften Klammern angegeben. Verwenden Sie zum Ausgeben eines Werts "return =". In Codeblöcken, die eine Funktion definieren, sind keine Eingabe- oder Ausgabeverbindungen vorhanden, da sie über andere Codeblöcke aufgerufen werden.

    // create a CoordinateSystem at x = 0, y = 0, z = 0,
    // no rotations, scaling, or sheering transformations
    
    cs = CoordinateSystem.Identity();
    // create a CoordinateSystem at a specific location,
    // no rotations, scaling, or sheering transformations
    x_pos = 3.6;
    y_pos = 9.4;
    z_pos = 13.0;
    
    origin = Point.ByCoordinates(x_pos, y_pos, z_pos);
    identity = CoordinateSystem.Identity();
    
    cs = CoordinateSystem.ByOriginVectors(origin,
        identity.XAxis, identity.YAxis, identity.ZAxis);
    // create a point with x, y, and z coordinates
    x_pos = 1;
    y_pos = 2;
    z_pos = 3;
    
    pCoord = Point.ByCoordinates(x_pos, y_pos, z_pos);
    
    // create a point in a specific coordinate system
    cs = CoordinateSystem.Identity();
    pCoordSystem = Point.ByCartesianCoordinates(cs, x_pos,
        y_pos, z_pos);
    
    // create a point on a cylinder with the following
    // radius and height
    radius = 5;
    height = 15;
    theta = 75.5;
    
    pCyl = Point.ByCylindricalCoordinates(cs, radius, theta,
        height);
    
    // create a point on a sphere with radius and two angles
    
    phi = 120.3;
    
    pSphere = Point.BySphericalCoordinates(cs, radius,
        theta, phi);
    p1 = Point.ByCoordinates(-2, -5, -10);
    p2 = Point.ByCoordinates(6, 8, 10);
    
    // a line segment between two points
    l2pts = Line.ByStartPointEndPoint(p1, p2);
    
    // a line segment at p1 in direction 1, 1, 1 with
    // length 10
    lDir = Line.ByStartPointDirectionLength(p1,
        Vector.ByCoordinates(1, 1, 1), 10);
    // create a cuboid with specified lengths
    cs = CoordinateSystem.Identity();
    
    cub = Cuboid.ByLengths(cs, 5, 15, 2);
    
    // create several cones
    p1 = Point.ByCoordinates(0, 0, 10);
    p2 = Point.ByCoordinates(0, 0, 20);
    p3 = Point.ByCoordinates(0, 0, 30);
    
    cone1 = Cone.ByPointsRadii(p1, p2, 10, 6);
    cone2 = Cone.ByPointsRadii(p2, p3, 6, 0);
    
    // make a cylinder
    cylCS = cs.Translate(10, 0, 0);
    
    cyl = Cylinder.ByRadiusHeight(cylCS, 3, 10);
    
    // make a sphere
    centerP = Point.ByCoordinates(-10, -10, 0);
    
    sph = Sphere.ByCenterPointRadius(centerP, 5);

    hashtag
    Untergeordnete Blöcke

    Sie können die Funktion in einem anderen Codeblock in derselben Datei aufrufen, indem Sie ihren Namen und dieselbe Anzahl von Argumenten angeben. Dies funktioniert auf dieselbe Weise wie die vordefinierten Blöcke aus der Bibliothek.

    hashtag
    Übung: Kugel durch z

    Laden Sie die Beispieldatei herunter, indem Sie auf den folgenden Link klicken.

    Eine vollständige Liste der Beispieldateien finden Sie im Anhang.

    In dieser Übung erstellen Sie eine allgemeine Definition zum Erstellen von Kugeln aus einer eingegebenen Liste von Punkten. Der Radius dieser Kugeln wird durch die z-Eigenschaft des jeweiligen Punkts gesteuert.

    Sie beginnen mit einem Zahlenbereich, der zehn Werte von 0 bis 100 umfasst. Verbinden Sie diesen mit einem Point.ByCoordinates-Block, um eine diagonale Linie zu erhalten.

    Erstellen Sie einen Code Block und stellen Sie die Definition vor.

    1. Verwenden Sie die folgenden Codezeilen:

    Dabei ist inputPt der Name, den Sie für die Punkte zuweisen, über die die Funktion gesteuert werden soll. Bis hierher hat die Funktion keine Wirkung. Dies entwickeln Sie jedoch in den folgenden Schritten.

    1. Fügen Sie der Code Block-Funktion einen Kommentar und die Variable sphereRadius hinzu, die die Z-Position der einzelnen Punkte abfragt. Beachten Sie, dass die Methode inputPt.Z keine Klammern benötigt. Da es sich um eine Abfrage von Eigenschaften eines bestehenden Elements handelt, sind keine Eingaben erforderlich.

    1. Als Nächstes rufen Sie die eben erstellte Funktion in einem anderen Code Block auf. Wenn Sie im Ansichtsbereich doppelklicken, um einen neuen Code Block zu erstellen, und sphereB eingeben, schlägt Dynamo die eben definierte sphereByZ-Funktion vor: Die Funktion wurde der IntelliSense-Bibliothek hinzugefügt. Dieser Mechanismus ist sehr hilfreich.

    1. Als Nächstes erstellen Sie eine Variable mit dem Namen Pt, um die Verbindung zu den Punkten herzustellen, die Sie in den vorherigen Schritten erstellt haben:

    2. Die Ausgabe zeigt lediglich Nullwerte. Dies geschieht aus dem folgenden Grund: Beim Definieren der Funktion wurde festgelegt, dass die Variable sphereRadius berechnet werden soll, Sie haben jedoch noch nicht definiert, was die Funktion als Ausgabe zurückgeben soll. Dies beheben Sie im nächsten Schritt.

    1. In diesem wichtigen Schritt müssen Sie die Ausgabe der Funktion definieren. Fügen Sie die Zeile return = sphereRadius; in die sphereByZ-Funktion ein.

    2. Jetzt zeigt die Ausgabe im Codeblock die z-Koordinaten der einzelnen Punkte an.

    Als Nächstes erstellen Sie die Kugeln, indem Sie die übergeordnete Funktion bearbeiten.

    1. Definieren Sie zunächst eine Kugel mit der folgenden Codezeile: sphere=Sphere.ByCenterPointRadius(inputPt,sphereRadius);

    2. Als Nächstes ändern Sie den Rückgabewert in sphere anstelle von sphereRadius: return = sphere; Dadurch erhalten Sie in der Dynamo-Vorschau einige riesengroße Kugeln.

    1. Um die Größe dieser Kugeln zu verringern, aktualisieren wir den Wert sphereRadius, indem wir ein Trennzeichen hinzufügen: sphereRadius = inputPt.Z/20; Jetzt sind die einzelnen Kugeln getrennt sichtbar und die Beziehung zwischen dem Radius und dem z-Wert wird erkennbar.

    1. Indem Sie im Point.ByCoordinates-Block die Vergitterung von Kürzeste in Kreuzprodukt ändern, erstellen Sie ein Raster aus Punkten. Die sphereByZ-Funktion ist weiterhin uneingeschränkt wirksam, d. h., für alle Punkte werden Kugeln mit von ihren z-Werten abhängigen Radien erstellt.

    1. Verbinden Sie jetzt als weiteren Test die ursprüngliche Zahlenliste mit der x-Eingabe von Point.ByCoordinates. Dadurch entsteht ein Würfel aus Kugeln.

    2. Anmerkung: Wenn diese Berechnung auf Ihrem Computer viel Zeit in Anspruch nimmt, ändern Sie den Wert #10 in einen kleineren Wert, z. B. #5.

    Beachten Sie, dass die von Ihnen erstellte Funktion sphereByZ eine allgemeine Funktion ist. Sie können daher die Helix aus einer der vorigen Lektionen erneut öffnen und die Funktion darauf anwenden.

    In einem letzten Schritt steuern Sie das Radienverhältnis über einen benutzerdefinierten Parameter. Zu diesem Zweck müssen Sie eine neue Eingabe für die Funktion erstellen und den Teiler 20 durch einen Parameter ersetzen.

    1. Aktualisieren Sie die Definition von sphereByZ wie folgt:

    2. Aktualisieren Sie den untergeordneten Codeblock, indem Sie der Eingabe eine Verhältnisvariable hinzufügen: sphereByZ(Pt,ratio);. Verbinden Sie einen Schieberegler mit der neu erstellten Code Block-Eingabe und ändern Sie die Größe der Radien anhand des Radienverhältnisses.

    file-download
    30KB
    Functions_SphereByZ.dyn
    arrow-up-right-from-squareOpen

    Python und Revit

    hashtag
    Python und Revit

    Nachdem im vorigen Abschnitt die Verwendung von Python-Skripts in Dynamo gezeigt wurde, erhalten Sie hier eine Einführung zur Einbindung von Revit-Bibliotheken in die Skriptumgebung. Rufen Sie sich kurz ins Gedächtnis zurück, dass wir Python Standard und unsere Dynamo-Core-Blöcke mithilfe der ersten vier Zeilen im folgenden Codeabschnitt importiert haben. Um die Blöcke, Elemente und die Dokumentenverwaltung von Revit zu importieren, sind lediglich einige weitere Zeilen erforderlich:

    Dadurch erhalten Sie Zugriff auf die Revit-API und können benutzerdefinierte Skripte für beliebige Revit-Aufgaben erstellen. Die Kombination der visuellen Programmierung mit der Skripterstellung in der Revit-API bringt erhebliche Verbesserungen für die Zusammenarbeit und die Entwicklung von Werkzeugen mit sich. So könnten beispielsweise ein BIM-Manager und ein Schemaplanentwickler gemeinsam am selben Diagramm arbeiten. Bei dieser Zusammenarbeit können sie sowohl den Entwurf als auch die Realisierung des Modells verbessern.

    hashtag
    Plattformspezifische APIs

    Mit dem Dynamo-Projekt ist beabsichtigt, die Möglichkeiten der Plattformimplementierung zu erweitern. Da Dynamo nach und nach weitere Programme in seine Palette aufnimmt, erhalten Benutzer Zugriff auf plattformspezifische APIs aus der Python-Skriptumgebung. In diesem Abschnitt wird ein Fallbeispiel für Revit behandelt. Zukünftig sollen jedoch weitere Kapitel mit umfassenden Lernprogrammen zur Skripterstellung für andere Plattformen bereitgestellt werden. Darüber hinaus stehen jetzt zahlreiche -Bibliotheken zur Verfügung, die Sie in Dynamo importieren können.

    Die folgenden Beispiele zeigen Möglichkeiten zur Implementierung Revit-spezifischer Vorgänge aus Dynamo mit Python. Eine genauere Beschreibung der Beziehung zwischen Python einerseits und Dynamo und Revit andererseits finden Sie auf der . Eine andere nützliche Ressource für Python und Revit ist das -Projekt.

    hashtag
    Übung 1

    Erstellen Sie ein neues Revit-Projekt.

    Laden Sie die Beispieldatei herunter, indem Sie auf den folgenden Link klicken.

    Eine vollständige Liste der Beispieldateien finden Sie im Anhang.

    In diesen Übungen lernen Sie die grundlegenden Python-Skripts in Dynamo für Revit kennen. Dabei liegt das Hauptaugenmerk auf der Verarbeitung von Revit-Dateien und -Elementen sowie der Kommunikation zwischen Revit und Dynamo.

    Dies ist eine einfache Methode zum Abrufen von doc, uiapp und app für die mit der Dynamo-Sitzung verknüpfte Revit-Datei. Programmierern, die zuvor bereits in der Revit-API gearbeitet haben, fallen eventuell die Einträge in der Liste des Watch-Blocks auf. Falls diese Einträge ungewohnt wirken, besteht kein Grund zur Beunruhigung. In den weiteren Übungen werden andere Beispiele verwendet.

    Der folgende Code zeigt, wie Sie die Revit-Dienste importieren und die Dokumentdaten in Dynamo abrufen können.

    Werfen Sie einen Blick auf den Python-Block in Dynamo. Sie finden den Code auch unten:

    hashtag
    Übung 2

    Laden Sie die Beispieldatei herunter, indem Sie auf den folgenden Link klicken.

    Eine vollständige Liste der Beispieldateien finden Sie im Anhang.

    In dieser Übung erstellen Sie mithilfe des Python-Blocks von Dynamo eine einfache Modellkurve in Revit.

    Beginnen Sie, indem Sie in Revit eine neue Entwurfskörperfamilie erstellen.

    Öffnen Sie den Ordner Conceptual Mass, und verwenden Sie die Vorlagendatei Metric Mass.rft.

    Verwenden Sie in Revit den Tastaturbefehl un, um die Einstellungen für Projekteinheiten aufzurufen, und ändern Sie die Längeneinheit in Meter.

    Starten Sie Dynamo und erstellen Sie die Gruppe von Blöcken in der Abbildung unten. Sie erstellen zunächst mithilfe von Dynamo-Blöcken zwei Referenzpunkte in Revit.

    1. Erstellen Sie einen Codeblock mit dem Wert "0;".

    2. Verbinden Sie diesen Wert mit den x-, y- und z-Eingaben eines ReferencePoint.ByCoordinates-Blocks.

    Werfen Sie einen Blick auf den Python-Block in Dynamo. Den vollständigen Code finden Sie unten.

    1. System.Array: Für Revit wird eine Systemreihe (anstelle einer Python-Liste) benötigt. Hierfür genügt eine weitere Codezeile. Indem Sie sorgfältig auf die Argumenttypen achten, erleichtern Sie jedoch die Python-Programmierung in Revit.

    Sie haben in Dynamo zwei Referenzpunkte erstellt und diese mithilfe von Python mit einer Linie verbunden. In der nächsten Übung führen Sie dies weiter.

    hashtag
    Übung 3

    Laden Sie die Beispieldatei herunter, indem Sie auf den folgenden Link klicken.

    Eine vollständige Liste der Beispieldateien finden Sie im Anhang.

    Diese Übung ist relativ einfach, macht jedoch die Verbindung von Daten und Geometrie zwischen Revit und Dynamo – in beiden Richtungen – deutlich. Öffnen Sie zuerst Revit-StructuralFraming.rvt. Starten Sie anschließend Dynamo und öffnen Sie die Datei Revit-StructuralFraming.dyn.

    Diese Datei ist denkbar einfach. Sie umfasst zwei auf Ebene 1 und Ebene 2 gezeichnete Referenzkurven. Diese Kurven sollen in Dynamo übernommen werden, wobei eine Direktverknüpfung bestehen bleibt.

    Diese Datei enthält eine Gruppe von Blöcken, die mit den fünf Eingaben eines Python-Blocks verbunden sind.

    1. Select Model Element-Blöcke: Klicken Sie jeweils auf die Schaltfläche Auswählen und wählen Sie die zugehörige Kurve in Revit aus.

    2. Code Block: Geben Sie die Syntax 0..1..#x;, ein und verbinden Sie einen Integer Slider mit Werten zwischen 0 und 20 mit der x-Eingabe. Dadurch wird die Anzahl der Träger gesteuert, die zwischen den beiden Kurven gezeichnet werden sollen.

    Dieser Code in Python ist etwas komplexer, aus den darin enthaltenen Kommentaren geht jedoch hervor, wie der Prozess abläuft.

    In Revit wird eine Reihe von Trägern zwischen den beiden Kurven als Tragwerkselemente angezeigt. Anmerkung: Dies ist kein realistisches Beispiel. Die Tragwerkselemente sind nur als Beispiele für aus Dynamo erstellte native Revit-Exemplare.

    In Dynamo werden die Ergebnisse ebenfalls angezeigt. Die Träger im Watch3D-Block verweisen auf die aus den Revit-Elementen abgefragte Geometrie.

    Dabei werden Daten aus der Revit-Umgebung für die Dynamo-Umgebung konvertiert. Zusammenfassung: Der Prozess läuft wie folgt ab:

    1. Wählen Sie das Revit-Element aus.

    2. Konvertieren Sie das Revit-Element in eine Dynamo-Kurve.

    3. Unterteilen Sie die Dynamo-Kurve in eine Folge von Dynamo-Punkten.

    Dies mag etwas umständlich erscheinen. Das Skript erleichtert den Vorgang jedoch erheblich: Sie müssen jetzt lediglich die Kurve in Revit bearbeiten und den Solver erneut ausführen. (Es ist möglich, dass Sie dabei die bisherigen Träger löschen müssen.) Dies liegt daran, dass wir die Träger in Python platzieren und dadurch die Zuordnung der OOTB-Blöcke auflösen.

    Werden die Referenzkurven in Revit aktualisiert, erhalten Sie eine neue Reihe von Trägern.

    def sphereByZ(inputPt)
    {
    
    };
    def sphereByZ(inputPt,radiusRatio)
    {
    //get Z Value, ise ot to drive radius of sphere
    sphereRadius=inputPt.Z;
    };
    sphereByZ(Pt)
    def sphereByZ(inputPt,radiusRatio)
    {
    //get Z Value, use it to drive radius of sphere
    sphereRadius=inputPt.Z/radiusRatio;
    //Define Sphere Geometry
    sphere=Sphere.ByCenterPointRadius(inputPt,sphereRadius);
    //Define output for function
    return sphere;
    };
    /*This is a multi-line comment,
    which continues for
    multiple lines*/
    def FunctionName(in1,in2)
    {
    //This is a comment
    sum = in1+in2;
    return sum;
    };
    FunctionName(in1,in2);
    import sys
    import clr
    clr.AddReference('ProtoGeometry')
    from Autodesk.DesignScript.Geometry import *
    
    # Import RevitNodes
    clr.AddReference("RevitNodes")
    import Revit
    
    # Import Revit elements
    from Revit.Elements import *
    
    # Import DocumentManager
    clr.AddReference("RevitServices")
    import RevitServices
    from RevitServices.Persistence import DocumentManager
    
    import System
    Erstellen Sie drei Schieberegler mit dem Bereich zwischen -100 und 100 und der Schrittgröße 1.
  • Verbinden Sie die Schieberegler jeweils mit einem ReferencePoint.ByCoordinates-Block.

  • Fügen Sie einen Python-Block im Arbeitsbereich hinzu, klicken Sie auf die Schaltfläche +, um eine weitere Eingabe hinzuzufügen, und verbinden Sie die beiden Referenzpunkte mit den Eingaben. Öffnen Sie den Python-Block.

  • Structural Framing Types: Wählen Sie hier den vorgegebenen W12x26-Träger aus der Dropdown-Liste.
  • Levels: Wählen Sie "Level 1".

  • Erstellen Sie Dynamo-Linien mithilfe der Dynamo-Punkte zwischen den beiden Kurven.
  • Erstellen Sie Revit-Träger durch Referenzieren der Dynamo-Linien.

  • Geben Sie Dynamo-Oberflächen durch Abfragen der Geometrie der Revit-Träger aus.

  • IronPythonarrow-up-right
    Wiki-Seite zu Dynamoarrow-up-right
    Revit Python Shellarrow-up-right
    file-download
    2KB
    Revit-Doc.dyn
    arrow-up-right-from-squareOpen
    file-download
    10KB
    Revit-ReferenceCurve.dyn
    arrow-up-right-from-squareOpen
    file-archive
    3MB
    Revit-StructuralFraming.zip
    archive
    arrow-up-right-from-squareOpen
    # Load the Python Standard and DesignScript Libraries
    import sys
    import clr
    
    #Import DocumentManager
    clr.AddReference("RevitServices")
    import RevitServices
    from RevitServices.Persistence import DocumentManager
    
    #Place your code below this line
    doc = DocumentManager.Instance.CurrentDBDocument
    uiapp = DocumentManager.Instance.CurrentUIApplication
    app = uiapp.Application
    
    #Assign your output to the OUT variable
    OUT = [doc,uiapp,app]
    import sys
    import clr
    
    # Import RevitNodes
    clr.AddReference("RevitNodes")
    import Revit
    #Import Revit elements
    from Revit.Elements import *
    import System
    
    #define inputs
    startRefPt = IN[0]
    endRefPt = IN[1]
    
    #define system array to match with required inputs
    refPtArray = System.Array[ReferencePoint]([startRefPt, endRefPt])
    
    #create curve by reference points in Revit
    OUT = CurveByPoints.ByReferencePoints(refPtArray)
    import clr
    #import Dynamo Geometry
    clr.AddReference('ProtoGeometry')
    from Autodesk.DesignScript.Geometry import *
    # Import RevitNodes
    clr.AddReference("RevitNodes")
    import Revit
    # Import Revit elements
    from Revit.Elements import *
    import System
    
    #Query Revit elements and convert them to Dynamo Curves
    crvA=IN[0].Curves[0]
    crvB=IN[1].Curves[0]
    
    #Define input Parameters
    framingType=IN[3]
    designLevel=IN[4]
    
    #Define "out" as a list
    OUT=[]
    
    for val in IN[2]:
    	#Define Dynamo Points on each curve
    	ptA=Curve.PointAtParameter(crvA,val)
    	ptB=Curve.PointAtParameter(crvB,val)
    	#Create Dynamo line
    	beamCrv=Line.ByStartPointEndPoint(ptA,ptB)
    	#create Revit Element from Dynamo Curves
    	beam = StructuralFraming.BeamByCurve(beamCrv,designLevel,framingType)
    	#convert Revit Element into list of Dynamo Surfaces
    	OUT.append(beam.Faces)

    Python-Blöcke

    Wozu dient die Textprogrammierung in der visuellen Programmierumgebung von Dynamo? Visuelle Programmierung bietet viele Vorteile. Sie ermöglicht es, in einer intuitiven visuellen Oberfläche Programme zu entwickeln, ohne eine spezielle Syntax zu erlernen. Visuelle Programme können jedoch recht unübersichtlich werden und enthalten zuweilen nicht genügend Funktionalität. So stehen in Python beispielsweise wesentlich praktischere Methoden zum Schreiben von Bedingungsanweisungen (if/then) und für Schleifen zur Verfügung. Python ist ein leistungsstarkes Werkzeug, das das Funktionsspektrum von Dynamo erweitern und Ihnen die Möglichkeit geben kann, eine große Gruppe von Blöcken durch einige wenige präzise Codezeilen zu ersetzen.

    Visuelles Programm:

    Textprogramm:

    hashtag
    Der Python-Block

    Python-Blöcke sind genau wie Codeblöcke eine Scripting-Oberfläche innerhalb einer Umgebung für die visuelle Programmierung. Der Python-Block befindet sich in der Bibliothek unter Skript > Editor > Python Script.

    Durch Doppelklicken auf den Block wird der Python-Skript-Editor geöffnet. (Sie können auch mit der rechten Maustaste auf den Block klicken und Bearbeiten … auswählen.) Oben auf dem Bildschirm befindet sich vorgegebener Text, der es Ihnen erleichtern soll, die benötigten Bibliotheken zu referenzieren. Eingaben werden in der IN-Reihe gespeichert. Werte werden durch Zuweisung zur OUT-Variablen an Dynamo zurückgegeben.

    In der Autodesk.DesignScript.Geometry-Bibliothek können Sie Punktnotation ähnlich wie in Codeblöcken verwenden. Weitere Informationen zur Dynamo-Syntax finden Sie unter sowie im . (Um dieses PDF-Dokument herunterzuladen, klicken Sie mit der rechten Maustaste auf den Link und wählen Link speichern unter... aus). Wenn Sie einen Geometrietyp, z. B. 'Point.' eingeben, wird eine Liste mit den Methoden zum Erstellen und Abfragen von Punkten angezeigt.

    Zu den Methoden gehören Konstruktoren, wie ByCoordinates, Aktionen wie Add und Abfragen wie X-, Y- und Z-Koordinaten.

    hashtag
    Übung: Erstellen eines benutzerdefinierten Blocks mit Python Script zum Erstellen von Mustern aus einem Volumenkörpermodul

    hashtag
    Teil I: Einrichten von Python Script

    Laden Sie die Beispieldatei herunter, indem Sie auf den folgenden Link klicken.

    Eine vollständige Liste der Beispieldateien finden Sie im Anhang.

    In diesem Beispiel schreiben Sie ein Python-Skript zum Erstellen von Mustern aus einem Körpermodul und wandeln das Skript in einen benutzerdefinierten Block um. Zuerst erstellen Sie das Körpermodul mithilfe von Dynamo-Blöcken.

    1. Rectangle.ByWidthLength: Erstellen Sie ein Rechteck, das als Basis für den Körper verwendet wird.

    2. Surface.ByPatch: Verbinden Sie das Rechteck mit der closedCurve-Eingabe, um die untere Oberfläche zu erstellen.

    1. Geometry.Translate: Verbinden Sie das Rechteck mit der geometry-Eingabe, um es nach oben zu verschieben, wobei Sie mithilfe eines Codeblocks die allgemeine Dicke des Körpers festlegen.

    2. Polygon.Points: Fragen Sie die Eckpunkte des verschobenen Rechtecks ab.

    3. Geometry.Translate

    Damit haben Sie die obere und untere Oberfläche erstellt. Erstellen Sie jetzt durch eine Erhebung zwischen den beiden Profilen die Seiten des Körpers.

    1. List.Create: Verbinden Sie das Rechteck unten und das Polygon oben mit den index-Eingaben.

    2. Surface.ByLoft: Erstellen Sie über eine Erhebung die Seiten des Körpers.

    3. List.Create: Verbinden Sie die obere und untere sowie die seitlichen Oberflächen mit den index-Eingaben, um eine Liste der Oberflächen zu erhalten.

    Damit haben Sie den Körper erstellt. Fügen Sie jetzt einen Block für das Python-Skript in den Arbeitsbereich ein.

    1. Um dem Block weitere Eingaben hinzuzufügen, klicken Sie auf das +-Symbol im Block. Die Eingaben erhalten die Namen IN[0], IN[1] usw., um anzuzeigen, dass sie für die Einträge einer Liste stehen.

    Sie beginnen, indem Sie die Ein- und Ausgaben definieren. Doppelklicken Sie auf den Block, um den Python-Editor zu öffnen. Halten Sie sich an den unten stehenden Code, um den Code im Editor zu ändern.

    Dieser Code wird im weiteren Verlauf der Übung leichter verständlich. Als Nächstes müssen Sie überlegen, welche Informationen Sie zum Erstellen einer Reihe aus dem Körpermodul benötigen. Als Erstes müssen Sie die Maße des Körpers kennen, um die Entfernung für die Verschiebung zu ermitteln. Wegen eines Fehlers bei Begrenzungsrahmen müssen Sie diesen anhand der Kurvengeometrie der Kanten erstellen.

    Werfen Sie einen Blick auf den Python-Block in Dynamo. Dieselbe Syntax wie in den Titeln der Blöcke in Dynamo wird auch hier verwendet. Sehen Sie sich den kommentierten Code unten an.

    Da die Körpermodule sowohl verschoben als auch gedreht werden sollen, verwenden Sie hier die Geometry.Transform-Operation. Wenn Sie den Geometry.Transform-Block genauer betrachten, sehen Sie, dass für die Transformation des Körpers ein Quell- und ein Zielkoordinatensystem benötigt werden. Die Quelle ist das Koordinatensystem, das den Kontext für den Ausgangskörper bildet, während als Ziel ein eigenes Koordinatensystem für jedes Modul in der Reihe verwendet wird. Das bedeutet, dass Sie die x- und y-Werte in einer Schleife verarbeiten müssen, um das Koordinatensystem jedes Mal auf andere Weise zu transformieren.

    Klicken Sie auf Ausführen, und speichern Sie dann den Code. Verbinden Sie den Python-Block wie folgt mit dem vorhandenen Skript.

    1. Verbinden Sie die Ausgabe aus Solid.ByJoinedSurfaces als erste Eingabe für den Python-Block, und definieren Sie die anderen Eingaben mithilfe eines Codeblocks.

    2. Erstellen Sie einen Topology.Edges-Block, und verwenden Sie die Ausgabe aus dem Python-Block als Eingabe.

    3. Erstellen Sie abschließend einen Edge.CurveGeometry

    Ändern Sie den Wert für die Ausgangszahl, um verschiedene Muster zu erstellen. Indem Sie die Parameter des Körpermoduls selbst ändern, erzielen Sie ebenfalls unterschiedliche Wirkungen.

    hashtag
    Teil II: Umwandeln des Python Script-Blocks in einen benutzerdefinierten Block

    Damit haben Sie ein nützliches Python-Skript erstellt. Speichern Sie dieses jetzt als benutzerdefinierten Block. Wählen Sie den Python Script-Block aus, klicken Sie mit der rechten Maustaste auf den Arbeitsbereich, und wählen Sie Benutzerdefinierten Block erstellen aus.

    Weisen Sie einen Namen, eine Beschreibung und eine Kategorie zu.

    Dadurch wird ein neuer Arbeitsbereich geöffnet, in dem Sie den benutzerdefinierten Block bearbeiten können.

    1. Eingabe-Blöcke: Geben Sie den Eingaben aussagekräftigere Namen und fügen Sie Datentypen und Vorgabewerte hinzu.

    2. Ausgabe-Blöcke: Ändert den Namen der Ausgabe.

    Speichern Sie den Block als DYF-Datei. Nun sollten Sie sehen, dass der benutzerdefinierte Block die gerade vorgenommenen Änderungen widerspiegelt.

    import clr
    clr.AddReference('ProtoGeometry')
    from Autodesk.DesignScript.Geometry import *
    
    solid = IN[0]
    seed = IN[1]
    xCount = IN[2]
    yCount = IN[3]
    
    solids = []
    
    yDist = solid.BoundingBox.MaxPoint.Y-solid.BoundingBox.MinPoint.Y
    xDist = solid.BoundingBox.MaxPoint.X-solid.BoundingBox.MinPoint.X
    
    for i in xRange:
    	for j in yRange:
    		fromCoord = solid.ContextCoordinateSystem
    		toCoord = fromCoord.Rotate(solid.ContextCoordinateSystem.Origin,Vector.ByCoordinates(0,0,1),(90*(i+j%val)))
    		vec = Vector.ByCoordinates((xDist*i),(yDist*j),0)
    		toCoord = toCoord.Translate(vec)
    		solids.append(solid.Transform(fromCoord,toCoord))
    
    OUT = solids
    : Erstellen Sie mithilfe eines Codeblocks eine Liste mit vier Werten für die vier Punkte, wobei Sie eine Ecke des Körpers nach oben verschieben.
  • Polygon.ByPoints: Erstellen Sie das obere Polygon aus den verschobenen Punkten erneut.

  • Surface.ByPatch: Schließen Sie das Polygon, um die obere Oberfläche zu erstellen.

  • Solid.ByJoinedSurfaces: Verbinden Sie die Flächen, um das Körpermodul zu erstellen.

  • -Block, und verwenden Sie die Ausgabe von Topology.Edges als Eingabe.
    https://github.com/DynamoDS/DynamoPrimerNew/blob/master-deu/coding-in-dynamo/7_code-blocks-and-design-script/7-2_design-script-syntax.md
    DesignScript-Handbucharrow-up-right
    file-download
    35KB
    Python_Custom-Node.dyn
    arrow-up-right-from-squareOpen
    # Load the Python Standard and DesignScript Libraries
    import sys
    import clr
    clr.AddReference('ProtoGeometry')
    from Autodesk.DesignScript.Geometry import *
    
    # The inputs to this node will be stored as a list in the IN variables.
    #The solid module to be arrayed
    solid = IN[0]
    
    #A Number that determines which rotation pattern to use
    seed = IN[1]
    
    #The number of solids to array in the X and Y axes
    xCount = IN[2]
    yCount = IN[3]
    
    #Create an empty list for the arrayed solids
    solids = []
    
    # Place your code below this line
    
    
    # Assign your output to the OUT variable.
    OUT = solids
    # Load the Python Standard and DesignScript Libraries
    import sys
    import clr
    clr.AddReference('ProtoGeometry')
    from Autodesk.DesignScript.Geometry import *
    
    # The inputs to this node will be stored as a list in the IN variables.
    #The solid module to be arrayed
    solid = IN[0]
    
    #A Number that determines which rotation pattern to use
    seed = IN[1]
    
    #The number of solids to array in the X and Y axes
    xCount = IN[2]
    yCount = IN[3]
    
    #Create an empty list for the arrayed solids
    solids = []
    #Create an empty list for the edge curves
    crvs = []
    
    # Place your code below this line
    #Loop through edges an append corresponding curve geometry to the list
    for edge in solid.Edges:
        crvs.append(edge.CurveGeometry)
    
    #Get the bounding box of the curves
    bbox = BoundingBox.ByGeometry(crvs)
    
    #Get the x and y translation distance based on the bounding box
    yDist = bbox.MaxPoint.Y-bbox.MinPoint.Y
    xDist = bbox.MaxPoint.X-bbox.MinPoint.X
    
    # Assign your output to the OUT variable.
    OUT = solids
    # Load the Python Standard and DesignScript Libraries
    import sys
    import clr
    clr.AddReference('ProtoGeometry')
    from Autodesk.DesignScript.Geometry import *
    
    # The inputs to this node will be stored as a list in the IN variables.
    #The solid module to be arrayed
    solid = IN[0]
    
    #A Number that determines which rotation pattern to use
    seed = IN[1]
    
    #The number of solids to array in the X and Y axes
    xCount = IN[2]
    yCount = IN[3]
    
    #Create an empty list for the arrayed solids
    solids = []
    #Create an empty list for the edge curves
    crvs = []
    
    # Place your code below this line
    #Loop through edges an append corresponding curve geometry to the list
    for edge in solid.Edges:
        crvs.append(edge.CurveGeometry)
    
    #Get the bounding box of the curves
    bbox = BoundingBox.ByGeometry(crvs)
    
    #Get the x and y translation distance based on the bounding box
    yDist = bbox.MaxPoint.Y-bbox.MinPoint.Y
    xDist = bbox.MaxPoint.X-bbox.MinPoint.X
    
    #Get the source coordinate system
    fromCoord = solid.ContextCoordinateSystem
    
    #Loop through x and y
    for i in range(xCount):
        for j in range(yCount):
            #Rotate and translate the coordinate system
            toCoord = fromCoord.Rotate(solid.ContextCoordinateSystem.Origin, Vector.ByCoordinates(0,0,1), (90*(i+j%seed)))
            vec = Vector.ByCoordinates((xDist*i),(yDist*j),0)
            toCoord = toCoord.Translate(vec)
            #Transform the solid from the source coord syste, to the target coord system and append to the list
            solids.append(solid.Transform(fromCoord,toCoord))
    
    # Assign your output to the OUT variable.
    OUT = solids

    Schnittpunkt und Stutzen

    Viele der bisherigen Beispiele bezogen sich auf die Konstruktion einer höherdimensionalen Geometrie aus niedrigerdimensionalen Objekten. Mit Intersection-Methoden können diese höherdimensionalen Geometrien Objekte mit niedrigerer Dimension generieren, während die Befehle Trim und SelectTrim es ermöglichen, geometrische Formen mit Skripts stark zu ändern, nachdem sie erstellt wurden.

    Die Methode Intersect ist für alle Geometrieobjekte in Dynamo definiert. Das bedeutet, dass theoretisch jedes Geometrieobjekt mit einem beliebigen anderen geschnitten werden kann. Natürlich sind einige Überschneidungen nicht von Bedeutung, wie z. B. Schnittpunkte von Punkten, da das resultierende Objekt immer der Eingabepunkt selbst ist. Andere mögliche Kombinationen von Überschneidungen zwischen Objekten sind in der folgenden Tabelle beschrieben. Die folgende Tabelle zeigt die Ergebnisse verschiedener Überschneidungsoperationen:

    hashtag
    Intersect

    Das folgende sehr einfache Beispiel zeigt die Überschneidung einer Ebene mit einer NurbsSurface. Die Überschneidung erzeugt ein NurbsCurve-Array, das wie jede andere NurbsCurve verwendet werden kann.

    Die Methode Trim ähnelt der Methode Intersect insofern, dass sie ebenfalls für nahezu jedes Geometrieobjekt definiert ist. Es bestehen jedoch für Trim weitaus mehr Einschränkungen als für Intersect.

    hashtag
    Trim

    Erwähnenswert bei den Trim-Methoden ist die Anforderung eines Select-Punkts, der bestimmt, welche Geometrie verworfen und welche Teile beibehalten werden sollen. Dynamo sucht und verwirft die gestutzte Geometrie, die dem ausgewählten Punkt am nächsten liegt.

    Ebene

    Kurve

    Punkt

    Kurve

    Kurve

    Volumenkörper

    Oberfläche

    Kurve

    Kurve

    Volumenkörper

    Ja

    Nein

    No

    Oberfläche

    -

    Ja

    Ja

    Ja

    Ja

    Volumenkörper

    -

    -

    Ja

    Ja

    Ja

    Mit:

    Oberfläche

    Kurve

    Ebene

    Volumenkörper

    Oberfläche

    Kurve

    Punkt

    Punkt, Kurve

    Oberfläche

    Kurve

    Punkt

    Punkt

    Punkt

    Verwendung: Punkt

    Kurve

    Ebene

    Oberfläche

    Volumenkörper

    Auf: Kurve

    Ja

    Nein

    Nein

    Nein

    No

    Polygon

    -

    Kurve

    Nein

    // python_points_5 is a set of Points generated with
    // a Python script found in Chapter 12, Section 10
    
    surf = NurbsSurface.ByPoints(python_points_5, 3, 3);
    
    WCS = CoordinateSystem.Identity();
    
    pl = Plane.ByOriginNormal(WCS.Origin.Translate(0, 0,
        0.5), WCS.ZAxis);
    
    // intersect surface, generating three closed curves
    crvs = surf.Intersect(pl);
    
    crvs_moved = crvs.Translate(0, 0, 10);
    // python_points_5 is a set of Points generated with
    // a Python script found in Chapter 12, Section 10
    
    surf = NurbsSurface.ByPoints(python_points_5, 3, 3);
    
    tool_pts = Point.ByCoordinates((-10..20..10)<1>,
        (-10..20..10)<2>, 1);
    
    tool = NurbsSurface.ByPoints(tool_pts);
    
    pick_point = Point.ByCoordinates(8, 1, 3);
    
    result = surf.Trim(tool, pick_point);

    Änderungen der Sprache

    Der Abschnitt Änderungen der Sprache bietet einen Überblick über die Aktualisierungen und Änderungen an der Sprache in den einzelnen Dynamo-Versionen. Diese Änderungen können sich auf die Funktionalität, Leistung und Verwendung auswirken. Dieser Leitfaden hilft Benutzern zu verstehen, wann und warum sie diese Aktualisierungen übernehmen sollten.

    hashtag
    Änderungen der Sprache in Dynamo 2.0

    1. Änderung der list@level-Syntax von "@-1" in "@L1"

    • Neue Syntax für list@level, sodass list@L1 anstelle von list@-1 verwendet wird

    • Grund: Benutzertests zeigen, dass die neue Anpassung der Code-Syntax an die Vorschau/Benutzeroberfläche besser verständlich ist.

    1. Implementierung der Int- und Double-Typen in TS, sodass sie den Dynamo-Typen entsprechen

    2. Unzulässigkeit überlasteter Funktionen, bei denen sich die Argumente nur durch die Kardinalität unterscheiden

    • Alte Diagramme, bei denen Überlastungen verwendet werden, die entfernt wurden, sollten vorgabemäßig die Überlastungen mit höherem Rang verwenden.

    • Grund: Beseitigung von Unklarheiten darüber, welche Funktion ausgeführt wird

    1. Deaktivierung der Array-Hochstufung mit Replikationsanleitungen

    2. Festlegen von Variablen in imperativen Blöcken als lokal für den imperativen Blockbereich

    • Variablenwerte, die innerhalb imperativer Codeblöcke definiert sind, werden durch Änderungen in imperativen Blöcken, die diese referenzieren, nicht geändert.

    1. Festlegen von Variablen als unveränderlich, um die assoziative Aktualisierung in Codeblock-Block zu deaktivieren

    2. Kompilierung aller Benutzeroberflächen-Blöcke zu statischen Methoden

    3. Unterstützung von Rückgabeanweisungen ohne Zuweisung

    • "=" wird weder in Funktionsdefinitionen noch in imperativem Code benötigt.

    1. Migration von alten Methodennamen in CBNs

    • Viele Blöcke wurden umbenannt, um die Lesbarkeit und Platzierung in der Benutzeroberfläche des Bibliotheks-Browsers zu verbessern.

    1. Liste als Wörterbuchbereinigung


    Bekannte Probleme:

    • Namensbereichskonflikte in imperativen Blöcken führen dazu, dass unerwartete Eingabeanschlüsse angezeigt werden. Weitere Informationen finden Sie unter . Um dies zu umgehen, definieren Sie die Funktion wie folgt außerhalb des imperativen Blocks:

    hashtag
    Erläuterungen zu den Änderungen der Sprache in Dynamo 2.0

    Für die Version Dynamo 2.0 wurden eine Reihe von Verbesserungen an der Sprache vorgenommen. Der Hauptgrund dafür war die Vereinfachung der Sprache. Der Schwerpunkt liegt darauf, DesignScript überschaubarer und benutzerfreundlicher und somit leistungsstärker und flexibler zu gestalten, sodass die Verständlichkeit für den Endbenutzer verbessert wird.

    Im Folgenden werden die Änderungen in Version 2.0 erläutert:

    • Vereinfachte List@Level-Syntax

    • Überlastete Methoden mit Parametern, die sich nur durch den Rang unterscheiden, sind unzulässig

    • Kompilierung aller Benutzeroberflächen-Blöcke zu statischen Methoden

    hashtag
    1. Vereinfachte List@Level-Syntax

    Neue Syntax für list@level, sodass list@L1 anstelle von list@-1 verwendet wird

    hashtag
    2. Überlastete Funktionen mit Parametern, die sich nur durch den Rang unterscheiden, sind unzulässig

    Überlastete Funktionen sind aus mehreren Gründen problematisch:

    • Eine überlastete Funktion, die durch einen Benutzeroberflächen-Block im Diagramm angegeben wird, enthält möglicherweise nicht dieselbe Überlastung, die zur Laufzeit ausgeführt wird.

    • Die Methodenauflösung ist teuer und funktioniert nicht gut für überlastete Funktionen.

    • Das Replikationsverhalten für überlastete Funktionen ist schwer nachzuvollziehen.

    Nehmen wir BoundingBox.ByGeometry als Beispiel (es gab zwei überlastete Funktionen in älteren Versionen von Dynamo, eine, die ein einzelnes Wertargument, und eine andere, die eine Liste von Geometrien als Argument akzeptierte):

    Wenn der Benutzer den ersten Block im Ansichtsbereich abgelegt und eine Liste von Geometrien verbunden hat, erwartet er, dass die Replikation einsetzt, dies findet jedoch nie statt, da zur Laufzeit stattdessen die zweite Überlastung aufgerufen wird, wie hier gezeigt:

    Aus diesem Grund sind in Version 2.0 überlastete Funktionen nicht zulässig, die sich nur in der Parameterkardinalität unterscheiden. Dies bedeutet, dass bei überlasteten Funktionen, die über die gleiche Anzahl und die gleichen Typen von Parametern verfügen, aber einen oder mehrere Parameter aufweisen, die sich nur im Rang unterscheiden, immer die zuerst definierte Überlastung verwendet wird, während der Rest vom Compiler verworfen wird. Der Hauptvorteil liegt in der Vereinfachung der Methodenauflösungslogik, da ein schneller Pfad zur Auswahl von Funktionskandidaten zur Verfügung steht.

    In der Geometriebibliothek für Version 2.0 wurde die erste Überlastung im BoundingBox.ByGeometry-Beispiel als veraltet markiert und die zweite beibehalten. Wenn der Block also repliziert werden soll, d. h. im Kontext des ersten Blocks verwendet werden soll, muss er mit der kürzesten (oder längsten) Vergitterungsoption oder in einem Codeblock mit Replikationsanleitungen verwendet werden:

    In diesem Beispiel sehen wir, dass der Block mit höherem Rang sowohl in einem replizierten als auch in einem nicht replizierten Aufruf verwendet werden kann und daher immer einer Überlastung mit niedrigerem Rang vorgezogen wird. Als Faustregel wird daher Blockautoren immer empfohlen, Überlastungen mit niedrigerem Rang zugunsten von Methoden mit höherem Rang unberücksichtigt zu lassen, sodass der DesignScript-Compiler immer die Methode mit höherem Rang als die erste und einzige Methode aufruft, die gefunden werden kann.

    hashtag
    Beispiele:

    Im folgenden Beispiel wurden zwei Überlastungen von Funktion foo definiert. In Version 1.x ist nicht eindeutig klar, welche Überlastung zur Laufzeit ausgeführt wird. Der Benutzer erwartet möglicherweise, dass die zweite Überlastung foo(a:int, b:int) ausgeführt wird. In diesem Fall wird erwartet, dass die Methode dreimal repliziert wird und den Wert 10 dreimal zurückgibt. In Wirklichkeit wird stattdessen ein einzelner Wert 10 zurückgegeben, da stattdessen die erste Überlastung mit dem Listenparameter aufgerufen wird.

    hashtag
    Die zweite Überlastung wird in Version 2.0 weggelassen:

    In Version 2.0 wird immer die zuerst definierte Methode den anderen vorgezogen. Es gilt das Prinzip "Wer zuerst kommt, mahlt zuerst".

    Für jeden der folgenden Fälle wird die zuerst definierte Überlastung verwendet. Beachten Sie, dass dies ausschließlich auf der Reihenfolge basiert, in der die Funktionen definiert werden, und nicht auf den Parameterrängen. Es wird jedoch empfohlen, Methoden mit höher eingestuften Parametern bei benutzerdefinierten und Zero-Touch-Blöcken zu bevorzugen.

    hashtag
    3. Kompilierung aller Benutzeroberflächen-Blöcke zu statischen Methoden

    In Dynamo 1.x wurden Benutzeroberflächen-Blöcke (Nicht-Codeblöcke) zu Instanzmethoden bzw. -eigenschaften kompiliert. So wurde z. B. der Block Point.X in pt.X und Curve.PointAtParameter in curve.PointAtParameter(param) kompiliert. Dieses Verhalten wies zwei Probleme auf:

    A. Die Funktion, die der Benutzeroberflächen-Block darstellte, war nicht immer dieselbe, die zur Laufzeit ausgeführt wurde.

    Ein typisches Beispiel ist der Block Translate. Es gibt mehrere Translate-Blöcke, die dieselbe Anzahl und die gleichen Typen von Argumenten verwenden, z. B. Geometry.Translate, Mesh.Translate und FamilyInstance.Translate. Aufgrund der Tatsache, dass Blöcke als Instanzmethoden kompiliert wurden, würde die Übergabe von FamilyInstance an einen Geometry.Translate-Block überraschenderweise immer noch funktionieren, da zur Laufzeit der Aufruf an die Translate-Instanzmethode in einer FamilyInstance weitergeleitet würde. Dies war offensichtlich irreführend für die Benutzer, da der Block nicht das tat, was erwartet wurde.

    B. Das zweite Problem war, dass Instanzmethoden nicht mit heterogenen Arrays funktionierten.

    Zur Laufzeit muss von der Ausführungs-Engine ermittelt werden, an welche Funktion weitergeleitet werden soll. Wenn es sich bei der Eingabe um eine Liste handelt, z. B. list.Translate(), gilt Folgendes: Da es teuer ist, die einzelnen Elemente in einer Liste durchzugehen und Methoden zum Typ zu suchen, würde die Methodenauflösungslogik einfach davon ausgehen, dass der Zieltyp mit dem Typ des ersten Elements identisch ist, und versuchen, die für diesen Typ definierte Methode Translate() zu suchen. Wenn also der erste Elementtyp nicht mit dem Zieltyp der Methode übereinstimmt (selbst wenn es sich um null oder eine leere Liste handelt), schlägt die gesamte Liste fehl, auch wenn andere übereinstimmende Typen in der Liste vorhanden sind.

    Wenn beispielsweise eine Listeneingabe mit den folgenden Typen [Arc, Line] an Arc.CenterPoint übergeben wird, enthält das Ergebnis wie erwartet einen Mittelpunkt für den Bogen und einen null-Wert für die Linie. Wenn die Reihenfolge jedoch umgekehrt wird, ist das gesamte Ergebnis null, da das erste Element die Methodenauflösungsprüfung nicht bestanden hat:

    hashtag
    Dynamo 1.x: Testet nur das erste Element der Eingabeliste in Bezug auf die Methodenauflösungsprüfung.

    In Version 2.0 werden diese beiden Probleme behoben, indem Benutzeroberflächen-Blöcke als statische Eigenschaften und statische Methoden kompiliert werden.

    Bei statischen Methoden ist die Methodenauflösung zur Laufzeit einfacher, und alle Elemente in der Eingabeliste werden iteriert. Beispiel:

    Die Semantik von foo.Bar() (Instanzmethode) muss auf den Typ foo prüfen und ebenso ermitteln, ob es sich um eine Liste handelt oder nicht, und sie dann mit möglichen Funktionen abgleichen. Das ist teuer. Auf der anderen Seite muss die Semantik von Foo.Bar(foo) (statische Methode) nur eine Funktion mit dem Parametertyp foo prüfen.

    In Version 2.0 geschieht Folgendes:

    • Ein Benutzeroberflächen-Eigenschaftsblock wird zu einem statischen Getter kompiliert: Die Engine generiert für jede Eigenschaft eine statische Version eines Getters. Beispiel: Ein Point.X-Block wird zu einem statischen Getter Point.get_X(pt) kompiliert. Beachten Sie, dass der statische Getter auch über seinen Alias aufgerufen werden kann: Point.X(pt) in einem Codeblock-Block.

    • Ein Benutzeroberflächen-Methodenblock wird zur statischen Version kompiliert: Die Engine generiert eine entsprechende statische Methode für den Block. Der Block Curve.PointAtParameter wird beispielsweise nicht zu curve.PointAtParameter(parameter)

    Anmerkung: Die Unterstützung von Instanzmethoden wurde mit dieser Änderung nicht entfernt, sodass vorhandene Instanzmethoden, die in CBNs wie pt.X und curve.PointAtParameter(parameter) in den obigen Beispielen verwendet werden, weiterhin funktionieren.

    Dieses Beispiel funktionierte zuvor in Version 1.x, da das Diagramm zu point.X; kompiliert wurde und die X-Eigenschaft für das Punktobjekt gefunden wurde. Jetzt in Version 2.0 schlägt es fehl, da der kompilierte Code Vector.X(point) nur einen Vector-Typ erwartet:

    hashtag
    Vorteile:

    Kohärent/verständlich: Statische Methoden beseitigen alle Unklarheiten darüber, welche Methode zur Laufzeit ausgeführt wird. Die Methode stimmt immer mit dem Benutzeroberflächen-Block überein, der in dem Diagramm verwendet wird, das der Benutzer aufrufen möchte.

    Kompatibel: Es besteht eine bessere Korrelation zwischen dem Code und dem visuellen Programm.

    Anweisend: Die Übergabe heterogener Listeneingaben an Blöcke führt jetzt zu Werten ungleich null für Typen, die vom Block akzeptiert werden, und zu Nullwerten für Typen, die den Block nicht implementieren. Die Ergebnisse sind besser vorhersagbar und geben einen besseren Hinweis darauf, welche Typen für den Block zulässig sind.

    hashtag
    Einschränkung: Nicht aufgelöste Mehrdeutigkeiten mit überlasteten Methoden

    Da Dynamo Funktionsüberlastungen im Allgemeinen unterstützt, kann es dennoch zu Verwirrungen kommen, wenn eine weitere überlastete Funktion mit derselben Anzahl von Parametern vorhanden ist. Wenn Sie im folgenden Diagramm beispielsweise einen numerischen Wert mit der direction-Eingabe von Curve.Extrude und einen Vektor mit der distance-Eingabe von Curve.Extrude verbinden, funktionieren beide Blöcke weiterhin, was unerwartet ist. In diesem Fall kann die Engine zur Laufzeit keinen Unterschied erkennen, auch wenn die Blöcke zu statischen Methoden kompiliert werden, und wählt je nach Eingabetyp eine der beiden Methoden aus.

    hashtag
    Behobene Probleme:

    Die Umstellung auf statische Methodensemantik brachte die folgenden Nebeneffekte mit sich, die hier als zugehörige Änderungen der Sprache in Version 2.0 erwähnenswert sind.

    1. Verlust des polymorphen Verhaltens:

    Betrachten wir ein Beispiel aus TSpline-Blöcken in ProtoGeometry (beachten Sie, dass TSplineTopology Werte vom Basistyp Topology übernimmt): Der Block Topology.Edges, der zuvor zur Instanzmethode object.Edges kompiliert wurde, wird jetzt zur statischen Methode Topology.Edges(object) kompiliert. Der vorherige Aufruf würde nach einem Methoden-Dispatch über den Laufzeittyp des Objekts polymorph in die abgeleitete Klassenmethode TsplineTopology.Edges aufgelöst.

    Beim neuen statischen Verhalten wurde hingegen erzwungen, dass die Basisklassenmethode Topology.Edges aufgerufen wird. Dieser Block gab daher die Edge-Objekte der Basisklasse anstelle der abgeleiteten Klassenobjekte des Typs TSplineEdge zurück.

    Dies war eine Regression, da nachgelagerte TSpline-Blöcke, die TSplineEdges erwarteten, fehlzuschlagen begannen.

    Das Problem wurde behoben, indem in der Methoden-Dispatch-Logik eine Laufzeitüberprüfung hinzugefügt wurde, um den Instanztyp anhand des Typs oder Untertyps des ersten Parameters der Methode zu überprüfen. Im Falle einer Eingabeliste haben wir den Methoden-Dispatch vereinfacht, sodass einfach nach dem Typ des ersten Elements gesucht wird. Somit war die endgültige Lösung ein Kompromiss zwischen einer teils statischen und teils dynamischen Methodensuche.

    Neues polymorphes Verhalten in Version 2.0:

    Da in diesem Fall das erste Element a ein TSpline ist, wird die abgeleitete Methode TSplineTopology.Edges zur Laufzeit aufgerufen. Als Ergebnis wird null für den Topology-Basistyp b zurückgegeben.

    Da im zweiten Fall der allgemeine Topology-Typ b das erste Element ist, wird die Topology.Edges-Basismethode aufgerufen. Da Topology.Edges auch den abgeleiteten TSplineTopology-Typ akzeptiert, gibt a als Eingabe Edges für beide Eingaben (a und b) zurück.

    2. Regressionen von der Erstellung redundanter äußerer Listen

    Es gibt einen Hauptunterschied zwischen Instanzmethoden und statischen Methoden, wenn es um das Verhalten der Replikationsanleitung geht. Bei Instanzmethoden werden Eingaben mit einzelnen Werten mit Replikationsanleitungen nicht in Listen hochgestuft, während sie bei statischen Methoden hochgestuft werden.

    Betrachten Sie das Beispiel des Blocks Surface.PointAtParameter mit Kreuzvergitterung und mit einer einzelnen surface-Eingabe sowie Arrays von u- und v-Parameterwerten. Die Instanzmethode wird kompiliert zu:

    wodurch ein 2D-Array mit Punkten entsteht.

    Die statische Methode wird kompiliert zu:

    wodurch eine 3D-Liste mit Punkten und einer redundanten äußersten Liste entsteht.

    Dieser Nebeneffekt beim Kompilieren von Benutzeroberflächen-Blöcken zu statischen Methoden kann in solchen vorhandenen Anwendungsfällen möglicherweise zu Regressionen führen. Dieses Problem wurde behoben, indem die Hochstufung einzelner Werteingaben in eine Liste bei Verwendung mit Replikationsanleitungen/Vergitterung deaktiviert wurde (siehe nächster Punkt).

    4. Deaktivierte Listenhochstufung mit Replikationsanleitungen/Vergitterung

    In Version 1.x gab es zwei Fälle, in denen einzelne Werte in Listen hochgestuft wurden:

    • Wenn Eingaben mit niedrigerem Rang an Funktionen übergeben wurden, die Eingaben mit höherem Rang erwarteten

    • Wenn Eingaben mit niedrigerem Rang an Funktionen übergeben wurden, die denselben Rang erwarteten, deren Eingabeargumente jedoch mit Replikationsanleitungen versehen waren oder Vergitterung verwendeten

    In Version 2.0 wird der letztere Fall nicht mehr unterstützt, indem die Listenhochstufung in solchen Szenarien verhindert wird.

    Im folgenden 1.x-Diagramm wurde durch eine Ebene der Replikationsanleitung für y bzw. z die Array-Hochstufung von Rang 1 für jeden Wert erzwungen, weshalb das Ergebnis den Rang 3 (jeweils 1 für x, y und z) aufwies. Stattdessen würde ein Benutzer erwarten, dass das Ergebnis Rang 1 aufweist, da es nicht offensichtlich ist, dass das Vorhandensein von Replikationsanleitungen für einzelne Werteingaben dem Ergebnis Ebenen hinzufügt.

    hashtag
    Dynamo 1.x: 3D-Liste mit Punkten

    In Version 2.0 resultiert das Vorhandensein von Replikationsanleitungen für jedes der Einzelwertargumente y und z nicht in einer Hochstufung, was dazu führt, dass die Liste dieselbe Dimension wie die eingegebene 1D-Liste für x aufweist.

    hashtag
    Dynamo 2.0: 1D-Liste mit Punkten

    Die oben erwähnte Regression, die durch die statische Methodenkompilierung mit der Generierung redundanter äußerer Listen verursacht wurde, wurde durch diese Änderung der Sprache ebenfalls behoben.

    Fahren wir mit dem obigen Beispiel fort: Wir haben gesehen, dass ein statischer Methodenaufruf wie

    in Dynamo 1.x eine 3D-Liste mit Punkten generiert hat. Dies geschah aufgrund der Hochstufung des ersten Einzelwertarguments surface in eine Liste bei Verwendung mit einer Replikationsanleitung.

    hashtag
    Dynamo 1.x: Listenhochstufung von Argumenten mit Replikationsanleitung

    In Version 2.0 wurde die Hochstufung von Einzelwertargumenten in Listen bei Verwendung mit Replikationsanleitungen oder Vergitterung deaktiviert. Nun gibt der Aufruf von

    einfach eine 2D-Liste zurück, da surface nicht hochgestuft wird.

    hashtag
    Dynamo 2.0: Listenhochstufung von Einzelwertargumenten mit Replikationsanleitung deaktiviert

    Durch diese Änderung wird nun das Hinzufügen einer redundanten Listenebene verhindert, und außerdem wird die durch den Übergang zur statischen Methodenkompilierung verursachte Regression behoben.

    hashtag
    Vorteile:

    Lesbar: Die Ergebnisse entsprechen den Erwartungen der Benutzer und sind einfacher zu verstehen.

    Kompatibel: Benutzeroberflächen-Blöcke (mit Vergitterungsoption) und CBNs mit Replikationsanleitungen liefern kompatible Ergebnisse.

    Konsistent:

    • Instanzmethoden und statische Methoden sind konsistent (Probleme mit statischer Methodensemantik behoben).

    • Blöcke mit Eingaben und Vorgabeargumenten verhalten sich konsistent (siehe unten).

    hashtag
    5. Variablen in Codeblock-Blöcken sind unveränderlich, um eine assoziative Aktualisierung zu verhindern

    DesignScript unterstützte bisher zwei Programmierparadigmen: die assoziative und die imperative Programmierung. Assoziativer Code erstellt ein Abhängigkeitsdiagramm aus Programmanweisungen, wobei Variablen voneinander abhängig sind. Das Aktualisieren einer Variablen kann Aktualisierungen für alle anderen Variablen auslösen, die von dieser Variable abhängen. Dies bedeutet, dass die Sequenz der Ausführung von Anweisungen in einem assoziativen Block nicht auf ihrer Reihenfolge, sondern auf den Abhängigkeitsbeziehungen zwischen den Variablen basiert.

    Im folgenden Beispiel lautet die Sequenz der Ausführung des Codes wie folgt: Zeilen 1 -> 2 -> 3 -> 2. Da b von a abhängig ist, springt die Ausführung bei einer Aktualisierung von a in Zeile 3 wieder zu Zeile 2, um b mit dem neuen Wert von a zu aktualisieren.

    Wenn derselbe Code hingegen in einem imperativen Kontext ausgeführt wird, werden die Anweisungen in einem linearen Ablauf von oben nach unten ausgeführt. Imperative Codeblöcke eignen sich daher für die sequenzielle Ausführung von Code-Konstrukten wie Schleifen und If-else-Bedingungen.

    hashtag
    Mehrdeutigkeiten bei assoziativer Aktualisierung:

    1. Variablen mit zyklischer Abhängigkeit:

    In bestimmten Fällen ist eine zyklische Abhängigkeit zwischen Variablen möglicherweise nicht so offensichtlich wie im folgenden Fall. In solchen Fällen, in denen der Compiler den Zyklus nicht statisch erkennen kann, kann dies zu einem unbegrenzten Laufzeitzyklus führen.

    2. Variablen, die von sich selbst abhängig sind:

    Wenn eine Variable von sich selbst abhängig ist, sollte ihr Wert bei jeder Aktualisierung akkumuliert oder auf den ursprünglichen Wert zurückgesetzt werden?

    Da der Würfel b in diesem Geometriebeispiel sowohl von sich selbst als auch vom Zylinder a abhängt, stellt sich die Frage, ob das Verschieben des Schiebereglers dazu führen soll, dass die Bohrung entlang des Blocks verschoben wird, oder dass bei jeder Aktualisierung der Position des Schiebereglers ein kumulativer Effekt erstellt wird, bei dem mehrere Löcher entlang des Pfads verteilt werden.

    3. Aktualisieren von Variableneigenschaften:

    4. Aktualisieren von Funktionen:

    Im Laufe der Zeit haben wir festgestellt, dass sich die assoziative Aktualisierung in Codeblock-Blöcken in einem blockbasierten Datenflussdiagrammkontext nicht als sinnvoll erweist. Bevor eine visuelle Programmierumgebung verfügbar war, bestand die einzige Möglichkeit zum Prüfen der Optionen darin, die Werte einiger Variablen im Programm explizit zu ändern. Ein textbasiertes Programm verfügt über den vollständigen Verlauf der Aktualisierungen einer Variablen, während in einer visuellen Programmierumgebung nur der letzte Wert einer Variablen angezeigt wird.

    Wenn sie überhaupt von einigen Benutzern verwendet wurde, geschah dies höchstwahrscheinlich unwissentlich, was mehr Schaden als Nutzen angerichtet hat. Aus diesem Grund haben wir uns in Version 2.0 entschieden, die Assoziativität bei der Verwendung von Codeblock-Blöcken auszublenden, indem wir Variablen unveränderlich gemacht haben, während wir die assoziative Aktualisierung weiterhin nur als systemeigene Funktion der DS-Engine beibehalten. Dies ist eine weitere Änderung, mit der die Skripterstellung für Benutzer vereinfacht werden soll.

    Die assoziative Aktualisierung wird in CBNs deaktiviert, indem die Neudefinition von Variablen verhindert wird:

    Listenindizierung in Codeblöcken weiterhin zulässig

    Eine Ausnahme wurde für die Listenindizierung gemacht, die in Version 2.0 mit Index-Operatorzuweisung weiterhin zulässig ist.

    Im nächsten Beispiel sehen wir, dass die Liste a initialisiert wird, aber später mit einer Index-Operatorzuweisung überschrieben werden kann, und dass alle von a abhängigen Variablen assoziativ aktualisiert werden, wie aus dem Wert c hervorgeht. Die Blockvorschau zeigt außerdem die aktualisierten Werte von a nach der Neudefinition eines oder mehrerer der zugehörigen Elemente an.

    hashtag
    6. Variablen in imperativen Blöcken gelten für den imperativen Blockbereich lokal

    Wir haben in Version 2.0 Änderungen an den imperativen Bereichsregeln vorgenommen, um komplizierte sprachübergreifende Aktualisierungsszenarien zu deaktivieren.

    In Dynamo 1.x würde die Ausführungssequenz des folgenden Skripts aus den Zeilen 1 -> 2 -> 4 -> 6 -> 4 erfolgen, wobei eine Änderung vom äußeren zum inneren Sprachbereich weitergegeben wird. Da y im äußeren assoziativen Block aktualisiert wird und x im imperativen Block von y abhängig ist, wechselt die Steuerung vom äußeren assoziativen Programm zur imperativen Sprache in Zeile 4.

    Die Ausführungssequenz in diesem nächsten Beispiel würde folgendermaßen lauten: Zeilen 1 -> 2 -> 4 -> 2, wobei die Änderung vom inneren Sprachbereich zum äußeren weitergegeben würde.

    Die oben genannten Szenarien beziehen sich auf die sprachübergreifende Aktualisierung, die ebenso wie assoziative Aktualisierungen in Codeblock-Blöcken nicht sehr nützlich sind. Um komplexe sprachübergreifende Aktualisierungsszenarien zu deaktivieren, haben wir Variablen im imperativen Bereich als lokal festgelegt.

    Im folgenden Beispiel in Dynamo 2.0

    • ist der im imperativen Block definierte Wert x jetzt lokal für den imperativen Bereich.

    • bleiben die Werte für x und y im äußeren Bereich bei 1 bzw. 2.

    Jede lokale Variable innerhalb eines imperativen Blocks muss zurückgegeben werden, wenn auf ihren Wert in einem äußeren Bereich zugegriffen werden soll.

    Beispiel:

    • y wird lokal in den imperativen Bereich kopiert.

    • Der Wert von x, lokal für den imperativem Bereich, lautet 4.

    • Das Aktualisieren des Werts von y

    hashtag
    7. Listen und Wörterbücher

    In Dynamo 1.x wurden Listen und Wörterbücher durch einen einzigen, einheitlichen Container dargestellt, der sowohl durch einen ganzzahligen Index als auch durch einen nicht ganzzahligen Schlüssel indiziert werden konnte. In der folgenden Tabelle werden die Trennung zwischen Listen und Wörterbüchern in Version 2.0 sowie die Regeln des neuen Wörterbuchdatentyps zusammengefasst:

    1.x
    2.0

    hashtag
    Neue []-Listensyntax

    Die Syntax der Listeninitialisierung wurde in Version 2.0 von geschweiften Klammern {} in eckige Klammern [] geändert. Alle 1.x-Skripte werden automatisch auf die neue Syntax migriert, wenn sie in Version 2.0 geöffnet werden.

    Anmerkung zu vorgegebenen Argumentattributen in Zero-Touch-Blöcken:

    Beachten Sie jedoch, dass die automatische Migration mit der alten Syntax, die in vorgegebenen Argumentattributen verwendet wird, nicht funktioniert. Blockautoren müssten ihre Zero-Touch-Methodendefinitionen bei Bedarf manuell aktualisieren, um die neue Syntax in vorgegebenen Argumentattributen des Typs DefaultArgumentAttribute zu verwenden.

    Anmerkung zur Indizierung:

    Das neue Indizierungsverhalten hat sich in bestimmten Fällen geändert. Beim Indizieren in eine Liste/ein Wörterbuch mit einer beliebigen Liste von Indizes/Schlüsseln mithilfe des Operators [] wird jetzt die Listenstruktur der Eingabeliste mit Indizes/Schlüsseln beibehalten. Bisher wurde immer eine 1D-Liste mit Werten zurückgegeben:

    hashtag
    Syntax zur Initialisierung des Wörterbuchs:

    {} (Syntax mit geschweiften Klammern) für die Wörterbuchinitialisierung kann nur im Schlüssel-Wert-Paarformat

    verwendet werden, bei dem nur eine Zeichenfolge für <key> zulässig ist und mehrere Schlüssel-Wert-Paare durch Kommas getrennt werden.

    Die Dictionary.ByKeysValues-Zero-Touch-Methode kann als vielseitigere Methode zur Initialisierung eines Wörterbuchs verwendet werden, indem eine Liste von Schlüsseln bzw. Werten übergeben wird und alle Vorteile der Verwendung von Zero-Touch-Methoden wie Replikationsanleitungen usw. enthalten sind.

    hashtag
    Warum haben wir keine beliebigen Ausdrücke für die Syntax der Wörterbuchinitialisierung verwendet?

    Wir haben mit der Idee, beliebige Ausdrücke für Schlüssel in der Wörterbuch-Schlüssel-Wert-Initialisierungssyntax zu verwenden, experimentiert, haben aber festgestellt, dass dies zu verwirrenden Ergebnissen führen kann, insbesondere wenn eine Syntax wie {keys : vals} (keys und vals repräsentieren beide Listen) mit anderen Sprachfunktionen von DesignScript wie der Replikation kollidierte und andere Ergebnisse aus dem Zero-Touch-Initialisierungsblock erzeugte.

    Es könnte beispielsweise andere Fälle wie diese Anweisung geben, bei denen es schwierig wäre, das erwartete Verhalten zu definieren:

    Das weitere Hinzufügen von Replikationsanleitungs-Syntax usw., nicht nur von Kennungen, würde der Idee der Einfachheit in der Sprache widersprechen.

    Wir könnten Wörterbuchschlüssel in Zukunft erweitern, um beliebige Ausdrücke zu unterstützen, wir müssen jedoch auch sicherstellen, dass die Interaktion mit anderen Sprachfunktionen konsistent und verständlich ist. Wir müssen daher zwischen einer größeren Komplexität und einer etwas geringeren Leistung des Systems abwägen, das dafür aber leichter verständlich ist. Außerdem gibt es mit der Dictionary.ByKeysValues(keyList, valueList)-Methode immer eine alternative Möglichkeit, ohne großen Aufwand zu betreiben.

    hashtag
    Interaktion mit Zero-Touch-Blöcken:

    1. Zero-Touch-Block, der ein .NET-Wörterbuch zurückgibt, wird als Dynamo-Wörterbuch zurückgegeben.

    Betrachten Sie die folgende C#-Zero-Touch-Methode, die ein IDictionary zurückgibt:

    Der entsprechende Rückgabewert des ZT-Blocks wird als Dynamo-Wörterbuch arrangiert:

    2. Blöcke mit mehreren Rückgaben werden in der Vorschau als Wörterbücher angezeigt.

    Zero-Touch-Block, der IDictionary mit einem Attribut mit Mehrfachrückgabe zurückgibt, gibt ein Dynamo-Wörterbuch zurück:

    3. Das Dynamo-Wörterbuch kann als Eingabe für einen Zero-Touch-Block übergeben werden, der das .NET-Wörterbuch akzeptiert.

    ZT-Methode mit IDictionary-Parameter:

    ZT-Block akzeptiert Dynamo-Wörterbuch als Eingabe:

    hashtag
    Wörterbuchvorschau in Blöcken mit mehreren Rückgaben

    Wörterbücher sind ungeordnete Schlüssel-Wert-Paare. In Übereinstimmung mit dieser Idee ist es daher nicht garantiert, dass die Vorschau der Schlüssel-Wert-Paare von Blöcken, die Wörterbücher zurückgeben, in der Reihenfolge der Rückgabewerte der Blöcke sortiert werden.

    Wir haben jedoch eine Ausnahme für Blöcke mit Mehrfachrückgabe hinzugefügt, für die MultiReturnAttribute-Werte definiert sind. Im folgenden Beispiel ist der Block DateTime.Components ein Block mit Mehrfachrückgabe, und in der Blockvorschau werden die Schlüssel-Wert-Paare in derselben Reihenfolge wie bei den Ausgabeanschlüssen im Block angezeigt, was auch der Reihenfolge entspricht, in der die Ausgaben basierend auf den MultiReturnAttribute-Werten in der Blockdefinition angegeben werden.

    Beachten Sie außerdem, dass die Vorschau für Codeblöcke, anders als beim Benutzeroberflächen-Block, nicht angeordnet ist, da die Informationen zum Ausgabeanschluss (in Form eines Mehrfachrückgabe-Attributs) für den Codeblock-Block nicht vorhanden sind:

    Deaktivierung der Listenhochstufung bei Verwendung mit Replikationsanleitungen/Vergitterung
  • Variablen in assoziativen Blöcken sind unveränderlich, um die assoziative Aktualisierung zu verhindern

  • Variablen in imperativen Blöcken gelten lokal für den imperativen Bereich

  • Trennung von Listen und Wörterbüchern

  • , sondern zu
    Curve.PointAtParameter(curve: Curve, parameter:double)
    kompiliert.
    im äußeren Bereich führt aufgrund der sprachübergreifenden Aktualisierung weiterhin zu einer Aktualisierung von
    x
    , ist jedoch in Codeblöcken in Version 2.0 aufgrund der Unveränderlichkeit von Variablen deaktiviert.
  • Der Wert von x und y im äußeren assoziativen Bereich bleibt 1 bzw. 2.

  • a[“foo”] = 1;

    b = {“foo” : 1, “bar” : 2, “baz” : 3};

    a[“bar”] = 2;

    a = {}; // Erstellt ein leeres Wörterbuch.

    a[“baz”] = 3;

    Wörterbuch-Indizierung

    Schlüssel-Indizierung

    Die Indizierungssyntax bleibt unverändert.

    b = a[“bar”];

    b = a[“bar”];

    Wörterbuch-Schlüssel

    Jeder Schlüsseltyp war zulässig.

    Nur Zeichenfolgenschlüssel sind zulässig.

    a = {};

    a = {“false” : 23, “point” : 12};

    a[false] = 23;

    a[point] = 12;

    Listeninitialisierung

    a = {1, 2, 3};

    a = [1, 2, 3];

    Leere Liste

    a = {};

    a = [];

    Wörterbuch-Initialisierung

    Kann dynamisch an dasselbe Wörterbuch angehängt werden:

    Kann nur neue Wörterbücher erstellen:

    a = {};

    a = {“foo” : 1, “bar” : 2};

    Github-Problemarrow-up-right
    pnt = Autodesk.Point.ByCoordinates;
    lne = Autodesk.Line.ByStartPointEndPoint;
    
    [Imperative]
    {
        x = 1;
        start = pnt(0,0,0);
        end = pnt(x,x,x);
        line = lne(start,end);
        return = line;
    };
    BoundingBox BoundingBox.ByGeometry(geometry: Geometry) {...}
    BoundingBox BoundingBox.ByGeometry(geometry: Geometry[]) {...}
    BoundingBox.ByGeometry(geometry<1>);
    1)
    foo(a: int[], b: int); ✓
    foo(a: int, b: int); ✕
    2) 
    foo(x: int, y: int); ✓
    foo(x: int[], y: int[]); ✕
    x = [arc, line];
    y = x.CenterPoint; // y = [centerpoint, null] ✓
    x = [line, arc];
    y = x.CenterPoint; // y = null ✕
    surface<1>.PointAtParameter(u<1>, v<2>);
    Surface.PointAtParameter(surface<1>, u<2>, v<3>);
    x = 1..5;
    y = 0;
    z = 0;
    p = Point.ByCoordinates(x<1>, y<2>, z<3>); // cross-lacing
    Surface.PointAtParameter(surface<1>, u<2>, v<3>); 
    Surface.PointAtParameter(surface<1>, u<2>, v<3>);
    1. a = 1; 
    2. b = a * 2;
    3. a = 2;
    a = 1;
    b = a;
    a = b;
    a = 1;
    b = 1;
    b = b + a + 2; // b = 4
    a = 4;         // b = 10 or b = 7?
    1: def foo(x: A) { x.prop = ...; return x; }
    2: a = A.A();
    3: p = a.prop;
    4: a1 = foo(a);  // will p update?
    1: def foo(v: double) { return v * 2; }// define “foo”
    2: x = foo(5);                         // first definition of “foo” called
    3: def foo(v: int) { return v * 3; }   // overload of “foo” defined, will x update?
    1: x = 1;
    2: y = 2;
    3: [Imperative] {
    4:     x = 2 * y;
    5: }
    6: y = 3;
    1: x = 1;
    2: y = x * 2;
    3: [Imperative] {
    4:     x = 3;
    5: }
    x = 1;
    y = x * 2;
    i = [Imperative] {
         x = 3;
         return x;
    }
    1: x = 1;
    2: y = 2;
    3: [Imperative] {
    4:     x = 2 * y;
    5: }
    6: y = 3; // x = 1, y = 3
    Given:
    a = {“foo” : 1, “bar” : 2};
    
    1.x:
    b = a[{“foo”, {“bar”}}];
    returns {1, 2}
    
    2.0:
    b = a[[“foo”, [“bar”]]];
    returns [1, [2]];
    dict = {<key> : <value>, …}; 
    dict = {["foo", "bar"] : "baz" };