martedì, febbraio 11, 2014

Door Threshold - External Command


UPDATE: AUTO FLOOR MAKER 2


If you are happy with my code you can show me some gratitude paying what you want on PayPal:

puntorevit@gmail.com
 

Recentemente mi è stato chiesto di provare ad implementare un'interfaccia per la selezione del tipo di pavimento per Auto Floor Maker che avevo sviluppato in precedenza.
Subito dopo è arrivata la richiesta per modellare la porzione di pavimento anche nel vano porta.
Per mantenere il più possibile quanto avevo scritto del codice precedente, ho solo quindi aggiunto una nuova procedura per le soglie delle porte e il form di selezione dei tipi di pavimento.
Il passo finale sarà quello di integrare tutto in unico form dove si potrà decidere se creare i pavimenti sulla finitura dei muri o fino al nucleo e si potranno selezionare tipi diversi per il pavimento dei locali e quello delle soglie.
Un grazie particolare a Luca Vocella di eVox Bill of Quantities e altri plugin molto avanzati per il mondo Revit, che mi ha illuminato sulla creazione dei combobox e mi ha dato il suo preziosissimo punto di vista sull'algoritmo per le soglie, mettendo in luce i punti deboli e lasciando margini per un possibile miglioramento di tutta la procedura.
Come sempre ho fatto tesoro di un articolo di Jeremy Tammik che ha gentilmente reso pubblico un algoritmo di ordinamento dei segmenti di un loop senza il quale non sarei stato in grado di portare a termine questo compito.

Intanto questo è il codice per il comando che crea le soglie sotto le porte e questo sono il file DLL e ADDIN che vanno copiati qui:

C:\ProgramData\Autodesk\Revit\Addins\2014

Ricordarsi di sbloccare i file: tasto destro, proprietà, annulla blocco.

sabato, febbraio 01, 2014

3D DWG to RFA - Divide and conquer macros




If you are happy with my code you can show me some gratitude paying what you want on PayPal:

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:

  1. 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
  2. Creare le N copie segnaposto del file MA-0 contenenti esattamente gli stessi oggetti con lo stesso ID di MA-0
  3. 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
  4. Eliminare tutti gli altri oggetti e salvare la famiglia.
  5. 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.