All pages
Powered 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...

Codifica in Dynamo

Dynamo è un ottimo punto da cui iniziare a codificare per il mondo AEC. Si potrebbe essere interessati ad alcune di queste sezioni per iniziare il percorso di codifica:

  • Blocchi di codice e DesignScript

  • Geometria con DesignScript

  • Python

Geometria con DesignScript

In questa sezione, è disponibile una serie di lezioni sulla creazione della geometria con DesignScript. Seguire la procedura copiando l'esempio di DesignScript nei blocchi di codice di Dynamo.

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

x = "Let's create some geometry!";

Python

​Python è un linguaggio di programmazione ampiamente utilizzato, la cui popolarità ha molto a che fare con il suo stile di sintassi. È altamente leggibile, il che rende più semplice l'apprendimento di molti altri linguaggi. Python supporta moduli e pacchetti e può essere incorporato nelle applicazioni esistenti. Per informazioni su come iniziare ad utilizzare Python, una buona risorsa è la pagina "Getting Started" sul sito Python.org

Curve: punti interpolati e di controllo

In Dynamo vi sono due metodi fondamentali per creare curve di forma libera: la specifica di una raccolta di punti e l'impostazione del programma in modo che venga interpolata una curva levigata tra di essi oppure esiste un metodo di livello molto più basso, ossia specificare i punti di controllo sottostanti di una curva di un determinato grado. Le curve interpolate sono utili quando un progettista sa esattamente la forma che deve assumere una linea o se il progetto ha vincoli specifici per il punto in cui la curva può e non può attraversare. Le curve specificate tramite i punti di controllo sono essenzialmente una serie di segmenti di linee rette che un algoritmo leviga in una forma di curva finale. Specificare una curva tramite punti di controllo può essere utile per esplorare forme di curva con diversi gradi di levigatezza o quando è necessaria una continuità uniforme tra segmenti di curva.

Curva interpolata

Per creare una curva interpolata, è sufficiente trasferire una raccolta di punti al metodo NurbsCurve.ByPoints.

La curva generata interseca ciascuno dei punti di input, iniziando e terminando rispettivamente nel primo e nell'ultimo punto della raccolta. È possibile utilizzare un parametro periodico facoltativo per creare una curva periodica chiusa. Dynamo inserirà automaticamente il segmento mancante, pertanto non è necessario un punto finale duplicato (identico al punto iniziale).

Curva con punti di controllo

Le NurbsCurve vengono generate in modo molto simile, con i punti di input che rappresentano i punti finali di un segmento di linea retta e un secondo parametro che specifica il livello e il tipo di levigatezza a cui è sottoposta la curva, denominati grado.* Una curva di grado 1 non ha alcuna levigatezza; è una polilinea.

Una curva di grado 2 viene levigata in modo che si intersechi ed è tangente al punto medio dei segmenti della polilinea:

Dynamo supporta curve NURBS (Non-Uniform Rational B-Spline) fino ad un massimo di 20 gradi. Nel seguente script è illustrato l'effetto che l'aumento dei livelli di levigatezza ha sulla forma di una curva:

Notare che è necessario disporre di almeno un altro punto di controllo rispetto al grado della curva.

Un altro vantaggio della costruzione delle curve tramite vertici di controllo è la possibilità di mantenere la tangenza tra singoli segmenti della curva. Per eseguire questa operazione, estrarre la direzione tra gli ultimi due punti di controllo e continuare in questa direzione con i primi due punti di controllo della curva seguente. Nel seguente esempio vengono create due curve NURBS separate, che sono tuttavia levigate come una curva:

*Questa è una descrizione molto semplificata della geometria della curva NURBS. Per una descrizione più accurata e dettagliata, vedere Pottmann, et al, 2007, nei riferimenti.

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);

Matematica vettoriale

Gli oggetti nelle progettazioni computazionali raramente vengono creati esplicitamente nella loro posizione e nella loro forma finali e più spesso vengono traslati, ruotati e altrimenti posizionati in base alla geometria esistente. La matematica vettoriale serve come una sorta di impalcatura geometrica per dare direzione e orientamento alla geometria, nonché per concettualizzare i movimenti attraverso lo spazio 3D senza rappresentazione visiva.

Fondamentalmente, un vettore rappresenta una posizione nello spazio 3D e spesso viene considerato come il punto finale di una freccia dalla posizione (0, 0, 0) a quella posizione. I vettori possono essere creati con il costruttore ByCoordinates, utilizzando la posizione x, y e z dell'oggetto vettoriale appena creato. Notare che gli oggetti vettoriali non sono oggetti geometrici e non compaiono nella finestra di Dynamo. Tuttavia, le informazioni relative ad un vettore appena creato o modificato possono essere stampate nella finestra della console:

// construct a Vector object
v = Vector.ByCoordinates(1, 2, 3);

s = v.X + " " + v.Y + " " + v.Z;

Un insieme di operazioni matematiche viene definito sugli oggetti vettoriali, consentendo di aggiungere, sottrarre, moltiplicare e altrimenti spostare oggetti nello spazio 3D, come si sposterebbero numeri reali nello spazio 1D su una linea numerica.

Addizione vettoriale

L'addizione vettoriale è definita come la somma dei componenti di due vettori e può essere considerata come il vettore risultante se le frecce dei componenti dei due vettori vengono posizionate "dalla punta alla coda". L'addizione vettoriale viene eseguita con il metodo Add ed è rappresentata dal diagramma a sinistra.

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);

Sottrazione vettoriale

Analogamente, due oggetti vettoriali possono essere sottratti l'uno dall'altro con il metodo Subtract. La sottrazione vettore può essere considerata come direzione dal primo vettore al secondo vettore.

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);

Moltiplicazione vettoriale

La moltiplicazione vettoriale può essere considerata come lo spostamento del punto finale di un vettore nella sua direzione mediante un determinato fattore di scala.

a = Vector.ByCoordinates(4, 4, 0);

// c has value x = 20, y = 20, z = 0
c = a.Scale(5);

Normalizzazione della lunghezza del vettore

Spesso è necessario durante la messa in scala di un vettore avere la lunghezza del vettore risultante esattamente uguale al valore in scala. Ciò si ottiene facilmente normalizzando prima un vettore, in altre parole impostando la lunghezza del vettore esattamente uguale ad uno.

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;

c punta ancora nella stessa direzione di a (1, 2, 3), anche se ora ha una lunghezza esattamente uguale a 5.

Globale

Nella matematica vettoriale esistono due metodi di addizione che non hanno paralleli chiari con la matematica 1D, il prodotto incrociato e il prodotto punto. Il prodotto incrociato è un mezzo per generare un vettore ortogonale (a 90 gradi) rispetto a due vettori esistenti. Ad esempio, il prodotto incrociato degli assi x e y è l'asse x, sebbene i due vettori di input non debbano essere ortogonali tra loro. Viene calcolato un vettore del prodotto incrociato con il metodo Cross.

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);

Prodotto punto

Un'ulteriore funzione, sebbene più avanzata di matematica vettoriale, è il prodotto punto. Il prodotto punto tra due vettori è un numero reale (non un oggetto Vector) che è correlato, ma non è esattamente, all'angolo tra due vettori. Una delle proprietà utili del prodotto punto è che il prodotto punto tra due vettori sarà 0 se e solo se sono perpendicolari. Il prodotto punto viene calcolato con il metodo Dot.

a = Vector.ByCoordinates(1, 2, 1);
b = Vector.ByCoordinates(5, -8, 4);

// d has value -7
d = a.Dot(b);

Operazioni booleane geometriche

Intersect, Trim e SelectTrim vengono utilizzati principalmente nella geometria dimensionale minore come punti, curve e superfici. La geometria solida, invece, presenta un insieme aggiuntivo di metodi per la modifica della forma dopo la costruzione, sottraendo il materiale in modo simile a Trim e combinando gli elementi insieme per formare un intero più grande.

Unione

Il metodo Unione utilizza due oggetti solidi e crea un singolo oggetto solido partendo dallo spazio coperto da entrambi gli oggetti. Lo spazio sovrapposto tra oggetti viene combinato nella forma finale. In questo esempio si combina una sfera e un cuboide in un'unica forma solida sfera-cubo:

s1 = Sphere.ByCenterPointRadius(
    CoordinateSystem.Identity().Origin, 6);

s2 = Sphere.ByCenterPointRadius(
    CoordinateSystem.Identity().Origin.Translate(4, 0,
    0), 6);

combined = s1.Union(s2);

Differenza

Il metodo Difference, come Trim, sottrae il contenuto del solido strumento di input dal solido di base. In questo esempio, viene ritagliata una piccola rientranza da una sfera:

s = Sphere.ByCenterPointRadius(
    CoordinateSystem.Identity().Origin, 6);

tool = Sphere.ByCenterPointRadius(
    CoordinateSystem.Identity().Origin.Translate(10, 0,
    0), 6);

result = s.Difference(tool);

Interseca

Il metodo Intersect restituisce il solido sovrapposto tra due input solidi. Nel seguente esempio, Difference è stato modificato in Intersect e il solido risultante è il vuoto mancante inizialmente ritagliato:

s = Sphere.ByCenterPointRadius(
    CoordinateSystem.Identity().Origin, 6);

tool = Sphere.ByCenterPointRadius(
    CoordinateSystem.Identity().Origin.Translate(10, 0,
    0), 6);

result = s.Intersect(tool);

Blocchi di codice e DesignScript

Il blocco di codice è una funzionalità unica di Dynamo che collega dinamicamente un ambiente di programmazione visiva con uno di programmazione basata su testo. Il blocco di codice ha accesso a tutti i nodi di Dynamo e può definire un intero grafico in un nodo. Leggere attentamente questo capitolo, poiché il blocco di codice è un elemento di base fondamentale di Dynamo.

Parametrizzazione geometrica

Nelle progettazioni computazionali, le curve e le superfici vengono spesso utilizzate come l'impalcatura sottostante per costruire la geometria successiva. Per poter utilizzare questa geometria iniziale come base per la geometria successiva, lo script deve essere in grado di estrarre qualità quali la posizione e l'orientamento nell'intera area dell'oggetto. Sia le curve che le superfici supportano questa estrazione, che è denominata parametrizzazione.

Tutti i punti su una curva possono essere considerati come un parametro unico compreso tra 0 e 1. Se si desidera creare una NurbsCurve basata su diversi punti di controllo o interpolati, il primo punto avrà il parametro 0 e l'ultimo punto avrà il parametro 1. Non è possibile sapere in anticipo quale sia l'esatto parametro qualunque sia il punto intermedio, il che potrebbe sembrare una limitazione grave, tuttavia ciò è mitigato da una serie di funzioni di utilità. Le superfici hanno una parametrizzazione simile a quella delle curve, anche se con due parametri invece di uno, denominati u e v. Se si desidera creare una superficie con i seguenti punti:

p1 avrebbe il parametro u = 0 v = 0, mentre p9 avrebbe i parametri u = 1 v = 1.

La parametrizzazione non è particolarmente utile per determinare i punti utilizzati per generare le curve; il suo uso principale è determinare le posizioni dei punti intermedi generati dai costruttori NurbsCurve e NurbsSurface.

Le curve hanno un metodo PointAtParameter, che utilizza un singolo argomento doppio compreso tra 0 e 1 e restituisce l'oggetto Point in corrispondenza di tale parametro. Ad esempio, questo script trova i Point in corrispondenza dei parametri 0, .1, .2, .3, .4, .5, .6, .7, .8, .9 e 1:

Analogamente, le superfici hanno un metodo PointAtParameter che utilizza due argomenti, il parametro u e v del Point generato.

Sebbene l'estrazione di punti singoli su una curva e una superficie possa essere utile, gli script spesso richiedono la conoscenza delle particolari caratteristiche geometriche in corrispondenza di un parametro, ad esempio qual è la direzione della curva o della superficie. Il metodo CoordinateSystemAtParameter non solo individua la posizione, ma anche un CoordinateSystem orientato in corrispondenza del parametro di una curva o superficie. Ad esempio, il seguente script estrae i CoordinateSystem orientati lungo una superficie di rivoluzione e utilizza l'orientamento dei CoordinateSystem per generare linee che si staccano dalla normale alla superficie:

Come detto in precedenza, la parametrizzazione non è sempre uniforme per tutta la lunghezza di una curva o di una superficie, ovvero il parametro 0.5 non corrisponde sempre al punto medio e 0.25 non sempre corrisponde al punto un quarto lungo una curva o superficie. Per ovviare a questa limitazione, le curve dispongono di un insieme aggiuntivo di comandi di parametrizzazione che consentono di trovare un punto in corrispondenza di lunghezze specifiche lungo una curva.

Cos'è un blocco di codice?

