Loopcamp con Dynamo: un esercizio di riconnessione
Se non avete mai visto Dynamo, se l’avete visto cinque minuti di striscio o se l’avete visto l’ultima volta cinque anni fa e poi mai più usato, ho sempre trovato che questo fosse un divertente esercizio di riconnessione. Lo faccio in italiano, dato che in inglese esiste già il Dynamo Primer che è un ottimo percorso di introduzione. Ho […]
Se non avete mai visto Dynamo, se l’avete visto cinque minuti di striscio o se l’avete visto l’ultima volta cinque anni fa e poi mai più usato, ho sempre trovato che questo fosse un divertente esercizio di riconnessione. Lo faccio in italiano, dato che in inglese esiste già il Dynamo Primer che è un ottimo percorso di introduzione. Ho pensato di condividerlo con voi, dato che sto elaborando qualcosa di nuovo. Gli screenshot sono estratti da Dynamo 2.0.2, ma verificati anche per le versioni precedenti fino alla 0.9, e la famiglia fornita (più avanti) è in Revit 2019 ma è talmente semplice che non ne avrete bisogno.
Sono una grande fan del Burning Man, come alcuni di voi già sanno. L’esercizio, quindi, prende ispirazione da un’installazione di Stéphane Malka per il Burning Man del 2012.
1. Creare un cilindro
La prima operazione, semplicissima, è creare un cilindro, per entrare nell’ottica di due concetti che ritengo fondamentali:
- Dynamo è un uomo quindi è necessario spiegargli le cose in modo semplice, per gradi, ma non è difficile capirsi con lui se abbiamo chiarezza mentale sul processo di creazione di ciò che vogliamo ottenere: quali sono i passaggi logici per la creazione di un cilindro?
- Un metodo efficace è partire non tanto con la fine in mente (espressione ormai abusata quando si tratta di BIM) quanto proprio partire dalla fine e risalire il percorso.
Seguendo questi due principi, il cilindro è un solido, e quindi un’estrusione dritta, perpendicolare al piano di lavoro, di cui vogliamo poter specificare l’altezza. Ci serve quindi un nodo che “suoni” come ciò che stiamo cercando di far fare a Dynamo: extrude. Personalmente, pesco di preferenza i nodi cliccando sul canvas (la parte bianca dell’interfaccia) con il tasto destro del mouse e utilizzando quella ricerca: ricorro alla ricerca nella barra di sinistra solo se non trovo quello che sto cercando. Cercando “extrude”, troviamo diverse opzioni. Se abbiamo dei dubbi circa quale sia l’estrusione lungo la normale [dal lat. normalis «perpendicolare», der. di norma (v. norma)], le icone nelle spiegazioni contestuali dei nodi dovrebbero chiarire anche i più confusi.
Troviamo due estrusioni lungo una distanza, ma possiamo occuparci in seguito della differenza.
Questo è un buon momento per iniziare a ripassare gli status dei nodi: il nodo ha la barra del titolo in grigio chiaro, quindi non sta ancora facendo nulla. Ha bisogno di qualcosa. Per fortuna sono i nodi stessi a chiarirci di che cosa hanno bisogno per funzionare: in questo caso, per la distanza si può anche arrangiare indovinando un valore, ma non ci può leggere nel pensiero la forma geometrica, quindi ha bisogno di una curva. Per ottenere un cilindro, evidentemente bisogna estrudere un cerchio. Ma cosa ci serve per fare un cerchio? Un re! – diranno subito i miei piccoli lettori. No, ragazzi, avete sbagliato. E purtroppo non ci vuole neanche un burattino.
Posizionando il nodo “Circle by Center Point and Radius”, possiamo recuperare un altro concetto base di Dynamo: certe volte i nodi funzionano anche senza input (e la loro barra è quindi grigio scuro) perché sono corredati da un valore di Default.
L’input c’è, quindi, ma non si vede. Nel nostro caso abbiamo un cerchio di raggio 1 con centro sull’origine del sistema. Possiamo scoprirlo passando con il mouse sugli input vuoti: scopriremo che il nodo dichiara quale sia il suo valore di Default.
Se nessuno se l’è ancora domandato, questo è un buon momento per farsi una domanda piuttosto importante per un progettista.
“Sì, ma 1 cosa?”
Perfetto. Dynamo non ha unità di misura, ma legge l’unità di misura impostata in Revit. E potete cambiargliela, in corsa, tutte le volte che volete: sempre perché Dynamo è un uomo, state pur tranquilli che non se ne accorgerà fino a quando non sarà troppo tardi.
In questo caso, sto lavorando in millimetri ma sto pensando in centimetri, quindi devo cambiare l’unità di misura (e dovrei sapere come si fa). Potrebbe valere la pena di inserire una nota, all’interno dello script, per fare in modo che me ne ricordi anche quando lo riaprirò in hangover tra cinque mesi. Ne creiamo una dal menu Edit > Create Note (oppure Ctrl + W, per i più audaci: attenzione perché il comando potrebbe anche chiudere il file di Revit in background).
Se volete, potete creare un template di partenza per gli script del vostro team, in cui viene sempre visualizzata una porzione di controllo che visualizza le unità attualmente in utilizzo.
Avendo chiarito quindi in che cosa stiamo parlando (centimetri), è giunto il momento di dare istruzioni dimensionali più precise al nostro cilindro: 120 cm di altezza ad esempio, e 45 cm di raggio. Un doppio click sul canvas ci consente di posizionare un Code Block, che onestamente va benissimo per dare istruzioni semplici anche se siete inesperti.
Un ulteriore doppio click sulla barra del Code Block ci consente di rinominarlo in modo da ricordarci, quando riapriremo lo script tra due mesi e in hangover, cosa significavano quei numeri.
A questo punto, in preda ad un irrefrenabile impulso creativo, possiamo addirittura provare a specificare un punto diverso dall’origine come centro del cerchio: vogliamo creare un Punto specificandone le Coordinate.
Collegando il punto all’input centerPoint del nodo Circle.ByCenterPointRadius, succede quello che ci aspettiamo succeda: il cilindro si sposta sulla base del nuovo input.
Usando il Code Block in questo modo, non è comodissimo modificare l’input per esplorare diverse opzioni: potrebbe quindi valere la pena sostituire alcuni di quegli input fissi con uno Slider. Cercandolo sul canvas, ne troviamo due.
Abbiamo dato input numerici interi, ma questo potrebbe essere un buon momento per esplorare la differenza tra Double e Integer sono entrambi numeri, ma l’Integer è un numero intero (lo dice il nome stesso), senza la virgola. Il Double è un numero con la virgola, quindi doppio: ha due valori (uno prima e uno dopo la virgola). Sostituisco gli input di Altezza e Raggio con due Integer Slider, per vedere di nascosto l’effetto che fa.
Al momento, non è cambiato niente. Giocando selvaggiamente con uno dei due slider, tuttavia, ci si potrebbe trovare in una condizione di improvviso ingiallimento dei nodi.
Anche in questo caso, per individuare l’origine del problema è necessario risalire: i nodi evidenziati in giallo non sono l’origine del problema, ma il punto in cui il problema si manifesta. Passando con il mouse su Circle.ByCenterPointRadius, Dynamo prova anche a spiegarci qual è il problema e, per una volta, lo fa in un linguaggio che dovrebbe essere immediatamente comprensibile a tutti.
Circle radius must be non-zero.
Ricordo che questo è un problema piuttosto serio, non solo di Dynamo ma di Revit in generale: l’impossibilità di mandare una geometria a zero. Per impedire di incorrere in questo inconveniente, i nodi Slider ci danno la possibilità di impostare un massimo e un minimo, oltre a uno step tra i valori.
Impostando un minimo superiore a zero, si evita il problema di poco fa.
2. Creare quattro cilindri
Una volta creato un cilindro, crearne quattro non dovrebbe essere troppo difficile.
Ogni volta che vogliamo ripetere la stessa operazione in circostanze diverse, ripetere i nodi che impartiscono le istruzioni relative all’operazione è un errore concettuale. Immaginate di dover tracciare quattro cerchi di raggio uguale: nessuno chiude il compasso e lo posa, tra un cilindro e l’altro. Vogliamo indicare a Dynamo le quattro circostanze in cui vogliamo tracciare i cerchi, eventualmente i quattro raggi ed eventualmente le quattro altezze, ma le istruzioni uguali devono essere concentrate in un unico nodo.
Iniziamo quindi dalla matrice di quattro punti. Volere quattro punti significa, traducendolo per il vecchio Cartesio:
P1 (2, 4, 0);
P2 (2, 104, 0);
P3 (102, 4, 0);
P4 (102, 104, 0).
Si tratta di una combinazione di due coppie di valori: 2 e 102 per le x, 4 e 104 per le y. Iniziate facendo due liste che contengono i due valori. Pote farlo tranquillamente mettendo i due valori tra parentesi quadre in un Code Block.
Se avete un dubbio su quello che state facendo (dubbio sempre legittimo e da coltivare, in generale, nella vita), il nodo Watch è molto utile ma non usate ciò che esce dal nodo Watch perché Dynamo, da bravo uomo, dopo che ha guardato cosa sta facendo non è più in grado di usarlo.
Collegare le due liste ai rispettivi input è un ottimo modo per iniziare a rinfrescare il concetto di lacing: al momento Dynamo crea due punti, uno in (2, 4) e uno in (102, 104). Questo perché combina il primo valore della prima lista con il primo valore della seconda lista e il secondo valore della prima lista con il secondo valore della seconda lista. Il lacing è una opzione che si richiama cliccando con il tasto destro sul nodo che esegue l’istruzione e che rimane visibile in basso a destra (al momento “AUTO”). Le opzioni sono:
- Auto;
- Shortest;
- Longest;
- Cross Product.
I caratteri in basso a destra provano disperatamente a farci capire che azioni vengono compiute dai vari Lacing ma, un po’ come la modalità “Auto”, fanno un po’ quello che possono: per chiarire le idee, consiglio gli schemi nella sezione corrispondente del Dynamo Primer.
Tralasciando la differenza tra Shortest e Longest (o meglio l’applicazione possibile di Longest, che l’esempio non mi consente di chiarire in questo momento), dovrebbe essere chiaro che a noi interessa lanciare la funzione in Cross Product, perché vogliamo punti in tutte le possibili combinazioni dei quattro valori.
A questo punto, non dovrebbe essere troppo difficile estrudere quattro cilindri con altezze incrementali. Ad esempio, potrei volere quattro altezze diverse in sequenza: la più bassa uguale al raggio e le altre, a scalare di 20 in 20.
Questa notazione fa ribrezzo agli smanettoni, quelli veri, quelli che usano il Code Block anche in sostituzione della carta igienica. Se volete uniformarvi a quella che anche nel Dynamo Primer viene indicata come buona pratica, il corrispettivo del nodo Sequence nel Code Block è da immaginare con questa sintassi:
Voglio partire da 45, ne voglio 4 e li voglio ogni 20.
Il risultato è identico ma non è ancora la stessa cosa: quel 45 deve essere trasformato in una variabile agganciata all’input che regola il raggio. Sostituite il valore con una lettera: si trasformerà in una variabile cui potete agganciare, in input, lo slider del raggio.
Dovrebbe andare tutto bene, ma collegando la lista di quattro valori con l’input “distance” di Curve.Extrude, un occhio attento dovrebbe rivelare che qualcosa non va. Se questo non accade, probabilmente è perché:
- Non state lavorando in centimetri ma in millimetri, quindi le differenze tra le altezze sono così piccole che il vostro occhio non riesce a percepirle;
- Non state usando i miei valori, ma altri valori straordinariamente simili tra loro, quindi il vostro occhio non riesce a percepirle;
- Il vostro occhio è marcio.
Guardate la mia immagine e ditemi cosa c’è che non va.
Questo accade a causa della struttura della lista di cerchi che usiamo per creare i cilindri e ci è utile per rinfrescare il concetto di livello.
Andate a esplorare la lista all’interno di Circle.ByCenterPointRadius: potete farlo passandoci sopra con il mouse e, eventualmente, bloccarne l’anteprima cliccando sul simbolo della puntina da disegno che appare in basso.
Se andiamo a risalire l’origine del problema, vediamo che già la lista dei punti centrali era strutturata in questo modo bizzarro.
Effettivamente, facendo un esame di coscienza, siamo stati noi a creare due liste da due punti, quando abbiamo impostato le coordinate, e Dynamo conserva la struttura delle liste.
Una lista di liste è come quando comprate un pacco di sacchetti di orsetti gommosi: ci può essere un grande sacco a livello superiore, ma al suo interno ci sono altri sacchetti (le sotto-liste), ciascuno dei quali contiene gli orsetti gommosi. E adesso mi è venuta fame.
Non credo esista un limite tecnico alla quantità di livelli di sotto-liste, sotto-sotto-liste, sotto-sotto-sotto-liste ecc. che possono esserci in una lista. Esiste certamente un limite di ragionevolezza al di sotto del quale dovreste farvi delle domande su quello che state facendo.
Quando avete tante sotto-liste ma volete riportare tutto a una singola lista, esiste il comando Flatten (che fino a qualche versione fa era l’unico modo di uscire da questa incresciosa situazione e mangiare un orsetto gommoso anziché dover ingurgitare tutto il pacchetto compreso di plastica). Flatten equivale a prendere tutti i pacchetti nel pacco, aprirli e versarli all’interno di una grande ciotola.
Ora, posizionare Flatten risolve tutti i nostri problemi ma non vi spiega come gestire i livelli, oltre ad aggiungere un nodo inutile. Se voi esplorate cosa si trova al di sotto di quel piccolo segno > accanto a “centerPoint” in Circle.ByCenterPointRadius, vi trovate con la possibilità di attivare l’opzione “Use Levels”. Sceglietela e impostate il valore a @L1.
Utilizzare i livelli equivale ad attivare un superpotere che vi consente di attraversare con la mano i pacchetti di caramelle per andare a prendere direttamente gli orsetti gommosi senza doverle aprire e versare. Forse durante le feste natalizie mi è venuto un qualche disturbo del metabolismo.
Naturalmente la lista così strutturata va benissimo per fare quello che volevamo fare con la sequenza di altezze.
Se mi avete seguito fino a qui e per caso non vedevate Dynamo da mesi, è normale che sentiate il cervello pronto a uscire dal naso e vi siete meritati un orsetto gommoso.
3. Costruiamo il Loopcamp
Sfortunatamente, i quattro cilindri sono tanto bellini ma non sono assolutamente quello che stavamo cercando di fare all’inizio, quindi buttateli via.
Il motivo per cui amo questo esercizio, da insegnante, è che può essere approcciato a diversi livelli di difficoltà ed eventualmente aggiustato in corsa a seconda della risposta che si ottiene dalla classe. Di fatto, si tratta di una sequenza di cilindri di raggio e altezza variabile, posizionati a saturare una corona circolare. Il primo livello di difficoltà tuttavia, il minimo da raggiungere, può essere la creazione di una sequenza di cilindri di raggio costante e altezza variabile posizionati lungo un perimetro circolare. Ed è sufficientemente facile perché possa riuscirci anche chi non vede Dynamo da mesi.
Innanzitutto dobbiamo tracciare un cerchio di costruzione: il perimetro generale del nostro Loopcamp.
Iniziamo da una versione estremamente semplificata: suddividiamo la circonferenza in un numero uguale di parti. Una trentina, diciamo.
Prima di iniziare a inguaiarsi con nodi balordi tipo Curve.PointAtParameter, gli anni mi hanno insegnato che trattandosi di una circonferenza è molto meglio usare lo specifico Curve.PointsAtEqualChordLength, che posiziona una serie di punti in modo da suddividere la curva in parti le cui corde siano uguali. La corda, giusto per rinfrescare anche le più ovvie cognizioni di geometria piana, è il segmento che congiunge i due estremi di un arco. Trattandosi di una circonferenza, a corde uguali corrispondono archi uguali.
Se osservate i punti posizionati sulla circonferenza, vi renderete immediatamente conto che ne manca uno. Si tratta del punto in corrispondenza di quello che secondo Dynamo è l’inizio della circonferenza, un concetto che rende impossibile utilizzare questo esercizio in un monastero tibetano. Se volete far ripassare Dynamo al Dalai Lama, vi consiglio di usare il mio altro esercizio, l’alveare.
Per posizionare anche l’ultimo punto mancante, temo che il modo più pratico sia proprio Curve.PointAtParameter, di cui ho appena finito di parlare male. La cosa ci consente anche di esplorare un concetto abbastanza importante che non c’è speranza di indovinare a meno che qualcuno non si prenda la briga di spiegarvelo: come funziona la suddivisione parametrica di una curva in ambiente a geometria variabile (Dynamo, ma anche i componenti adattivi). La versione semplice di quella che in realtà è una faccenda complessa, è che Revit ragionevolmente ha poca idea della lunghezza attuale della curva una volta lanciata in ambiente di progetto, quindi utilizza una versione “normalizzata” del parametro di lunghezza, dove l’inizio è posto uguale a 0 e la fine è posta uguale a 1. Tutto quello che viene in mezzo è una suddivisione proporzionale che non si cura della lunghezza effettiva. Se non mi credete, fate una prova sul nostro cerchio.
Se vi ho convinto, eliminate pure quello con input 1 e lasciate quello con input 0 (valore di default). Naturalmente bisognerà fondere il tutto in una lista unica di punti, per farci qualcosa di utile, e fare in modo di non ritrovarsi con un pacchetto di orsetti gommosi e un singolo orsetto gommoso dentro a un altro sacchetto.
Ora, la faccenda si fa complicata se non abbiamo ben presente la differenza tra una corda e l’arco sotteso da essa. Fino ad ora stiamo lavorando con le corde. Se dividiamo la lunghezza della circonferenza per trenta, otteniamo la lunghezza degli archi tra un punto e l’altro. Non ci servirà a molto.
Quello che vogliamo, però, è un valore da utilizzare come raggi dei cilindri che vogliamo posizionare centrati su ogni punto: ci serve quindi la lunghezza della corda che sottende alla metà dell’arco. Ricavare la lunghezza della corda avendo arco e raggio è un’operazione non troppo difficile.
Se non vi ricordate la formula potete sempre misurare la distanza tra due dei punti che avete posizionato. Se non vi va bene nemmeno questa soluzione, inscrivete un poligono regolare con un numero di lati pari alla nostra suddivisione, estraete la lunghezza di quella curva e dividetela di nuovo. Solo ricordatevi che il valore dato come input a “divisions” in Curve.PointsAtEqualChordLength non è il numero di punti sulla curva ma il numero di divisioni, quindi il numero di punti sulla curva è Divisions +1.
Questo è un buon punto per iniziare a raggruppare i nodi nello script: selezionate i nodi che volete tenere insieme, scegliete “Create Group” dopo aver cliccato su un nodo qualunque con il tasto di destra, assegnate un colore e date un nome al gruppo. Cercate di decidere un senso per i colori che avete a disposizione: sembrano pochi ma sono anche troppi.
Abbiamo i punti, abbiamo il raggio corretto dei cerchi, sappiamo come estruderli in cilindri e sappiamo dare loro un’altezza sequenziale (ricordate la sequenza dei quattro cerchi nell’apparentemente inutile parte 2?). Stiamo lavorando in centimetri: ipotizziamo, in prima battuta, di voler partire da 100 e avere tante variazioni quanti cilindri lungo il perimetro, con una distanza di 50 l’uno dall’altro.
100..#n..50
Siamo quindi riusciti a realizzare le geometrie di costruzione per la versione più semplice dell’elemento: una sequenza di cilindri con raggio uguale e altezze crescenti.
Se vogliamo mescolare le altezze, introducendo un primo elemento variabile, possiamo provare il nodo List.Shuffle, che rimescola una lista in ordine apparentemente casuale.
Se siete arrivati a questo punto, potrebbe essere il momento di prendere un altro orsetto gommoso, prima di passare a Revit e riprendere la cattiva notizia che avevamo spazzato sotto al tappeto al termine dell’esercizio 1: in realtà non abbiamo ancora fatto niente.
Quelle che abbiamo creato fino ad ora sono geometrie di costruzione e sono come avere rimorchiato per sbaglio un nerd: se ne andranno nel momento in cui chiuderete Dynamo. Provare per credere.
Come fare quindi per creare una geometria reale, che può essere computata e documentata? Esistono vari nodi che creano elementi nativi di Revit: alcuni operano in modo dannatamente ignorante, mentre altri sono più adatti ai nostri scopi.
Il più ignorante di tutti è DirectShape.ByGeometry: data una geometria, crea un elemento abbastanza simile a un model-in-place, che finge di essere in una categoria data ma che si comporta molto male se messo di fronte alle proprie responsabilità di oggetto BIM.
Tra l’altro, potrebbe essere un buon momento per osservare come si comportano gli elementi circolari in Revit se li maneggiamo con poca cura.
Una delle soluzioni più eleganti, per quanto mi riguarda, è sempre quella di togliersi la scimmia dalla spalla, uscire un istante da Dynamo (non muore nessuno), creare un componente nativo di Revit con le caratteristiche di cui abbiamo bisogno e poi impartirgli istruzioni tramite lo script. Nel nostro caso, tutto quello che ci serve è una famiglia cilindrica con altezza di istanza (probabilmente condivisa: a un certo punto qualcuno vorrà sapere quanto devono essere alti i cilindri da portare fin nel mezzo del deserto del Nevada).
Mi piace pensare che non sareste arrivati fino a qui se non sapeste fare una famiglia cilindrica. Tuttavia, se non avete voglia di farla adesso potete scaricarla da qui. Pigroni. Caricatela nel progetto che state usando. E, già che ci siete, cancellate tutti quei Generic Model, perché non ci serviranno.
Anche parte dello script i realtà non ci serve più e, nello specifico, si tratta della parte che crea le estrusioni. Fate un po’ di pulizia: portatevi in questa condizione.
Se abbiamo dei punti e delle famiglie, il nodo per posizionarle è FamilyInstance.ByPoint: funziona con qualunque famiglia non sia weirdo-based. Abbiamo i punti, se non li avete buttati facendo pulizia.
Quello che succederà è che in questa battuta Dynamo posizionerà le famiglie in corrispondenza dei punti, ma saranno ancora della dimensione di default della famiglia che abbiamo caricato.
Per modificare le dimensioni degli elementi, dobbiamo compilarne i parametri. Questo ci consente di rinfrescare quella che probabilmente è la funzione più utile di Dynamo nella piccola vita di tutti i giorni: la capacità di far confluire in batch una grande quantità di informazioni dove serve che confluiscano. Il nodo che stiamo cercando è Element.SetParameterByName e conviene farlo lavorare in due riprese: la prima volta ci occupiamo del raggio.
Element.SetParameterByName è case sensitive, quindi attenti alle minuscole e alle maiuscole quando richiamate il nome del parametro. Se avete dei dubbi, potete usare il nodo Element.Parameters, che legge il nome dei parametri associati a un’istanza e – incidentalmente – il loro valore.
In seconda battuta possiamo occuparci dell’Altezza, con un’istruzione data dallo stesso nodo e la lista di valori semi-casuale che usavamo per le Direct Shape.
Questo è il risultato finale.
4. Un passo in più
Fino ad ora, abbiamo creato un cerchio di elementi regolari con altezze irregolari e sono soddisfatta, perché mi ha consentito di rinfrescare in una volta sola alcuni elementi di base, in particolare:
- vedere come Dynamo si rapporta con Revit;
- creare geometrie di lavoro;
- leggere e scrivere parametri.
Tuttavia, non abbiamo realizzato esattamente l’installazione. Se volete avvicinarvi di più alla nostra ispirazione, dovete lavorare con dei punti distribuiti all’interno di una corona circolare e con elementi di diametro tale da toccarsi l’un l’altro senza compenetrarsi. E se state pensando di ricorrere a una tassellatura di Voronoi, probabilmente siete sulla strada giusta. Ma questa è un’altra storia, decisamente più complessa di un semplice esercizio di ripasso.
Translated with google. Nice!
Top
Nice…