puntorevit@gmail.com
Dopo aver
completato la modellazione di tutti gli edifici ho dovuto separarli uno per uno per avere la possibilità di eseguire comandi come il
View Depth Override che, altrimenti, con un'unica famiglia di massa (che chiamerò MA-0.rfa) non servirebbero a niente.
La procedura che ho elaborato è la seguente:
- Per ogni Form nella famiglia MA-0, registrare in un file CSV esterno su una riga l'ID dell'oggetto, le coordinate XYZ del punto di minimo del suo BoundingBoxXYZ e un numero incrementale per una famiglia segnaposto del tipo MA-NNN.rfa
- Creare le N copie segnaposto del file MA-0 contenenti esattamente gli stessi oggetti con lo stesso ID di MA-0
- Aprire ciascuno dei file segnaposto secondo l'ordine del file CSV, selezionare un oggetto con il suo ID e spostarlo in modo che il punto di minimo del suo BoundingBoxXYZ coincida con l'origine della famiglia
- Eliminare tutti gli altri oggetti e salvare la famiglia.
- Utilizzando lo stesso file CSV si possono poi posizionare le famiglie all'interno del modello come già mostrato da Jeremy Tammik sul suo blog a più riprese, ma sto pensando di utilizzare Dynamo, giusto per vedere come integrarlo all'interno della procedura.
La prima cosa interessante che ho scoperto è in che modo Revit gestisce due o più forme che vengono combinate tra loro con join geometry (unisci geometria) e cut (taglia), nel caso dei vuoti.
I vuoti non sono classificati come Form, almeno internamente la loro categoria di appartenenza è "null".
Quando si filtrano gli Element per la categoria interna OST_MassForm, che corrisponde alla categoria forme delle masse, si ottiene un conteggio "doppio" nel senso che gli elementi di questa categoria possono essere sia Form solidi semplici, sia GeomCombination, risultanti dalla combinazione appunto di membri come i Form e i Void; in sostanza questi due tipi di elementi hanno proprietà simili ma diverse e vanno gestiti in modo opportuno. Dopo qualche tentativo andato male su un file di prova molto piccolo, ho deciso di semplificare eliminando i void da una copia di MA-0 (che ho chiamato solamente MA-) da utilizzare come base per le operazioni successive, è un punto su cui devo ancora lavorare per un ulteriore affinamento della procedura.
Il BoundingBoxXYZ è una proprietà degli elementi ma dipende dalla vista, eseguendo una macro da una vista 3D si ottiene quello che serve per determinare la posizione dello spazio di ciascun oggetto che andrà scritta scomponendola nelle sue coordinate XYZ all'interno di un file CSV. L'unità di misura è quella interna di Revit (ft) ma si può pensare di convertirla in metri anche se non è strettamente necessario per questo scopo (il file CSV è infatti un passaggio necessario per riposizionare successivamente le famiglie all'interno del modello).
Per stabilire il numero di copie segnaposto necessarie basta selezionare tutti gli oggetti presenti in MA-.rfa della categoria Form, la duplicazione si può ottenere con un file batch di poche righe, da modificare secondo le proprie esigenze:
pushd %~dp0
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set TESTFOLDER=MA
md "%TESTFOLDER%"
set /a times=2
FOR /L %%i IN (1,1,%times%) DO (
copy "MA-.rfa" ".\%TESTFOLDER%"
cd ".\%TESTFOLDER%"
ren "MA-.rfa" "MA-%%i.rfa"
cd ".."
)
Basta copiare e incollare in un editor di .txt e salvare con estensione .bat all'interno della cartella dove si trova il file MA-.rfa, successivamente verrà creata una cartella MA all'interno della quale verranno create delle copie con indice incrementale di MA-.rfa. La prima riga consente l'esecuzione anche su percorsi di rete. La duplicazione di 712 file è avvenuta in una manciata di secondi, ha richiesto però uno spazio libero di circa 8GB.
Un'altra cosa interessante che ho scoperto è la possibilità di caricare in background nella sessione di Revit, altri documenti, senza quindi renderli visibili all'utente (proprio come avviene quando si apre un modello con dei file collegati al suo interno: i file collegati vengono caricati nella sessione corrente di Revit ma non sono modificabili). In questo caso, dato che i file non sono collegati, possono anche essere modificati e salvati.
Questa caratteristica mi ha poi fatto venire in mente delle possibili applicazioni per delle operazioni veramente tediose quando si opera con i file collegati, e sarà oggetto prossimamente di qualche riflessione più attenta.
Una volta che il primo file MA-1 è caricato, dal file CSV si ottiene il valore dell'ID dell'oggetto e lo si sposta nell'origine passando ancora per l'Element associato all'ID (si sarebbe potuto anche ottenere lo spostamento direttamente dal file CSV, ma in questo modo occorrono meno righe di codice).
Per lo spostamento si ricorre a ElementTransformUtils.MoveElement che consente di specificare l'ID dell'oggetto da spostare all'interno di uno specifico documento e il vettore di spostamento (in questo caso dal punto di minimo del BoundingBoxXYZ all'origine). Successivamente si eliminano tutti gli altri oggetti Form escludendo l'ID che deriva dal file CSV. Il documento viene chiuso e quindi direttamente salvato.
Operando ciclicamente su tutte le copie MA-1, MA-2,..., MA-712 ci sono volute 12 ore e 30 minuti e ulteriori 4GB di spazio perché purtroppo non tutti gli oggetti sono stati eliminati, infatti i file MA-NNN.rfa sono passati da una dimensione iniziale di circa 12MB a circa 6MB, ma sono state mantenute anche le copie di backup MA-NNN.0001.rfa.
Ho creato poi un'altra macro molto simile alla precedente dove ho sostanzialmente mantenuto solo la parte in cui vengono eliminati gli oggetti con ID diverso da quello derivante dal file CSV e questa volta sembra aver sortito gli effetti desiderati riducendo la dimensione a circa 850kB (si potrebbe forse fare qualcosa di meglio ma ho notato che manualmente non si ottengono risultati sensibilmente migliori, per cui mi accontento).
Questo secondo passaggio riesce a gestire circa 2/3 file al minuto, quindi poco meno di 6 ore per tutti i file con una stima di circa 600MB di spazio totale richiesto.
Ecco le
macro, suggerimenti e critiche sono ben accetti.