I blocchi di codice sono una finestra sul mondo di DesignScript, il linguaggio di programmazione al centro di Dynamo. Sviluppato da zero per supportare i workflow di progettazione esplorativa, DesignScript è un linguaggio leggibile e conciso che offre feedback immediato a piccoli bit di codice e si adatta anche a interazioni complesse e di grandi dimensioni. DesignScript costituisce inoltre le fondamenta del motore che controlla la maggior parte degli aspetti di Dynamo "dietro le quinte". Poiché quasi tutte le funzionalità presenti nelle interazioni e nei nodi di Dynamo hanno una relazione uno ad uno con il linguaggio di scripting, esistono opportunità uniche di spostarsi tra le interazioni basate su nodi e lo scripting in modo fluido.

Per i principianti, i nodi possono essere convertiti automaticamente in sintassi di testo per agevolare l'apprendimento di DesignScript o semplicemente per ridurre la dimensione di sezioni più grandi dei grafici. A tale scopo, è necessario utilizzare un processo denominato "Nodo da aggiungere al codice", descritto in dettaglio nella sezione . Gli utenti più esperti possono utilizzare i blocchi di codice per creare mashup personalizzati delle funzionalità esistenti e relazioni create dall'utente utilizzando molti paradigmi di codifica standard. Tra il principiante e l'utente avanzato, esistono innumerevoli scorciatoie e frammenti di codice che accelerano i progetti. Sebbene il termine "blocco di codice" possa risultare un po' intimidatorio per gli utenti non esperti di programmazione, è facile da utilizzare ed efficace. Un principiante può utilizzare il blocco di codice in modo efficiente con una codifica minima e un utente avanzato può definire definizioni di script da richiamare altrove in una definizione di Dynamo.

Blocco di codice: Una breve panoramica

In breve, i blocchi di codice sono un'interfaccia dello scripting di testo all'interno di un ambiente di scripting visivo. Possono essere utilizzati come numeri, stringhe, formule e altri tipi di dati. Il blocco di codice è stato progettato per Dynamo, pertanto è possibile definire variabili arbitrarie nel blocco di codice e tali variabili vengono aggiunte automaticamente agli input del nodo:

Con i blocchi di codice, un utente ha la flessibilità di decidere come specificare gli input. Di seguito sono riportati diversi modi per creare un punto base con le coordinate (10, 5, 0):

Man mano che si acquisiscono ulteriori informazioni sulle funzioni disponibili nella libreria, si potrebbe persino scoprire che la digitazione di Point.ByCoordinates è più rapida rispetto alla ricerca nella libreria e all'individuazione del nodo appropriato. Quando si digita Point ad esempio, in Dynamo verrà visualizzato un elenco di possibili funzioni da applicare ad un punto. Ciò rende più intuitivo lo scripting e aiuterà ad imparare come applicare le funzioni in Dynamo.

Creazione di nodi di blocco di codice

Il blocco di codice è disponibile in Core > Input > Actions > Code Block. Ma per una procedura ancora più veloce per visualizzare il blocco di codice, è sufficiente fare doppio clic nell'area di disegno. Questo nodo viene utilizzato così spesso che dispone di tutte le funzioni accessibili con il doppio clic del mouse.

Numeri, stringhe e formule

Anche i blocchi di codice sono flessibili rispetto ai tipi di dati. L'utente può definire rapidamente numeri, stringhe e formule e il blocco di codice fornirà l'output desiderato.

Nella seguente immagine, è possibile vedere che il modo di eseguire le operazioni della "vecchia scuola" è leggermente più lungo: l'utente cerca il nodo desiderato nell'interfaccia, aggiunge il nodo all'area di disegno e quindi inserisce i dati. Con il blocco di codice, l'utente può fare doppio clic nell'area di disegno per estrarre il nodo e digitare il tipo di dati corretto con la sintassi di base.

I nodi Number e String sono due esempi di nodi di Dynamo che risultano probabilmente obsoleti rispetto al blocco di codice.

  1. "Vecchia scuola"

  2. Code Block

pts = [ [p1, p2, p3],
        [p4, p5, p6],
        [p7, p8, p9] ];
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));
Sintassi di DesignScript

Nozioni di base della geometria DesignScript

Punto

L'oggetto geometrico più semplice nella libreria della geometria standard di Dynamo è un punto. Tutta la geometria viene creata utilizzando funzioni speciali denominate costruttori, i quali singolarmente restituiscono una nuova istanza di quel particolare tipo di geometria. In Dynamo, i costruttori iniziano con il nome del tipo di oggetto, in questo caso Point, seguito dal metodo di costruzione. Per creare un punto tridimensionale specificato dalle coordinate cartesiane x, y e z, utilizzare il costruttore ByCoordinates:

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

p = Point.ByCoordinates(x, y, z);

In Dynamo, i costruttori vengono in genere designati con il prefisso By e il richiamo di queste funzioni restituisce un oggetto appena creato di quel tipo. Questo oggetto appena creato viene memorizzato nella variabile indicata sul lato sinistro del segno di uguale.

La maggior parte degli oggetti ha molti differenti costruttori ed è possibile utilizzare il costruttore BySphericalCoordinates per creare un punto su una sfera, specificato dal raggio della sfera, un primo angolo di rotazione e un secondo angolo di rotazione (specificato in gradi):

// 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);

Da punto a linea

I punti possono essere utilizzati per costruire la geometria dimensionale maggiore, come le linee. È possibile utilizzare il costruttore ByStartPointEndPoint per creare un oggetto Line tra due punti:

// 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);

Da linea a superficie

Analogamente, le linee possono essere utilizzate per creare la geometria di superfici dimensionale maggiore, ad esempio utilizzando il costruttore Loft, che utilizza una serie di linee o curve e interpola una superficie tra loro.

// 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]);

Da superficie a solido

È possibile utilizzare anche superfici per creare la geometria di solidi dimensionale maggiore, ad esempio mediante l'ispessimento della superficie in base ad una distanza specificata. Molti oggetti hanno funzioni associate, denominate metodi, che consentono al programmatore di eseguire comandi su quel particolare oggetto. I metodi comuni a tutti gli elementi della geometria includono Translate e Rotate, che rispettivamente traslano (spostano) e ruotano la geometria di un valore specificato. Le superfici hanno un metodo Thicken, che acquisisce un singolo input, un numero che specifica il nuovo spessore della superficie.

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);

Interseca

I comandi Intersection consentono di estrarre la geometria dimensionale minore da oggetti dimensionali maggiori. Questa geometria dimensionale minore estratta può formare la base per la geometria dimensionale maggiore, in un processo ciclico di creazione, estrazione e ricreazione geometriche. In questo esempio, si utilizzerà il solido generato per creare una superficie e si utilizzerà la superficie per creare una curva.

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)));

Primitive geometriche

Sistema di Coordinate

Sebbene Dynamo sia in grado di creare una vasta gamma di forme geometriche complesse, le primitive geometriche semplici formano le fondamenta di qualsiasi progettazione computazionale: direttamente espresse nella forma finale progettata o utilizzata come impalcatura dalla quale viene generata una geometria più complessa.

Anche se non è strettamente un elemento di geometria, CoordinateSystem è uno strumento importante per la costruzione della geometria. Un oggetto CoordinateSystem tiene traccia delle trasformazioni geometriche e di posizione, quali rotazione, taglio e messa in scala.

La creazione di un CoordinateSystem centrato in un punto con x = 0, y = 0, z = 0, senza rotazioni, messa in scala o trasformazioni di taglio, richiede semplicemente di chiamare il costruttore Identity:

// create a CoordinateSystem at x = 0, y = 0, z = 0,
// no rotations, scaling, or sheering transformations

cs = CoordinateSystem.Identity();

I CoordinateSystem con trasformazioni geometriche non rientrano nell'ambito di questo capitolo, sebbene un altro costruttore consenta di creare un sistema di coordinate in un punto specifico, CoordinateSystem.ByOriginVectors:

// 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);

Punto

La primitiva geometrica più semplice è un punto, che rappresenta una posizione a zero dimensioni nello spazio tridimensionale. Come detto in precedenza, esistono diversi modi per creare un punto in un particolare sistema di coordinate: Point.ByCoordinates crea un punto con coordinate x, y e z specificate; Point.ByCartesianCoordinates crea un punto con coordinate x, y e z specificate in un sistema di coordinate specifico; Point.ByCylindricalCoordinates crea un punto su un cilindro con raggio, angolo di rotazione e altezza e Point.BySphericalCoordinates crea un punto su una sfera con raggio e due angoli di rotazione.

In questo esempio sono mostrati i punti creati in diversi sistemi di coordinate:

// 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);

Linea

La successiva primitiva di Dynamo dimensionale maggiore è un segmento di linea, che rappresenta un numero infinito di punti tra due punti finali. Le linee possono essere create specificando esplicitamente i due punti di contorno con il costruttore Line.ByStartPointEndPoint o specificando un punto iniziale, una direzione e una lunghezza in tale direzione, Line.ByStartPointDirectionLength.

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);

Primitive 3D - Cuboide, cono, cilindro, sfera e così via

Dynamo dispone di oggetti che rappresentano i tipi più elementari di primitive geometriche in tre dimensioni: cuboidi, creati con Cuboid.ByLengths; coni, creati con Cone.ByPointsRadius e Cone.ByPointsRadii; cilindri, creati con Cylinder.ByRadiusHeight e sfere create con Sphere.ByCenterPointRadius.

// 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);

Impostazione del modello di Python personalizzato

Con Dynamo 2.0 è possibile specificare un modello di default (.py extension) da utilizzare all'apertura della finestra di Python per la prima volta. Questa è stata una richiesta a lungo desiderata perché consente di accelerare l'utilizzo di Python all'interno di Dynamo. La possibilità di utilizzare un modello consente di avere importazioni di default pronte per lo sviluppo di uno script Python personalizzato.

La posizione di questo modello è APPDATA per l'installazione di Dynamo.

In genere, è la seguente: ( %appdata%\Dynamo\Dynamo Core\{version}\ ).

Configurazione del modello

Per utilizzare questa funzionalità, è necessario aggiungere la seguente riga nel file DynamoSettings.xml. (Modifica nel Blocco note)

Dove è visibile la riga <PythonTemplateFilePath />, è sufficiente sostituirla con quanto segue:

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

Nota: Sostituire CURRENTUSER con il nome utente.

Successivamente, è necessario creare un modello con le funzionalità incorporate che si desidera utilizzare. In questo caso, si incorporano le importazioni correlate a Revit e alcuni degli altri elementi tipici quando si utilizza Revit.

È possibile aprire un documento del Blocco note vuoto e incollare il seguente codice all'interno:

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

Al termine, salvare il file come PythonTemplate.py nella posizione APPDATA.

Funzionamento successivo dello script Python

Dopo aver definito un modello di Python, verrà cercato in Dynamo ogni volta che viene posizionato un nodo Python. Se non viene trovato, sarà simile alla finestra di Python di default.

Se viene trovato il modello di Python (ad esempio, come il modello di Revit), verranno visualizzati tutti gli elementi di default incorporati.

Ulteriori informazioni su questa straordinaria aggiunta (di Radu Gidei) sono disponibili qui. https://github.com/DynamoDS/Dynamo/pull/8122

Generatori di punti di Python

I seguenti script Python generano serie di punti per diversi esempi. È necessario incollarli in un nodo Python Script come segue:

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

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

python_points_5

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

Intersezione e taglio

Molti degli esempi riportati finora si sono concentrati sulla costruzione di geometria dimensionale maggiore a partire da oggetti dimensionali minori. I metodi di intersezione consentono a questa geometria dimensionale maggiore di generare oggetti dimensionali minori, mentre i comandi di taglio e selezione del taglio consentono di modificare pesantemente le forme geometriche mediante script dopo la creazione.

Il metodo Intersect è definito su tutti gli elementi della geometria in Dynamo, ovvero, in teoria qualsiasi elemento della geometria può essere intersecato con qualsiasi altro elemento della geometria. Naturalmente alcune intersezioni sono insignificanti, come le intersezioni che coinvolgono i punti, poiché l'oggetto risultante sarà sempre il punto di input stesso. Le altre possibili combinazioni di intersezioni tra gli oggetti sono descritte nel seguente grafico, in cui è illustrato il risultato di diverse operazioni di intersezione:

Interseca

Con:

Superficie

Curva

Piano

Uniforme

Superficie

Curva

Punto

Punto, curva

Superficie

Curva

Punto

Punto

Punto

Curva

Piano

Curva

Punto

Curva

Curva

Uniforme

Superficie

Curva

Curva

Uniforme

Nel semplicissimo esempio riportato di seguito è mostrata l'intersezione di un piano con una NurbsSurface. L'intersezione genera una serie di NurbsCurve, che può essere utilizzata come qualsiasi altra NurbsCurve.

// 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);

Il metodo Trim è molto simile al metodo Intersect, in quanto viene definito per quasi ogni elemento della geometria. Tuttavia, esistono molte più limitazioni per Trim rispetto a Intersect.

Riduci

Mediante: Point

Curva

Piano

Superficie

Uniforme

Su: Curva

Sì

No

No

No

No

Poligono

-

No

Sì

No

No

Superficie

-

Sì

Sì

Sì

Sì

Uniforme

-

-

Sì

Sì

Sì

Qualcosa da notare sui metodi Trim è il requisito di un punto di "selezione", un punto che determina quale geometria eliminare e quali elementi mantenere. In Dynamo viene trovata ed eliminata la geometria ritagliata più vicina al punto di selezione.

// 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);

Funzioni

Le funzioni possono essere create in un blocco di codice e richiamate in un altro punto della definizione di Dynamo. In questo modo viene creato un altro livello di controllo in un file parametrico e può essere visualizzato come versione basata su testo di un nodo personalizzato. In questo caso, il blocco di codice "principale" è facilmente accessibile e può essere posizionato ovunque nel grafico. Non sono necessari i fili.

Parent

La prima riga contiene la parola chiave "def", il nome della funzione e i nomi degli input tra parentesi. Le parentesi graffe definiscono il corpo della funzione. Restituiscono un valore con "return =". I blocchi di codice che definiscono una funzione non presentano porte di input o output, in quanto vengono chiamati da altri blocchi di codice.

/*This is a multi-line comment,
which continues for
multiple lines*/
def FunctionName(in1,in2)
{
//This is a comment
sum = in1+in2;
return sum;
};

Elementi derivati

Chiamano la funzione con un altro blocco di codice nello stesso file, assegnando lo stesso nome e lo stesso numero di argomenti. Funzionano come i nodi predefiniti nella libreria.

FunctionName(in1,in2);

Esercizio: Sfera per Z

Scaricare il file di esempio facendo clic sul collegamento seguente.

Un elenco completo di file di esempio è disponibile nell'Appendice.

30KB
Functions_SphereByZ.dyn
Open

In questo esercizio verrà eseguita una definizione generica che creerà sfere da un elenco di input di punti. Il raggio di queste sfere viene gestito dalla proprietà Z di ogni punto.

Iniziare con un numero di dieci valori compresi tra 0 e 100. Collegarli ai nodi Point.ByCoordinates per creare una linea diagonale.

Creare un Code Block e introdurre la definizione.

  1. Utilizzare queste righe di codice:

    def sphereByZ(inputPt)
    {
    
    };

inputPt è il nome fornito per rappresentare i punti che controlleranno la funzione. Per ora, la funzione non sta eseguendo alcuna operazione, ma si costruirà questa funzione nei prossimi passaggi.

  1. Alla funzione Code Block, si aggiungono un commento e una variabile sphereRadius che esegue una query sulla posizione Z di ogni punto. Tenere presente che inputPt.Z non richiede parentesi come metodo. Si tratta di una query sulle proprietà di un elemento esistente, pertanto non sono necessari input:

def sphereByZ(inputPt,radiusRatio)
{
//get Z Value, ise ot to drive radius of sphere
sphereRadius=inputPt.Z;
};
  1. Ora, richiamare la funzione che è stata creata in un altro Code Block. Se si fa doppio clic sull'area di disegno per creare un nuovo Code Block e si digita sphereB, si noterà che Dynamo suggerisce la funzione sphereByZ definita. La funzione è stata aggiunta alla libreria di IntelliSense. Ottimo.

  1. Ora richiamare la funzione e creare una variabile denominata Pt per collegare i punti creati nei passaggi precedenti:

    sphereByZ(Pt)
  2. Dall'output si noterà che tutti i valori sono nulli. Perché? Quando è stata definita la funzione, si stava calcolando la variabile sphereRadius, ma non è stato definito che cosa la funzione dovrebbe restituire come output. È possibile risolvere il problema nel passaggio successivo.

  1. Un passaggio importante: è necessario definire l'output della funzione aggiungendo la riga return = sphereRadius; alla funzione sphereByZ.

  2. Ora si può vedere che l'output di Code Block fornisce le coordinate Z di ciascun punto.

Procedere alla creazione di sfere effettive modificando la funzione principale.

  1. Per prima cosa si definisce una sfera con la riga di codice: sphere=Sphere.ByCenterPointRadius(inputPt,sphereRadius);.

  2. Successivamente, si modifica il valore restituito in modo che sia sphere anziché sphereRadius: return = sphere;. In questo modo vengono restituite alcune sfere giganti nell'anteprima di Dynamo.

1. Per ridurre le dimensioni di queste sfere, aggiornare il valore sphereRadius aggiungendo un divisore: sphereRadius = inputPt.Z/20;. Ora è possibile vedere le sfere separate. Inizia ad avere un senso la relazione tra il raggio e il valore Z.

  1. Nel nodo Point.ByCoordinates, modificando il collegamento da Più breve a Globale, verrà creata una griglia di punti. La funzione sphereByZ è ancora attiva, per cui tutti i punti creano sfere con i raggi basati sui valori Z.

  1. E solo per fare delle prove, è necessario collegare l'elenco originale di numeri all'input X per Point.ByCoordinates. Ora si ottiene un cubo di sfere.

  2. Nota: se il calcolo al computer richiede molto tempo, provare a modificare #10 impostandolo su un valore simile a #5.

Tenere presente che la funzione sphereByZ che è stata creata è una funzione generica, pertanto è possibile richiamare l'elica da una lezione precedente e applicare la funzione ad essa.

Un passaggio finale: controllare il rapporto del raggio con un parametro definito dall'utente. A tale scopo, è necessario creare un nuovo input per la funzione e sostituire anche il divisore 20 con un parametro.

  1. Aggiornare la definizione di sphereByZ a:

    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;
    };
  2. Aggiornare il Code Block degli elementi derivati aggiungendo una variabile ratio all'input: sphereByZ(Pt,ratio);. Collegare un dispositivo di scorrimento all'input Code Block appena creato e modificare la dimensione dei raggi in base al rapporto del raggio.

Sintassi di DesignScript

Nei nomi dei nodi di Dynamo è possibile aver notato un tema comune: ogni nodo utilizza una sintassi "." senza spazi. Questo perché il testo nella parte superiore di ogni nodo rappresenta la sintassi effettiva per lo scripting e "." (o notazione con punto) separa un elemento dai metodi possibili che è possibile chiamare. In questo modo è possibile creare una facile conversione dallo scripting visivo nello scripting basato su testo.

Nomi di nodi

Come analogia generale per la notazione con punto, in che modo è possibile gestire una mela parametrica in Dynamo? Di seguito sono riportati alcuni metodi che si eseguiranno sulla mela prima di decidere di mangiarla (nota: questi non sono metodi di Dynamo effettivi):

Leggibile dall'uomo
Notazione con punto
Output

Di che colore è la mela?

Apple.color

rosso

La mela è matura?

Apple.isRipe

true

Quanto pesa la mela?

Apple.weight

170 gr

Da dove è venuta la mela?

Apple.parent

albero

Cosa crea la mela?

Apple.children

semi

Questa mela è cresciuta localmente?

Apple.distanceFromOrchard

circa 96 km

Non so quello che pensate, ma a giudicare dagli output nella tabella riportata sopra, sembra una mela gustosa. Il risultato è Apple.eat().

Notazione con punto in Code Block

Tenendo presente l'analogia con la mela, si esaminerà Point.ByCoordinates e sarà mostrato com'è possibile creare un punto utilizzando Code Block.

La sintassi di Code Block Point.ByCoordinates(0,10); fornisce lo stesso risultato di un nodo Point.ByCoordinates in Dynamo, tranne per il fatto che è possibile creare un punto utilizzando un nodo. Ciò è più efficiente rispetto al collegamento di un nodo separato in X e Y.

  1. Utilizzando Point.ByCoordinates in Code Block, si specificano gli input nello stesso ordine del nodo predefinito (X,Y).

Chiamata di nodi - Crea, Azioni, Query

È possibile chiamare qualsiasi nodo normale nella libreria tramite Code Block, purché il nodo non sia un nodo "UI" speciale: quelli con una funzionalità speciale dell'interfaccia utente. Ad esempio, è possibile chiamare Circle.ByCenterPointRadius, ma non sarebbe molto utile chiamare un nodo Watch 3D.

I nodi regolari (nella maggior parte della libreria) in genere sono di tre tipi. Si scoprirà che la libreria è organizzata in base a queste categorie. I metodi, o nodi, di questi tre tipi vengono trattati in modo diverso quando vengono richiamati all'interno di Code Block.

  1. Crea: consente di creare (o costruire) un elemento.

  2. Azione: consente di eseguire un'azione su un elemento.

  3. Query: consente di ottenere una proprietà di un elemento già esistente.

Crea

La categoria Crea costruirà la geometria da zero. I valori vengono immessi in Code Block da sinistra a destra. Questi input sono nello stesso ordine degli input nel nodo dall'alto verso il basso.

Confrontando il nodo Line.ByStartPointEndPoint e la sintassi corrispondente in Code Block, si ottengono gli stessi risultati.

Azione

Un'azione è un'operazione che si esegue su un oggetto di quel tipo. In Dynamo si utilizza la notazione con punto, comune a molti linguaggi di codifica, per applicare un'azione ad un elemento. Una volta ottenuto l'elemento, digitare un punto, quindi il nome dell'azione. L'input del metodo di tipo Azione viene inserito tra parentesi, come i metodi di tipo Crea, solo che non è necessario specificare il primo input visualizzato nel nodo corrispondente. È necessario specificare invece l'elemento su cui si sta eseguendo l'azione:

  1. Il nodo Point.Add è un nodo di tipo Azione, pertanto la sintassi funziona in modo leggermente diverso.

  2. Gli input sono (1) Point e (2) Vector da aggiungere ad esso. In Code Block, è stato denominato il punto (l'elemento) "pt". Per aggiungere un vettore denominato "vec" a "pt", è necessario scrivere pt.Add(vec) o: elemento, punto, azione. L'azione Add presenta solo un input o tutti gli input del nodo Point.Add meno il primo. Il primo input per il nodo Point.Add è il punto stesso.

Query

I metodi di tipo Query consentono di ottenere una proprietà di un oggetto. Poiché l'oggetto stesso è l'input, non è necessario specificare alcun input. Non sono richieste parentesi.

Informazioni sul collegamento

Il collegamento con i nodi è piuttosto diverso dal collegamento con il blocco di codice. Con i nodi, l'utente fa clic con il pulsante destro del mouse sul nodo e seleziona l'opzione Collegamento da eseguire. Con il blocco di codice, l'utente dispone di un maggiore controllo sulla modalità di strutturazione dei dati. Il metodo abbreviato del blocco di codice utilizza guide di replica per impostare il modo in cui occorre associare diversi elenchi unidimensionali. I numeri tra parentesi angolari "<>" definiscono la gerarchia dell'elenco nidificato risultante: <1>,<2>,<3> e così via.

  1. In questo esempio, si utilizza un metodo abbreviato per definire due intervalli (ulteriori informazioni sul metodo abbreviato saranno fornite nella sezione seguente di questo capitolo). In breve, 0..1; è equivalente a {0,1} e -3..-7 è equivalente a {-3,-4,-5,-6,-7}. Il risultato offre un elenco di 2 valori X e 5 valori Y. Se non si utilizzano le guide di replica con questi elenchi non corrispondenti, si ottiene un elenco di due punti, che rappresenta la lunghezza dell'elenco più breve. Utilizzando le guide di replica, è possibile trovare tutte le combinazioni possibili di 2 e 5 coordinate (o un collegamento Globale).

  2. Utilizzando la sintassi Point.ByCoordinates(x_vals<1>,y_vals<2>); si ottengono due elenchi con cinque voci in ogni elenco.

  3. Utilizzando la sintassi Point.ByCoordinates(x_vals<2>,y_vals<1>); si ottengono cinque elenchi con due voci in ogni elenco.

Con questa notazione, è possibile anche specificare quale elenco sarà dominante: 2 elenchi di 5 cose o 5 elenchi di 2 cose. Nell'esempio, la modifica dell'ordine delle guide di replica restituisce come risultato un elenco di righe di punti o un elenco di colonne di punti in una griglia.

Nodo da aggiungere al codice

Sebbene i metodi del blocco di codice riportati sopra possano richiedere del tempo per acquisire familiarità, in Dynamo è disponibile una funzionalità denominata Nodo da aggiungere al codice che facilita il processo. Per utilizzare questa funzionalità, selezionare una serie di nodi nel grafico di Dynamo, fare clic con il pulsante destro del mouse sull'area di disegno e selezionare Nodo da aggiungere al codice. In Dynamo vengono compressi questi nodi in un blocco di codice, con tutti gli input e gli output. Questo non è solo un ottimo strumento per apprendere il blocco di codice, ma consente anche di utilizzare un grafico di Dynamo più efficiente e parametrico. Per concludere l'esercizio riportato di seguito, utilizzare Nodo da aggiungere al codice.

Esercizio: Attrattore di superficie

Scaricare il file di esempio facendo clic sul collegamento seguente.

Un elenco completo di file di esempio è disponibile nell'Appendice.

14KB
Dynamo-Syntax_Attractor-Surface.dyn
Open

Per mostrare l'efficacia del blocco di codice, verrà convertita una definizione di campo attrattore esistente nel formato blocco di codice. L'utilizzo di una definizione esistente dimostra come il blocco di codice si correla allo scripting visivo ed è utile per apprendere la sintassi di DesignScript.

Iniziare ricreando la definizione nell'immagine riportata sopra (o aprendo il file di esempio).

  1. Notare che il collegamento in Point.ByCoordinates è stato impostato su Globale.

  2. Ogni punto di una griglia viene spostato verso l'alto nella direzione Z in base alla sua distanza dal punto di riferimento.

  3. Viene ricreata e ispessita una superficie, creando una bombatura nella geometria rispetto alla distanza dal punto di riferimento.

  1. Partendo dall'inizio, definire innanzitutto il punto di riferimento: Point.ByCoordinates(x,y,0);. Viene utilizzata la stessa sintassi di Point.ByCoordinates specificata nella parte superiore del nodo del punto di riferimento.

  2. Le variabili x e y vengono inserite in Code Block in modo che sia possibile aggiornarle dinamicamente con i dispositivi di scorrimento.

  3. Aggiungere alcuni dispositivi di scorrimento agli input di Code Block che vanno da -50 a 50. In questo modo, è possibile estendersi in tutta la griglia di default di Dynamo.

  1. Nella seconda riga di Code Block, definire una sintassi abbreviata per sostituire il nodo della sequenza numerica: coordsXY = (-50..50..#11);. Se ne discuterà più in dettaglio nella prossima sezione. Per il momento, notare che questo metodo abbreviato è equivalente al nodo Number Sequence nello script visivo.

  1. A questo punto, si desidera creare una griglia di punti dalla sequenza coordsXY. A tale scopo, si desidera utilizzare la sintassi di Point.ByCoordinates, ma è anche necessario avviare un collegamento Globale dell'elenco nello stesso modo di quello utilizzato nello script visivo. A tale scopo, digitare la riga: gridPts = Point.ByCoordinates(coordsXY<1>,coordsXY<2>,0);. Le parentesi angolari indicano il riferimento Globale.

  2. Notare nel nodo Watch3D che è presente una griglia di punti nella griglia di Dynamo.

  1. Ora per la parte complessa: si desidera spostare la griglia di punti verso l'alto in base alla loro distanza dal punto di riferimento. Innanzitutto, denominare questo nuovo gruppo di punti transPts. E poiché la traslazione è un'azione su un elemento esistente, anziché utilizzare Geometry.Translate..., utilizzare gridPts.Translate.

  2. Leggendo dal nodo effettivo nell'area di disegno, si noterà che sono presenti tre input. La geometria da traslare è già stata dichiarata perché si sta eseguendo l'azione su quell'elemento (con gridPts.Translate). I due input rimanenti verranno inseriti tra le parentesi della funzione: direction e distance.

  3. direction è abbastanza semplice. Per spostarla verticalmente, utilizzare Vector.ZAxis().

  4. distance tra il punto di riferimento e ogni punto della griglia deve ancora essere calcolata, pertanto è necessario eseguire questa operazione come azione per il punto di riferimento nello stesso modo: refPt.DistanceTo(gridPts).

  5. La riga di codice finale fornisce i punti traslati: transPts=gridPts.Translate(Vector.ZAxis(),refPt.DistanceTo(gridPts));.

  1. Ora si ha una griglia di punti con la struttura di dati appropriata per creare una superficie NURBS. Costruire la superficie utilizzando srf = NurbsSurface.ByControlPoints(transPts);.

  1. E infine, per aggiungere profondità alla superficie, costruire un solido utilizzando solid = srf.Thicken(5);. In questo caso, la superficie è stata ispessita di 5 unità nel codice, ma la si potrebbe sempre dichiarare come variabile (ad esempio, chiamandola thickness) e poi controllare quel valore con un dispositivo di scorrimento.

Semplificazione del grafico con Nodo da aggiungere al codice

La funzionalità Nodo da aggiungere al codice consente di automatizzare l'intero esercizio appena completato facendo clic su un pulsante. Questa funzione non solo è efficiente per la creazione di definizioni personalizzate e blocchi di codice riutilizzabili, ma è anche uno strumento molto utile per apprendere come eseguire lo script in Dynamo:

  1. Iniziare con lo script visivo esistente del passaggio 1 dell'esercizio. Selezionare tutti i nodi, fare clic con il pulsante destro del mouse sull'area di disegno e selezionare Nodo da aggiungere al codice. È semplicissimo.

Dynamo dispone di una versione automatizzata basata su testo del grafico visivo, del collegamento e di tutto il resto. Verificare tutto questo negli script visivi e sfruttare la potenza del blocco di codice.

Sintassi abbreviata

Sintassi abbreviata

Nel blocco di codice esistono alcuni metodi di sintassi abbreviata di base che, in poche parole, rendono la gestione dei dati molto più facile. Le nozioni di base riportate di seguito verranno analizzate e sarà descritto come utilizzare questa sintassi abbreviata sia per la creazione che per l'esecuzione di una query sui dati.

Sintassi aggiuntiva

Intervalli e sequenze

Il metodo per la definizione di intervalli e sequenze può essere ridotto ad una sintassi abbreviata di base. Utilizzare l'immagine riportata di seguito come guida per la sintassi "..." per definire un elenco di dati numerici con il blocco di codice. Dopo aver appreso come eseguire questa notazione, la creazione di dati numerici è un processo davvero efficiente:

  1. In questo esempio, un intervallo di numeri viene sostituito dalla sintassi di Code Block di base che definisce beginning..end..step-size;. Rappresentata numericamente, si ottiene: 0..10..1;.

  2. Notare che la sintassi 0..10..1; è equivalente a 0..10;. Una dimensione di incremento di 1 è il valore di default per la notazione della sintassi abbreviata. Pertanto, 0..10; darà una sequenza da 0 a 10 con una dimensione di incremento di 1.

  3. L'esempio di sequenza è simile, ad eccezione del fatto che viene utilizzato un simbolo "#" per indicare che nell'elenco si desiderano 15 valori, anziché un elenco che arriva fino a 15. In questo caso, si sta definendo: beginning..#ofSteps..step-size:. La sintassi effettiva per la sequenza è 0..#15..2.

  4. Utilizzando il simbolo "#" del passaggio precedente, è ora possibile posizionarlo nella parte "step-size" della sintassi. Ora, è presente un intervallo di numeri che si estende dall'"inizio" alla "fine" e la notazione "step-size" distribuisce uniformemente un numero di valori tra i due: beginning..end..#ofSteps.

Intervalli avanzati

La creazione di intervalli avanzati consente di utilizzare l'elenco di elenchi in modo semplice. Negli esempi riportati di seguito, si isola una variabile dalla notazione dell'intervallo primario e si crea un altro intervallo di tale elenco.

1. Creando intervalli nidificati, confrontare la notazione con un simbolo "#" rispetto alla notazione senza. La stessa logica si applica agli intervalli di base, tranne per il fatto che diventa un po' più complesso.

2. È possibile definire un sottointervallo in qualsiasi punto dell'intervallo primario e notare che si possono anche avere due sottointervalli.

3. Controllando il valore di "fine" in un intervallo, si creano più intervalli di lunghezze differenti.

Come esercizio logico, confrontare le due sintassi abbreviate riportate sopra e provare ad analizzare il modo in cui i sottointervalli e la notazione # determinano l'output risultante.

Creazione di elenchi e recupero di voci da un elenco

Oltre a creare elenchi con la sintassi abbreviata, è anche possibile creare elenchi al volo. Questo elenco può contenere una vasta gamma di tipi di elementi e può anche essere sottoposto ad una query (ricordare che gli elenchi sono oggetti di per sé). Per riepilogare, con Code Block si creano elenchi e si esegue una query sulle voci di un elenco con le parentesi quadre:

1. Creare rapidamente elenchi con stringhe ed eseguire una query su di essi utilizzando l'indice delle voci.

2. Create elenchi con variabili ed eseguire una query utilizzando la notazione della sintassi abbreviata dell'intervallo.

La gestione di elenchi nidificati è un processo simile. Tenere presente l'ordine dell'elenco e richiamarlo utilizzando più gruppi di parentesi quadre:

1. Definire un elenco di elenchi.

2. Eseguire una query su un elenco con la notazione della parentesi quadra singola.

3. Eseguire una query su una voce con la notazione della parentesi quadra doppia.

Esercizio: Superficie seno

Scaricare il file di esempio facendo clic sul collegamento seguente.

Un elenco completo di file di esempio è disponibile nell'Appendice.

In questo esercizio, si mostreranno le nuove competenze in termini di sintassi abbreviata per creare una bizzarra superficie di guscio definita da intervalli e formule. Durante questo esercizio, notare come si utilizzano il blocco di codice e i nodi di Dynamo esistenti contemporaneamente: viene utilizzato il blocco di codice per l'elaborazione di dati di grandi dimensioni, mentre i nodi di Dynamo vengono disposti visivamente per la leggibilità della definizione.

Iniziare creando una superficie collegando i nodi riportati sopra. Anziché utilizzare un nodo del numero per definire la larghezza e la lunghezza, fare doppio clic sull'area di disegno e digitare 100; in un Code Block.

  1. Definire un intervallo compreso tra 0 e 1 con 50 divisioni digitando 0..1..#50 in un Code Block.

  2. Collegare l'intervallo a Surface.PointAtParameter, che utilizza i valori u e v compresi tra 0 e 1 sulla superficie. Ricordarsi di modificare Collegamento in Globale facendo clic con il pulsante destro del mouse sul nodo Surface.PointAtParameter.

In questo passaggio, si utilizza la prima funzione per spostare la griglia di punti verso l'alto nella direzione Z. Questa griglia determinerà una superficie generata in base alla funzione sottostante. Aggiungere nuovi nodi come mostrato nell'immagine seguente.

  1. Utilizziamo un Code Block con la riga: (0..Math.Sin(x*360)..#50)*5;. Per suddividerlo rapidamente, definire un intervallo con una formula al suo interno. Questa formula è la funzione seno. La funzione seno riceve gli input di gradi in Dynamo, pertanto per ottenere un'onda seno completa, è necessario moltiplicare i valori x (questo è l'input di intervallo da 0 a 1) per 360. Successivamente, si desidera che il numero di divisioni corrisponda a quello dei punti della griglia di controllo per ogni riga, pertanto si definiscono 50 suddivisioni con #50. Infine, il moltiplicatore 5 aumenta semplicemente l'ampiezza della traslazione in modo da poter vedere l'effetto nell'anteprima di Dynamo.

  1. Sebbene il Code Block precedente funzionasse correttamente, non era completamente parametrico. Si desidera animare dinamicamente i relativi parametri, pertanto si sostituirà la riga del passaggio precedente con (0..Math.Sin(x*360*cycles)..#List.Count(x))*amp;. In questo modo è possibile definire questi valori in base agli input.

Modificando i dispositivi di scorrimento (compresi tra 0 e 10), si ottengono alcuni risultati interessanti.

  1. Eseguendo una trasposizione sull'intervallo di numeri, si inverte la direzione dell'onda della tenda: transposeList = List.Transpose(sineList);.

  1. Quando si aggiungono sineList e tranposeList, viene visualizzata una superficie di guscio distorta: eggShellList = sineList+transposeList;.

Modifichiamo i valori dei dispositivi di scorrimento specificati qui sotto per ottenere un algoritmo che consenta un maggiore controllo sulla superficie.

Infine, si esegue una query su parti isolate dei dati con Code Block. Per rigenerare la superficie con un intervallo specifico di punti, aggiungere il blocco di codice riportato sopra tra i nodi Geometry.Translate e NurbsSurface.ByPoints. Contiene la riga di testo: sineStrips[0..15..1];. Verranno selezionate le prime 16 righe di punti (su 50). Ricreando la superficie, si può vedere che è stata generata una parte isolata della griglia di punti.

  1. Nel passaggio finale, per rendere Code Block più parametrico, eseguire la query utilizzando un dispositivo di scorrimento compreso tra 0 e 1. Questa operazione viene eseguita con la seguente riga di codice: sineStrips[0..((List.Count(sineStrips)-1)*u)];. Ciò può sembrare confuso, ma la riga di codice offre un modo rapido per scalare la lunghezza dell'elenco in un moltiplicatore compreso tra 0 e 1.

Un valore di 0.53 nel dispositivo di scorrimento consente di creare una superficie appena oltre il punto medio della griglia.

Come previsto, un dispositivo di scorrimento di 1 crea una superficie dalla griglia completa di punti.

Osservando il grafico visivo, è possibile evidenziare i Code Block e vedere ciascuna delle loro funzioni.

1. Il primo Code Block sostituisce il nodo Number.

2. Il secondo Code Block sostituisce il nodo Range.

3. Il terzo Code Block sostituisce i nodi List.Transpose, List.Count e Number Range.

4. Il quarto Code Block esegue una query su un elenco di elenchi, sostituendo il nodo List.GetItemAtIndex.

Tipo dati

Dynamo standard

Equivalente a Code Block

Numeri

Stringhe

Sequenze

Intervalli

Recupero di una voce nell'indice

Creazione di un elenco

Concatenazione di stringhe

Istruzioni condizionali

Nodo/i

Equivalente a Code Block

Nota

Qualsiasi operatore (+, &&, >=, Not e così via)

+, &&, >=, !, e così via.

Notare che "Not" diventa "!", ma il nodo viene chiamato "Not" per distinguerlo da "Factorial"

Boolean True

true;

Notare la lettera minuscola

Boolean False

false;

Notare la lettera minuscola

20KB
Obsolete-Nodes_Sine-Surface.dyn
Open

Python e Revit

Python e Revit

Ora che è stato dimostrato come utilizzare gli script di Python in Dynamo, verrà esaminato il collegamento delle librerie di Revit nell'ambiente di scripting. Tenere presente che sono stati importati i nodi standard di Python e i nodi principali di Dynamo con le prime tre righe del blocco di codice riportato di seguito. Per importare i nodi di Revit, gli elementi di Revit e la gestione dei documenti di Revit, è necessario aggiungere solo alcune righe:

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

Questo consente di accedere all'API di Revit e offre scripting personalizzato per qualsiasi operazione di Revit. Combinando il processo di programmazione visiva con lo scripting, la collaborazione e lo sviluppo di strumenti dell'API di Revit, si ottiene un miglioramento significativo. Ad esempio, un responsabile BIM e un progettista di schemi possono lavorare insieme sullo stesso grafico. In questa collaborazione, possono migliorare la progettazione e l'esecuzione del modello.

API specifiche della piattaforma

Il piano che sta dietro al progetto di Dynamo è quello di ampliare l'ambito di implementazione della piattaforma. Poiché Dynamo aggiunge altri programmi all'elenco di casi, gli utenti potranno accedere alle API specifiche della piattaforma dall'ambiente di scripting di Python. Sebbene Revit sia il case study di questa sezione, è possibile prevedere altri capitoli in futuro che offrono esercitazioni complete sullo scripting in altre piattaforme. Inoltre, ora sono disponibili numerose librerie di IronPython, che possono essere importate in Dynamo.

Negli esempi riportati di seguito sono illustrati modi per implementare operazioni specifiche di Revit da Dynamo utilizzando Python. Per una revisione più dettagliata sulla relazione di Python con Dynamo e Revit, fare riferimento alla pagina Wiki di Dynamo. Un'altra utile risorsa per Python e Revit è il progetto Revit Python Shell.

Esercizio 1

Creare un nuovo progetto di Revit.

Scaricare il file di esempio facendo clic sul collegamento seguente.

Un elenco completo di file di esempio è disponibile nell'Appendice.

2KB
Revit-Doc.dyn
Open

In questi esercizi, verranno esaminati gli script di Python elementari in Dynamo for Revit. L'esercizio si concentrerà sull'utilizzo di file ed elementi di Revit, nonché sulla comunicazione tra Revit e Dynamo.

Questo è un metodo molto semplice per il recupero di doc, uiapp e app del file di Revit collegato alla sessione di Dynamo. I programmatori che hanno lavorato in precedenza nell'API di Revit possono notare le voci dell'elenco di controllo. Se questi elementi non risultano familiari, sarà possibile utilizzare altri esempi negli esercizi riportati di seguito.

Di seguito è mostrato il modo in cui si importano i servizi di Revit e si recuperano i dati dei documenti in Dynamo.

Osservare il nodo Python in Dynamo. Il codice è disponibile anche di seguito:

# 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]

Esercizio 2

Scaricare il file di esempio facendo clic sul collegamento seguente.

Un elenco completo di file di esempio è disponibile nell'Appendice.

10KB
Revit-ReferenceCurve.dyn
Open

In questo esercizio, verrà creata una semplice curva di modello in Revit mediante il nodo Python di Dynamo.

Iniziare creando una nuova famiglia di masse concettuali in Revit.

Aprire la cartella Conceptual Mass e utilizzare il file modello Metric Mass.rft.

In Revit, utilizzare il tasto di scelta rapida un per visualizzare le impostazioni Unità di misura, quindi modificare l'unità di lunghezza in metri.

Avviare Dynamo e creare il gruppo di nodi nell'immagine riportata sotto. Innanzitutto, verranno creati due punti di riferimento in Revit dai nodi di Dynamo.

  1. Creare un Code Block e assegnargli un valore di "0;".

  2. Collegare questo valore ad un nodo ReferencePoint.ByCoordinates per gli input X, Y e Z.

  3. Creare tre dispositivi di scorrimento, compresi tra -100 e 100, con una dimensione di incremento pari a 1.

  4. Collegare ogni dispositivo di scorrimento ad un nodo ReferencePoint.ByCoordinates.

  5. Aggiungere un nodo Python all'area di lavoro, fare clic sul pulsante + sul nodo per aggiungere un altro input e collegare i due punti di riferimento ad ogni input. Aprire il nodo Python.

Osservare il nodo Python in Dynamo. Per il codice completo, vedere di seguito.

  1. System.Array: Revit richiede una matrice di sistema come input (anziché un elenco di Python). Si tratta solo di un'altra riga di codice, ma prestare attenzione ai tipi di argomento faciliterà la programmazione di Python in Revit.

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)

In Dynamo, sono stati creati due punti di riferimento con una linea che li collega utilizzando Python. Si aumenterà un po' il livello di complessità nel prossimo esercizio.

Esercizio 3

Scaricare il file di esempio facendo clic sul collegamento seguente.

Un elenco completo di file di esempio è disponibile nell'Appendice.

3MB
Revit-StructuralFraming.zip
archive
Open

Questo esercizio semplifica la procedura, ma enfatizza gli argomenti relativi al collegamento di dati e geometria da Revit a Dynamo e viceversa. Per iniziare, aprire Revit-StructuralFraming.rvt. Una volta aperto il file, avviare Dynamo e aprire il file Revit-StructuralFraming.dyn.

Questo file di Revit contiene dati di base. Due curve di riferimento: una disegnata sul livello 1 e l'altra sul livello 2. Si desidera ottenere queste curve in Dynamo e mantenere un collegamento attivo.

In questo file è presente un gruppo di nodi che si collegano a cinque input di un nodo Python.

  1. Nodi Select Model Element: fare clic sul pulsante Seleziona per ogni elemento e selezionare una curva corrispondente in Revit.

  2. Code Block: utilizzando la sintassi 0..1..#x;, collegare un dispositivo di scorrimento di numeri interi compreso tra 0 e 20 all'input x. Questo indica il numero di travi da disegnare tra le due curve.

  3. Structural Framing Types: dal menu a discesa, scegliere la trave di default W12x26.

  4. Levels: selezionare "Livello 1".

Questo codice in Python è un po' più denso, ma i commenti all'interno del codice descrivono cosa sta accadendo nel processo:

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)

In Revit, è presente una serie di travi che si estendono sulle due curve come elementi strutturali. Nota: questo non è un esempio realistico; gli elementi strutturali vengono utilizzati come esempio per le istanze native di Revit create da Dynamo.

In Dynamo, è possibile visualizzare anche i risultati. Le travi del nodo Watch 3D fanno riferimento alla geometria sottoposta a query dagli elementi di Revit.

Notare che è presente un processo continuo di conversione dei dati dall'ambiente di Revit all'ambiente di Dynamo. In sintesi, ecco come viene riprodotto il processo:

  1. Selezionare l'elemento di Revit.

  2. Convertire l'elemento di Revit nella curva di Dynamo.

  3. Dividere la curva di Dynamo in una serie di punti di Dynamo.

  4. Utilizzare i punti di Dynamo tra due curve per creare le linee di Dynamo.

  5. Creare le travi di Revit facendo riferimento alle linee di Dynamo.

  6. Generare le superfici di Dynamo eseguendo una query sulla geometria delle travi di Revit.

Questo processo può sembrare un po' complicato, ma lo script lo rende semplice quanto la modifica della curva in Revit e la riesecuzione del risolutore (anche se potrebbe essere necessario eliminare le travi precedenti quando si esegue questa operazione). Ciò è dovuto al fatto che si stanno posizionando le travi in Python, interrompendo così l'associazione che hanno i nodi OOTB.

Con un aggiornamento delle curve di riferimento in Revit, si ottiene una nuova serie di travi.

Traslazione, rotazione e altre trasformazioni

Alcuni oggetti della geometria possono essere creati indicando in modo esplicito le coordinate x, y e z nello spazio tridimensionale. Più spesso, tuttavia, la geometria viene spostata nella sua posizione finale utilizzando le trasformazioni geometriche sull'oggetto stesso o sul relativo CoordinateSystem sottostante.

Conversione

La trasformazione geometrica più semplice è una traslazione, che sposta un oggetto in base ad un numero specificato di unità nelle direzioni x, y e 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);

Rotazione

Sebbene tutti gli oggetti in Dynamo possano essere convertiti aggiungendo il metodo .Translate alla fine del nome dell'oggetto, le trasformazioni più complesse richiedono la trasformazione dell'oggetto da un CoordinateSystem sottostante ad un nuovo CoordinateSystem. Ad esempio, per ruotare un oggetto di 45 gradi attorno all'asse x, è necessario trasformare l'oggetto dal CoordinateSystem esistente senza rotazione ad un CoordinateSystem che è stato ruotato di 45 gradi attorno all'asse x con il metodo .Transform:

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);

Scala

Oltre a essere traslati e ruotati, è possibile creare anche CoordinateSystems messi in scala o tagliati. Un CoordinateSystem può essere messa in scala con il metodo .Scale:

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);

I CoordinateSystems tagliati vengono creati mediante l'inserimento di vettori non ortogonali nel costruttore CoordinateSystem.

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);

La messa in scala e il taglio sono trasformazioni geometriche relativamente più complesse rispetto alla rotazione e alla traslazione, pertanto non tutti gli oggetti di Dynamo possono essere sottoposti a queste trasformazioni. Nella seguente tabella sono riportati i contorni degli oggetti di Dynamo che possono presentare CoordinateSystem messi in scala in modo non uniforme e i CoordinateSystem tagliati.

Classe
CoordinateSystem messo in scala in modo non uniforme
CoordinateSystem tagliato

Arco

No

No

NurbsCurve

Sì

Sì

NurbsSurface

No

No

Cerchio

No

No

Linea

Sì

Sì

Piano

No

No

Punto

Sì

Sì

Poligono

No

No

Uniforme

No

No

Superficie

No

No

Testo

No

No

Nodi Python

Perché è opportuno utilizzare la programmazione testuale nell'ambiente di programmazione visiva di Dynamo? La programmazione visiva offre molti vantaggi. Consente di creare programmi senza apprendere una sintassi speciale in un'interfaccia visiva intuitiva. Tuttavia, un programma visivo può diventare disordinato e a volte può risultare carente in termini di funzionalità. Ad esempio, Python offre metodi molto più facili da realizzare per la scrittura di istruzioni condizionali (if/then) e il loop. Python è un potente strumento in grado di ampliare le funzionalità di Dynamo e di consentire di sostituire molti nodi con alcune righe di codice concise.

Programma visivo:

Programma testuale:

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

Nodo Python

Come i blocchi di codice, i nodi Python sono un'interfaccia di script all'interno di un ambiente di programmazione visiva. Il nodo Python è disponibile in Script>Editor>Script Python nella libreria.

Facendo doppio clic sul nodo, viene aperto l'editor di script Python. È inoltre possibile fare clic con il pulsante destro del mouse sul nodo e scegliere Modifica. Si noterà del testo boilerplate in alto, che è utile per fare riferimento alle librerie necessarie. Gli input vengono memorizzati nella matrice IN. I valori vengono restituiti a Dynamo assegnandoli alla variabile OUT.

La libreria Autodesk.DesignScript.Geometry consente di utilizzare la notazione punto analogamente ai blocchi di codice. Per ulteriori informazioni sulla sintassi di Dynamo, fare riferimento a https://github.com/DynamoDS/DynamoPrimerNew/blob/master-ita/coding-in-dynamo/7_code-blocks-and-design-script/7-2_design-script-syntax.md e a DesignScript Guide (per scaricare questo documento PDF, fare clic con il pulsante destro del mouse sul collegamento e scegliere Salva link con nome...). Digitando un tipo di geometria, ad esempio Point., verrà visualizzato un elenco di metodi per la creazione e l'esecuzione di una query sui punti.

I metodi includono costruttori quali ByCoordinates, azioni quali Add e query quali le coordinate X, Y e Z.

Esercizio: Nodo personalizzato con script Python per la creazione di motivi da un modulo solido

Parte I: Impostazione dello script Python

Scaricare il file di esempio facendo clic sul collegamento seguente.

Un elenco completo di file di esempio è disponibile nell'Appendice.

35KB
Python_Custom-Node.dyn
Open

In questo esempio, si scriverà uno script di Python che crea modelli da un modulo solido e lo si trasformerà in un nodo personalizzato. Innanzitutto, creare il modulo solido utilizzando i nodi di Dynamo.

  1. Rectangle.ByWidthLength: creare un rettangolo che sarà la base del solido.

  2. Surface.ByPatch: collegare il rettangolo all'input "closedCurve" per creare la superficie inferiore.

  1. Geometry.Translate: collegate il rettangolo all'input "geometry" per spostarlo verso l'alto, utilizzando un blocco di codice per specificare lo spessore di base del solido.

  2. Polygon.Points: eseguire la query sul rettangolo traslato per estrarre i punti degli angoli.

  3. Geometry.Translate: utilizzare un blocco di codice per creare un elenco di quattro valori corrispondenti ai quattro punti, traslando un angolo del solido verso l'alto.

  4. Polygon.ByPoints: utilizzare i punti traslati per ricreare il poligono superiore.

  5. Surface.ByPatch: collegare il poligono per creare la superficie superiore.

Ora che sono presenti le superfici superiore e inferiore, creati i lati del solido tramite loft tra i due profili.

  1. List.Create: collegare il rettangolo inferiore e il poligono superiore agli input dell'indice.

  2. Surface.ByLoft: eseguire il loft dei due profili per creare i lati del solido.

  3. List.Create: collegare le superfici superiore, laterale e inferiore agli input dell'indice per creare un elenco di superfici.

  4. Solid.ByJoinedSurfaces: unire le superfici per creare il modulo solido.

Ora che è stato realizzato il solido, rilasciare un nodo Script Python nell'area di lavoro.

  1. Per aggiungere altri input al nodo, fare clic sull'icona + sul nodo. Gli input sono denominati IN[0], IN[1] e così via per indicare che rappresentano le voci di un elenco.

Iniziare definendo gli input e l'output. Fare doppio clic sul nodo per aprire l'editor di Python. Seguire il codice riportato qui sotto per modificare il codice nell'editor.

# 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

Questo codice risulterà più utile mentre si prosegue nell'esercizio. Successivamente, occorre pensare alle informazioni necessarie per includere in una matrice il modulo solido. Per prima cosa, è necessario conoscere le quote del solido per determinare la distanza di traslazione. A causa di un bug del riquadro di delimitazione, è necessario utilizzare la geometria della curva dello spigolo per creare un riquadro di delimitazione.

Osservare il nodo Python in Dynamo. Si noti che viene utilizzata la stessa sintassi presente nei titoli dei nodi in Dynamo. Consultare il codice commentato qui sotto.

# 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

Poiché si eseguiranno sia la traslazione che la rotazione dei moduli solidi, utilizzare l'operazione Geometry.Transform. Guardando il nodo Geometry.Transform, si sa che per trasformare il solido sarà necessario un sistema di coordinate di origine e un sistema di coordinate di destinazione. L'origine è il sistema di coordinate contestuale del solido, mentre la destinazione sarà un sistema di coordinate diverso per ogni modulo incluso nella matrice. Ciò significa che si dovrà riprodurre a ciclo continuo i valori X e Y per trasformare il sistema di coordinate in modo diverso ogni volta.

# 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

Fare clic su Esegui, quindi salvare il codice. Collegare il nodo Python con lo script esistente come indicato di seguito.

  1. Collegare l'output da Solid.ByJoinedSurfaces come primo input per il nodo Python e utilizzare un Code Block per definire gli altri input.

  2. Creare un nodo Topology.Edges e utilizzare l'output del nodo Python come input.

  3. Infine, creare un nodo Edge.CurveGeometry e utilizzare l'output di Topology.Edges come input.

Provare a modificare il valore iniziale (seme) per creare modelli diversi. È anche possibile modificare i parametri del modulo solido stesso per effetti differenti.

Parte II: Conversione del nodo dello script Python in nodo personalizzato

Dopo aver creato uno script di Python utile, salvarlo come nodo personalizzato. Selezionare il nodo dello script Python, fare clic con il pulsante destro del mouse su Area di lavoro e selezionare Crea nodo personalizzato.

Assegnare un nome, una descrizione e una categoria.

Verrà aperta una nuova area di lavoro in cui modificare il nodo personalizzato.

  1. Input: modificare i nomi di input in modo che siano più descrittivi e aggiungere i tipi di dati e i valori di default.

  2. Output: consente di modificare il nome di output.

Salvare il nodo come file .dyf e il nodo personalizzato dovrebbe riflettere le modifiche appena apportate.

Superfici: punti interpolati e di controllo, loft, rivoluzione

L'analogia bidimensionale con una NurbsCurve è la NurbsSurface e, come la NurbsCurve di forma libera, le NurbsSurface possono essere costruite con due metodi di base: l'inserimento di un insieme di punti base con l'interpolazione di Dynamo tra di essi e l'indicazione esplicita dei punti di controllo della superficie. Come per le curve a mano libera, le superfici interpolate sono utili quando un progettista conosce con precisione la forma che una superficie deve assumere o se un progetto richiede che la superficie attraversi punti di vincolo. Dall'altra parte, le superfici create mediante punti di controllo possono essere più utili per la progettazione esplorativa in diversi livelli di levigatezza.

Superficie interpolata

Per creare una superficie interpolata, è sufficiente generare una raccolta bidimensionale di punti che si avvicinano alla forma di una superficie. La raccolta deve essere rettangolare, ovvero non irregolare. Il metodo NurbsSurface.ByPoints costruisce una superficie da questi punti.

// 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);

Superficie con punti di controllo

Le NurbsSurface di forma libera possono essere create anche specificando i punti di controllo sottostanti di una superficie. Come per le NurbsCurve, i punti di controllo possono essere considerati come la rappresentazione di una mesh quadrilatera con segmenti retti, che, a seconda del grado della superficie, viene levigata nella forma della superficie finale. Per creare una NurbsSurface tramite punti di controllo, includere due parametri aggiuntivi a NurbsSurface.ByPoints, indicando i gradi delle curve sottostanti in entrambe le direzioni della superficie.

// 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);

È possibile aumentare il grado della NurbsSurface per modificare la geometria della superficie risultante:

// 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);

Superficie di loft

Così come è possibile creare le superfici interpolando un insieme di punti di input, è possibile crearle interpolando un insieme di curve di base. Questa procedura è denominata loft. Viene creata una curva di loft utilizzando il costruttore Surface.ByLoft, con una raccolta di curve di input come unico parametro.

// 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]);

Superficie di rivoluzione

Le superfici di rivoluzione sono un tipo aggiuntivo di superficie creato tramite l'estrusione di una curva di base attorno ad un asse centrale. Se le superfici interpolate sono l'analogia bidimensionale con le curve interpolate, le superfici di rivoluzione sono l'analogia bidimensionale con i cerchi e gli archi.

Le superfici di rivoluzione sono specificate da una curva di base, che rappresenta lo "spigolo" della superficie; l'origine di un asse, il punto base della superficie; la direzione di un asse, la direzione centrale; un angolo iniziale di sweep e un angolo finale di sweep. Questi vengono utilizzati come input per il costruttore Surface.Revolve.

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);

Modifiche al linguaggio

Nella presente sezione è fornita una panoramica degli aggiornamenti e delle modifiche apportate al linguaggio in Dynamo in ogni versione. Queste modifiche possono influire sulla funzionalità, sulle prestazioni e sull'utilizzo e questa guida aiuterà gli utenti a capire quando e perché adattarsi a questi aggiornamenti.

Modifiche al linguaggio di Dynamo 2.0

  1. La sintassi di list@level è stata cambiata passando da "@-1" a "@L1".

  • È stata progettata una nuova sintassi per list@level, per utilizzare list@L1 invece di list@-1.

  • La motivazione è quella di allineare la sintassi del codice con l'anteprima/interfaccia utente; i test degli utenti dimostrano che la nuova sintassi è più comprensibile.

  1. Sono stati implementati i tipi Int e Double in TS per allinearli ai tipi di Dynamo.

  2. Non sono consentite funzioni in overload in cui gli argomenti differiscono solo in base alla cardinalità.

  • Per default, i grafici precedenti che utilizzano overload rimossi dovrebbero essere impostati sugli overload con classificazione più alta.

  • La motivazione è quella di rimuovere l'ambiguità su quale funzione specifica viene eseguita.

  1. È stato disattivato l'innalzamento di livello delle matrici con le guide per la replica.

  2. Le variabili nei blocchi imperativi sono state rese locali rispetto all'ambito del blocco imperativo.

  • I valori delle variabili definiti all'interno di blocchi di codice imperativi non verranno influenzati dalle modifiche apportate all'interno di blocchi imperativi che vi fanno riferimento.

  1. Le variabili sono state rese immutabili per disattivare l'aggiornamento associativo nei nodi di blocchi di codice.

  2. Tutti i nodi dell'interfaccia utente vengono compilati come metodi statici.

  3. Le dichiarazioni restituite sono supportate senza assegnazione.

  • Il segno "=" non è necessario né nelle definizioni di funzione né nel codice imperativo.

  1. È stata eseguita la migrazione dei nomi dei metodi precedenti nei nodi di blocchi di codice.

  • Molti nodi sono stati rinominati per migliorare la leggibilità e il posizionamento nell'interfaccia utente del Browser libreria.

  1. Viene utilizzato l'elenco come correzione del dizionario.


Problemi noti:

  • I conflitti dello spazio dei nomi nei blocchi imperativi causano la visualizzazione di porte di input impreviste. Per ulteriori informazioni, vedere il . Per ovviare a questo problema, definire la funzione all'esterno del blocco imperativo in questo modo:

Spiegazione delle modifiche al linguaggio di Dynamo 2.0

Sono stati apportati numerosi miglioramenti al linguaggio per la release di Dynamo 2.0. Tra le motivazioni principali c'è la semplificazione del linguaggio. L'enfasi è stata posta sul rendere DesignScript più comprensibile e semplice da utilizzare a favore di una potenza e una flessibilità maggiori, con l'obiettivo di migliorare la comprensibilità per l'utente finale.

Di seguito è riportato l'elenco delle modifiche apportate alla versione 2.0:

  • La sintassi di List@Level è stata semplificata.

  • I metodi in overload con parametri che differiscono solo in base alla classificazione non sono validi.

  • Tutti i nodi dell'interfaccia utente vengono compilati come metodi statici.

  • L'innalzamento di livello dell'elenco è disattivato quando viene utilizzato con le guide per la replica/il collegamento.

  • Le variabili nei blocchi associativi sono immutabili per impedire l'aggiornamento associativo.

  • Le variabili dei blocchi imperativi sono collocate nell'ambito imperativo

  • Esiste una separazione tra elenchi e dizionari.

1. Sintassi di list@level semplificata

È stata progettata una nuova sintassi per list@level, per utilizzare list@L1 invece di list@-1

2. Le funzioni in overload con parametri che differiscono solo in base alla classificazione non sono valide

Le funzioni in overload sono problematiche per diversi motivi:

  • Una funzione in overload indicata da un nodo dell'interfaccia utente nel grafico potrebbe non corrispondere all'overload eseguito in fase di runtime.

  • La risoluzione del metodo è costosa e non è adatta alle funzioni in overload.

  • È difficile comprendere il comportamento della replica per le funzioni in overload.

Prendiamo BoundingBox.ByGeometry come esempio: c'erano due funzioni in overload nelle versioni precedenti di Dynamo, che come argomento richiedevano un valore singolo e un elenco di geometrie rispettivamente:

Se l'utente eliminava il primo nodo nell'area di disegno e collegava un elenco di geometrie, si aspettava che venisse avviata la replica, ma ciò non si verificava mai perché in fase di runtime veniva chiamato il secondo overload come mostrato qui:

Nella versione 2.0 non sono consentite funzioni in overload che differiscono solo nella cardinalità dei parametri per questo motivo. Ciò significa che per le funzioni in overload che hanno lo stesso numero e gli stessi tipi di parametri ma hanno uno o più parametri che differiscono solo per la classificazione, l'overload definito per primo ha sempre la precedenza, mentre gli altri vengono scartati dal compilatore. Il vantaggio principale di questa operazione è quello di semplificare la logica di risoluzione del metodo disponendo di un percorso rapido per selezionare le funzioni candidate.

Nella libreria della geometria per la versione 2.0, il primo overload nell'esempio BoundingBox.ByGeometry è stato eliminato e il secondo è stato mantenuto, quindi se il nodo è destinato alla replica, cioè utilizzato nel contesto del primo, dovrebbe essere utilizzato con l'opzione di collegamento più breve (o più lunga) o in un blocco di codice con le guide per la replica:

In questo esempio possiamo vedere che il nodo con classificazione superiore può essere utilizzato sia in una chiamata replicata che in una non replicata e pertanto è sempre preferibile ad un overload con classificazione inferiore. Come regola generale, pertanto, si consiglia sempre agli autori dei nodi di eliminare gli overload con classificazione inferiore a favore di metodi con classificazione superiore in modo che il compilatore DesignScript chiami sempre il metodo con classificazione più alta come il primo e l'unico che trova.

Esempi:

Nel seguente esempio sono stati definiti due overload della funzione foo. Nella versione 1.x, l'overload eseguito in fase di runtime è ambiguo. L'utente potrebbe aspettarsi l'esecuzione del secondo overload foo(a:int, b:int), nel qual caso il metodo dovrebbe replicarsi tre volte restituendo un valore di 10 triplicato. In realtà quello che viene restituito è un valore singolo di 10, poiché viene chiamato il primo overload con il parametro list.

Il secondo overload viene omesso nella versione 2.0:

Nella versione 2.0, è sempre il primo metodo definito che viene scelto rispetto agli altri. Vale il principio "primo arrivato, primo servito".

Per ognuno dei seguenti casi, verrà utilizzato il primo overload definito. Si noti che si basa esclusivamente sull'ordine di definizione delle funzioni e non sulle classificazioni dei parametri, sebbene sia consigliabile dare la preferenza ai metodi con parametri con classificazione superiore per i nodi definiti dall'utente e zero-touch.

3. Tutti i nodi dell'interfaccia utente vengono compilati come metodi statici.

In Dynamo 1.x, i nodi dell'interfaccia utente (non i blocchi di codice) sono stati compilati rispettivamente come metodi di istanza e proprietà. Ad esempio, il nodo Point.X è stato compilato come pt.X e Curve.PointAtParameter è stato compilato come curve.PointAtParameter(param). Questo comportamento presentava due problemi:

A. La funzione rappresentata dal nodo dell'interfaccia utente non è sempre la stessa funzione eseguita in fase di runtime

Un tipico esempio è il nodo Translate. Esistono più nodi Translate che richiedono lo stesso numero e gli stessi tipi di argomenti, ad esempio: Geometry.Translate, Mesh.Translate e FamilyInstance.Translate. A causa del fatto che i nodi sono stati compilati come metodi di istanza, il passaggio di FamilyInstance ad un nodo Geometry.Translate funzionerebbe sorprendentemente ancora in quanto in fase di runtime invierebbe la chiamata al metodo di istanza Translate in FamilyInstance. Ciò era ovviamente fuorviante per gli utenti, poiché il nodo non funzionava come dichiarato.

B. Il secondo problema era che i metodi di istanza non funzionavano con matrici eterogenee

In fase di runtime, il motore di esecuzione deve individuare la funzione a cui deve essere inviato. Se l'input è un elenco, ad esempio list.Translate(), poiché è costoso esaminare ogni elemento di un elenco e cercare metodi nel suo tipo, la logica di risoluzione del metodo presuppone semplicemente che il tipo di destinazione sia uguale al tipo del primo elemento e tenta di cercare il metodo Translate() definito in quel tipo. Di conseguenza, se il primo tipo di elemento non corrispondeva al tipo di destinazione del metodo (o anche se era null o un elenco vuoto), l'intero elenco aveva esito negativo, anche se erano presenti altri tipi corrispondenti.

Ad esempio, se un input list con i seguenti tipi [Arc, Line] veniva passato in Arc.CenterPoint, il risultato conteneva un punto centrale per l'arco e un valore null per la linea come previsto. Tuttavia, se l'ordine era invertito, l'intero risultato era null poiché il primo elemento non aveva superato la verifica della risoluzione del metodo:

Dynamo 1.x: verifica solo il primo elemento dell'input list per la verifica della risoluzione del metodo

Nella versione 2.0 entrambi questi problemi vengono risolti compilando i nodi dell'interfaccia utente come proprietà statiche e metodi statici.

Con i metodi statici, la risoluzione del metodo di runtime è più semplice e tutti gli elementi nell'input list vengono iterati. Ad esempio:

La semantica di foo.Bar() (metodo di istanza) deve cercare il tipo di foo e anche controllare se si tratta di un elenco o meno e quindi abbinarlo alle funzioni candidate. Tutto questo è costoso. D'altra parte, la semantica di Foo.Bar(foo) (metodo statico) deve verificare solo una funzione con il tipo di parametro foo.

Ecco cosa succede nella versione 2.0:

  • Un nodo di proprietà dell'interfaccia utente viene compilato come un getter statico: il motore genera una versione statica di un getter per ogni proprietà. Ad esempio, un nodo Point.X viene compilato come un getter statico Point.get_X(pt). Si noti che il getter statico può anche essere chiamato utilizzando il relativo alias: Point.X(pt) in un nodo del blocco di codice.

  • Un nodo del metodo dell'interfaccia utente viene compilato come versione statica: il motore genera un metodo statico corrispondente per il nodo. Ad esempio, il nodo Curve.PointAtParameter viene compilato come Curve.PointAtParameter(curve: Curve, parameter:double) anziché come curve.PointAtParameter(parameter).

Nota Con questa modifica, non è stato rimosso il supporto dei metodi di istanza, pertanto i metodi di istanza esistenti utilizzati nei nodi di blocchi di codice, come pt.X e curve.PointAtParameter(parameter) negli esempi precedenti, continueranno a funzionare.

Questo esempio funzionava in precedenza nella versione 1.x, poiché il grafico veniva compilato come point.X; e veniva trovata la proprietà X nell'oggetto punto. Ora ha esito negativo nella versione 2.0 poiché il codice compilato Vector.X(point) prevede solo un tipo Vector:

Vantaggi:

Metodi coerenti/comprensibili: i metodi statici eliminano ogni ambiguità sul metodo da eseguire in fase di runtime. Il metodo corrisponde sempre al nodo dell'interfaccia utente utilizzato nel grafico che l'utente prevede di chiamare.

Metodi compatibili: esiste una migliore correlazione tra il codice e il programma visivo.

Metodi istruttivi: il passaggio di input list eterogenei ai nodi ora genera valori non null per i tipi accettati dal nodo e valori null per i tipi che non implementano il nodo. I risultati sono più prevedibili e forniscono una migliore indicazione dei tipi consentiti per il nodo.

Avviso: ambiguità irrisolte con metodi in overload

Poiché Dynamo supporta in generale gli overload di funzioni, si potrebbe comunque generare confusione se è presente un'altra funzione in overload con lo stesso numero di parametri. Ad esempio, nel seguente grafico, se colleghiamo un valore numerico all'input direction di Curve.Extrude e un vettore all'input distance di Curve.Extrude, entrambi i nodi continuano a funzionare, il che è imprevisto. In questo caso, anche se i nodi vengono compilati come metodi statici, il motore non è ancora in grado di distinguere la differenza in fase di runtime e ne seleziona uno a seconda del tipo di input.

Problemi risolti:

Il passaggio alla semantica del metodo statico ha introdotto i seguenti effetti collaterali, che vale la pena menzionare qui come modifiche correlate al linguaggio della versione 2.0.

1. Perdita di comportamento polimorfico:

Consideriamo un esempio di nodi TSpline in ProtoGeometry (si noti che TSplineTopology eredita dal tipo di Topology base): il nodo Topology.Edges, che è stato precedentemente compilato come metodo di istanza, object.Edges, è ora compilato come metodo statico, Topology.Edges(object). La chiamata precedente si risolveva in modo polimorfico nel metodo della classe derivata TsplineTopology.Edges dopo l'invio di un metodo sul tipo di oggetto in fase di runtime.

Il nuovo comportamento statico, invece, veniva forzato a chiamare il metodo della classe di base, Topology.Edges. Di conseguenza, questo nodo restituiva gli oggetti Edge della classe di base anziché gli oggetti della classe derivata di tipo TSplineEdge.

Si trattava di una regressione perché i nodi TSpline a valle prevedevano che TSplineEdges iniziasse a non funzionare.

Il problema è stato risolto aggiungendo una verifica di runtime nella logica di invio del metodo per cercare il tipo di istanza rispetto al tipo o ad un sottotipo del primo parametro del metodo. Nel caso di un input list, è stato semplificato l'invio del metodo per cercare semplicemente il tipo del primo elemento. Quindi la soluzione finale era un compromesso tra la ricerca di un metodo in parte statico e uno in parte dinamico.

Nuovo comportamento polimorfico nella versione 2.0:

In questo caso, poiché il primo elemento a è TSpline, si tratta del metodo derivato TSplineTopology.Edges che viene richiamato in fase di runtime. Di conseguenza, restituisce null per Topology base di tipo b.

Nel secondo caso, poiché Topology generale di tipo b è il primo elemento, viene chiamato il metodo Topology.Edges di base. Poiché Topology.Edges accetta anche il tipo TSplineTopology derivato, a come input restituisce Edges per entrambi gli input, a e b.

2. Regressioni dovute alla produzione di elenchi esterni ridondanti

Esiste una differenza principale tra i metodi di istanza e i metodi statici per quanto riguarda il comportamento delle guide per la replica. Con i metodi di istanza, gli input a valore singolo con le guide per la replica non vengono alzati di livello ad elenchi, mentre vengono alzati di livello per i metodi statici.

Si consideri l'esempio del nodo Surface.PointAtParameter con il collegamento incrociato e con un singolo input surface e matrici di valori di parametri u e v. Il metodo di istanza viene compilato in:

ottenendo una matrice 2D di punti.

Il metodo statico viene compilato come:

ottenendo un elenco 3D di punti con un elenco più esterno ridondante.

Questo effetto collaterale della compilazione dei nodi dell'interfaccia utente come metodi statici potrebbe causare regressioni nei casi d'uso esistenti. Questo problema è stato risolto disattivando l'innalzamento di livello di input a valore singolo ad elenco quando vengono utilizzati con le guide per la replica/il collegamento (vedere l'elemento successivo).

4. Innalzamento di livello ad elenco disattivato con guide per la replica/collegamento

Nella versione 1.x c'erano due casi in cui valori singoli venivano innalzati al livello di elenco:

  • Quando gli input con classificazione inferiore erano passati nelle funzioni che prevedevano input con classificazione superiore

  • Quando gli input di livello inferiore erano passati nelle funzioni che prevedevano la stessa classificazione ma in cui gli argomenti di input erano caratterizzati dalle guide per la replica o utilizzavano il collegamento

Nella versione 2.0 quest'ultimo caso non è più supportato, pertanto l'innalzamento al livello di elenco in tali scenari non è possibile.

Nel seguente grafico della versione 1.x, un livello di guida per la replica per ognuno dei valori y e z forzava l'innalzamento di livello a matrice con classificazione 1 per ciascuno di essi, motivo per cui il risultato aveva una classificazione 3 (1 ciascuna per x, y e z). L'utente si aspettava invece che il risultato fosse di classificazione 1 poiché non era del tutto ovvio che la presenza di guide per la replica per gli input a valore singolo aggiungesse livelli al risultato.

Dynamo 1.x: elenco 3D di punti

Nella versione 2.0, la presenza di guide per la replica per ognuno degli argomenti a valore singolo y e z non causa un innalzamento di livello determinando un elenco con la stessa dimensione dell'elenco 1D di input per x.

Dynamo 2.0: elenco 1D di punti

La modifica del linguaggio ha risolto anche il problema della regressione di cui sopra, causata dalla compilazione come metodo statico e dalla generazione di elenchi esterni ridondanti.

Continuando con lo stesso esempio precedente, abbiamo visto che una chiamata al metodo statico come:

produceva un elenco 3D di punti in Dynamo 1.x. Ciò si verificava a causa dell'innalzamento di livello del primo argomento a valore singolo surface ad elenco quando veniva utilizzato con una guida per la replica.

Dynamo 1.x: innalzamento di livello dell'argomento ad elenco con la guida per la replica

Nella versione 2.0 è stato disattivato l'innalzamento al livello di elenchi degli argomenti a valore singolo quando vengono utilizzati con le guide per la replica o il collegamento. Quindi ora la chiamata a:

restituisce semplicemente un elenco 2D poiché l'input surface non viene alzato di livello.

Dynamo 2.0: disattivato l'innalzamento al livello di elenco dell'argomento a valore singolo, se utilizzato con una guida per la replica

Questa modifica ora rimuove l'aggiunta di un livello di elenco ridondante e risolve anche la regressione causata dal passaggio alla compilazione come metodo statico.

Vantaggi:

Risultati leggibili: i risultati sono in linea con le aspettative dell'utente e sono più facili da comprendere.

Risultati compatibili: i nodi dell'interfaccia utente (con l'opzione di collegamento) e i nodi di blocchi di codice che utilizzano le guide per la replica offrono risultati compatibili.

Risultati coerenti:

  • I metodi di istanza e quelli statici sono coerenti (si risolvono i problemi relativi alla semantica del metodo statico).

  • I nodi con input e con argomenti di default si comportano in modo coerente (vedere di seguito).

5. Le variabili sono immutabili nei nodi di blocchi di codice per impedire l'aggiornamento associativo

DesignScript supporta storicamente due paradigmi di programmazione: la programmazione associativa e la programmazione imperativa. Il codice associativo crea un grafico delle dipendenze dalle istruzioni del programma in cui le variabili dipendono l'una dall'altra. L'aggiornamento di una variabile può comportare l'aggiornamento di tutte le variabili che dipendono da essa. Ciò significa che la sequenza di esecuzione delle istruzioni in un blocco associativo non si basa sul loro ordine, ma sulle relazioni di dipendenza tra le variabili.

Nel seguente esempio, la sequenza di esecuzione del codice è costituita dalle righe 1 -> 2 -> 3 -> 2. Poiché b ha una dipendenza da a, quando a viene aggiornato nella riga 3, l'esecuzione passa di nuovo alla riga 2 per aggiornare b con il nuovo valore di a.

Al contrario, se lo stesso codice viene eseguito in un contesto imperativo, le istruzioni vengono eseguite in un flusso lineare, dall'alto verso il basso. I blocchi di codice imperativi sono quindi adatti per l'esecuzione sequenziale di costrutti di codice come i loop e le condizioni if-else.

Ambiguità dell'aggiornamento associativo:

1. Variabili con dipendenza ciclica:

In alcuni casi, una dipendenza ciclica tra le variabili potrebbe non essere così ovvia come nel seguente caso. In questi casi, in cui il compilatore non è in grado di rilevare il ciclo in modo statico, potrebbe portare a un ciclo di runtime indefinito.

2. Variabili che dipendono da se stesse:

Se una variabile dipende da se stessa, il suo valore deve accumularsi o deve essere ripristinato il suo valore originale ad ogni aggiornamento?

In questo esempio di geometria, poiché il cubo b dipende da se stesso oltre che dal cilindro, a, lo spostamento del dispositivo di scorrimento dovrebbe far spostare il foro lungo il blocco o dovrebbe creare un effetto cumulativo di creazione di diversi fori lungo il suo percorso per ogni aggiornamento della posizione del dispositivo di scorrimento?

3. Aggiornamento delle proprietà delle variabili:

4. Aggiornamento delle funzioni:

L'esperienza ci insegna che l'aggiornamento associativo non risulta utile nei nodi di blocchi di codice in un contesto del grafico del flusso di dati basato sui nodi. Prima che fosse disponibile qualsiasi ambiente di programmazione visiva, l'unico modo per esplorare le opzioni era quello di modificare in modo esplicito i valori di alcune variabili nel programma. Un programma basato sul testo dispone della cronologia completa degli aggiornamenti di una variabile, mentre in un ambiente di programmazione visiva viene visualizzato solo l'ultimo valore di una variabile.

Se qualche utente l'ha utilizzato, è molto probabile che l'abbia fatto inconsapevolmente, causando più danni che benefici. Pertanto, nella versione 2.0 si è deciso di nascondere l'associatività nell'utilizzo dei nodi di blocchi di codice rendendo le variabili immutabili, pur continuando a mantenere l'aggiornamento associativo solo come funzionalità nativa del motore DesignScript. Questa è un'altra modifica apportata con l'idea di semplificare l'esperienza di scripting per gli utenti.

L'aggiornamento associativo è disattivato nei nodi di blocchi di codice impedendo la ridefinizione delle variabili:

L'indicizzazione dell'elenco è ancora consentita nei blocchi di codice

È stata fatta un'eccezione per l'indicizzazione dell'elenco, che è ancora consentita nella versione 2.0 con l'assegnazione dell'operatore index.

In questo esempio l'elenco a viene inizializzato ma può essere successivamente sovrascritto con l'assegnazione di un operatore index ed eventuali variabili dipendenti da a vengono aggiornate in modo associativo, come si vede dal valore di c. Inoltre, l'anteprima del nodo visualizza i valori aggiornati di a dopo la ridefinizione di uno o più dei suoi elementi.

6. Le variabili dei blocchi imperativi sono collocate nell'ambito del blocco imperativo

Le regole di definizione dell'ambito imperativo sono state modificate nella versione 2.0 per evitare complicati scenari di aggiornamento tra linguaggi differenti.

In Dynamo 1.x, la sequenza di esecuzione del seguente script prevedeva le righe 1 -> 2 -> 4 -> 6 -> 4, dove una modifica veniva propagata dagli ambiti di linguaggio esterni a quelli interni. Poiché il valore y viene aggiornato nel blocco associativo esterno e poiché x nel blocco imperativo ha una dipendenza da y, il controllo passa dal programma associativo esterno al linguaggio imperativo nella riga 4.

La sequenza di esecuzione nell'esempio successivo prevede le righe 1 -> 2 -> 4 -> 2, dove la modifica si propaga dall'ambito di linguaggio interno a quello esterno.

Gli scenari precedenti si riferiscono all'aggiornamento tra i vari linguaggi, che proprio come l'aggiornamento associativo non è molto utile nei nodi di blocchi di codice. Per evitare complicati scenari di aggiornamento tra linguaggio differenti, le variabili sono state rese locali rispetto all'ambito imperativo.

Nel seguente esempio in Dynamo 2.0:

  • Il valore di x definito nel blocco imperativo è ora locale rispetto all'ambito Imperativo.

  • I valori di x e y nell'ambito esterno rimangono rispettivamente 1 e 2.

Qualsiasi variabile locale all'interno di un blocco imperativo deve essere restituita se si desidera accedere al relativo valore in un ambito esterno.

Si consideri il seguente esempio:

  • Il valore di y viene copiato localmente all'interno dell'ambito imperativo.

  • Il valore di x collocato nell'ambito imperativo è 4.

  • L'aggiornamento del valore di y nell'ambito esterno continua a determinare l'aggiornamento di x a causa dell'aggiornamento tra i vari linguaggi, ma è disattivato nei blocchi di codice nella versione 2.0 a causa dell'immutabilità delle variabili.

  • I valori di x e y nell'ambito associativo esterno rimangono rispettivamente 1 e 2.

7. Elenchi e dizionari

In Dynamo 1.x, elenchi e dizionari erano rappresentati da un singolo contenitore unificato, che poteva essere indicizzato sia mediante un indice di numeri interi che da una chiave non integrale. Nella seguente tabella sono riepilogate la separazione tra elenchi e dizionari nella versione 2.0 e le regole del nuovo tipo di dati del dizionario:

1.x
2.0

Nuova sintassi dell'elenco con []

La sintassi di inizializzazione dell'elenco è stata modificata passando dalle parentesi graffe {} alle parentesi quadre [] nella versione 2.0. Viene eseguita automaticamente la migrazione di tutti gli script della versione 1.x alla nuova sintassi quando vengono aperti nella versione 2.0.

Nota sugli attributi degli argomenti di default nei nodi zero-touch:

Si noti, tuttavia, che la migrazione automatica non funzionerà con la vecchia sintassi utilizzata negli attributi degli argomenti di default. Se necessario, gli autori dei nodi devono aggiornare manualmente le definizioni del metodo zero-touch per utilizzare la nuova sintassi negli attributi degli argomenti di default DefaultArgumentAttribute.

Nota sull'indicizzazione:

Il comportamento della nuova indicizzazione è cambiato in alcuni casi. L'indicizzazione in un elenco/dizionario con un elenco arbitrario di indici/chiavi utilizzando l'operatore [] ora mantiene la struttura dell'elenco di input di indici/chiavi. In precedenza restituiva sempre un elenco 1D di valori:

Sintassi di inizializzazione del dizionario:

Il segno {} (la sintassi con parentesi graffe) per l'inizializzazione del dizionario può essere utilizzata solo nel formato di coppia chiave-valore

dove è consentita solo una stringa per <key> e più coppie chiave-valore sono separate da virgole.

Il metodo zero-touch Dictionary.ByKeysValues può essere utilizzato come un modo più versatile per inizializzare un dizionario passando rispettivamente un elenco di chiavi e valori e sfruttando tutti i vantaggi dei metodi zero-touch come le guide per la replica e così via.

Perché non sono state utilizzate espressioni arbitrarie per la sintassi di inizializzazione del dizionario?

Abbiamo sperimentato l'idea di utilizzare espressioni arbitrarie per le chiavi nella sintassi di inizializzazione delle coppie chiave-valore del dizionario e abbiamo scoperto che poteva portare a risultati confusi, soprattutto quando una sintassi come {keys : vals} (dove entrambi gli elementi keys, vals rappresentano elenchi) interferiva con altre caratteristiche del linguaggio di DesignScript come la replica e produceva risultati diversi dal nodo di inizializzazione zero-touch.

Ad esempio, potrebbero esserci altri casi come questa istruzione in cui sarebbe difficile definire il comportamento previsto:

Aggiungere la sintassi delle guide per la replica o altro, invece di limitarsi ai soli identificatori, sarebbe andare contro l'idea di semplicità del linguaggio.

In futuro potremmo estendere le chiavi del dizionario per supportare espressioni arbitrarie, ma dovremmo anche garantire che l'interazione con altre caratteristiche del linguaggio rimanga coerente e comprensibile. Il rischio di rendere il sistema più complesso è quello di sacrificare un po' della sua potenza e facilità d'uso. In ogni caso, c'è sempre un modo alternativo per affrontare questo problema utilizzando il metodo Dictionary.ByKeysValues(keyList, valueList), che non è poi così difficile.

Interazione con nodi zero-touch:

1. Il nodo zero-touch che restituisce un dizionario .NET viene restituito come dizionario di Dynamo

Si consideri il seguente metodo zero-touch C# che restituisce un IDictionary:

Viene eseguito il marshalling del valore restituito del nodo ZT corrispondente come dizionario di Dynamo:

2. I nodi a restituzione multipla vengono visualizzati in anteprima come dizionari

Il nodo zero-touch che restituisce IDictionary con attributo a restituzione multipla restituisce un dizionario di Dynamo:

3. Il dizionario di Dynamo può essere passato come input nel nodo zero-touch che accetta il dizionario .NET

Metodo ZT con un parametro IDictionary:

Il nodo ZT accetta il dizionario di Dynamo come input:

Anteprima del dizionario nei nodi a restituzione multipla

I dizionari sono coppie chiave-valore non ordinate. Coerentemente con questa idea, non è quindi garantito che le anteprime delle coppie chiave-valore dei nodi che restituiscono dizionari siano disposte secondo l'ordine dei valori restituiti dei nodi.

È stata tuttavia fatta un'eccezione per i nodi a restituzione multipla con valori MultiReturnAttribute definiti. Nell seguente esempio, il nodo DateTime.Components è un nodo a restituzione multipla e l'anteprima del nodo riflette le relative coppie chiave-valore in modo che siano nello stesso ordine di quello delle porte di output nel nodo, che è anche l'ordine in cui gli output vengono specificati in base ai valori MultiReturnAttribute nella definizione del nodo.

Si noti inoltre che le anteprime per i blocchi di codice non vengono ordinate diversamente dal nodo dell'interfaccia utente, poiché le informazioni sulla porta di output (sotto forma di un attributo a restituzione multipla) non esistono per il nodo del blocco di codice:

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

Inizializzazione dell'elenco

a = {1, 2, 3};

a = [1, 2, 3];

Elenco vuoto

a = {};

a = [];

Inizializzazione del dizionario

Poteva essere aggiunto allo stesso dizionario in modo dinamico:

È possibile creare solo nuovi dizionari:

a = {};

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

a[“foo”] = 1;

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

a[“bar”] = 2;

a = {}; // Crea un dizionario vuoto

a[“baz”] = 3;

Indicizzazione del dizionario

Indicizzazione delle chiavi

La sintassi di indicizzazione rimane invariata

b = a[“bar”];

b = a[“bar”];

Chiavi del dizionario

Qualsiasi tipo di chiave era valido

Solo le chiavi stringa sono valide

a = {};

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

a[false] = 23;

a[point] = 12;

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" };
problema di Github