mercoledì, gennaio 08, 2014

View Depth Override - Polar Distance Update



Ecco un aggiornamento del codice precedente, ora la distanza degli oggetti per le viste 2D  è calcolata rispetto al piano della vista e non più dal punto di origine (opzione che rimane valida per le viste di prospettiva).
Per ragioni di grafica ho impostato il limite del grigio non più a 255 ma a 205 poiché c'è il rischio che risulti troppo chiaro in fase di stampa, ma avendo pubblicato il codice ognuno può impostarlo a piacere modificando tutte le occorrenze della variabile: 

int grey=205;

Ho fatto anche qualche modifica per la gestione degli errori, ciononostante è un lavoro preliminare e rimane valido il mio appello per ricevere feedback nei commenti.

Questo il codice sorgente, qui invece il file DLL e l'ADDIN che vanno copiati qui:

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

Potrebbe essere utile anche consultare questo articolo per sbloccare i file .dll



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

puntorevit@gmail.com

View Depth Override Polar Distance - External Command




Ho cambiato del tutto approccio al problema e ho riscritto per intero il comando.
Stavolta la sostituzione grafica non è più limitata ai grigi 128 e 192, ma è un vero e proprio gradiente funzione della distanza tra gli oggetti e l'origine della vista.
Così facendo è possibile applicare praticamente lo stesso codice sia alle viste 2D sia alle prospettive.
Questa versione del comando è molto semplice, leggera e veloce nell'esecuzione ed anche più elegante nel codice.
I comandi sono 3:
  • View Depth Override - Polar Distance per le viste 2D attive
  • View Depth Override 3D - Write List per scrivere il file sul desktop con l'elenco delle viste di prospettiva
  • View Depth Override 3D - Read List per eseguire il view depth override sulle viste elencate nel file (si può editare manualmente il contenuto del file per decidere su quali viste 3D eseguire il comando che andrà lanciato da una qualsiasi altra vista)
Quando si edita il file di testo si deve mantenere il nome e il percorso sul desktop.

Una cosa importante è settare la profondità della vista poiché rappresenta la massima distanza entro cui viene calcolato il gradiente della sostituzione grafica.
Si tratta ancora di un work in progress ed esistono delle casistiche che possono portare ad un overflow (una specie di ciclo infinito), per questo nel codice ho inserito dei punti in cui le eventuali eccezioni al funzionamento riporteranno dei messaggi, nel caso prego chi intenda fare uso di questo comando di segnalarmele nei commenti.

Questo il codice sorgente, qui invece il file DLL e l'ADDIN che vanno copiati qui:

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

Potrebbe essere utile anche consultare questo articolo per sbloccare i file .dll

Ecco una dimostrazione della funzionalità, prossimamente il comando su viste 2D considererà la distanza dal piano della vista così da evitare  gradienti indesiderati su oggetti che appartengono allo stesso piano.

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



puntorevit@gmail.com

sabato, dicembre 21, 2013

Revit Add Ons

Tim Grimm di Revit Add-ons mi ha fatto una bella sorpresa offrendosi di ospitare gratuitamente un banner che rimanda al mio blog per darmi più visibilità.


Revit Add-ons è letteralmente una miniera di strumenti per Revit, sia a pagamento sia gratuiti, che permettono di migliorare il nostro flusso di lavoro con il software. Le recensioni sono essenziali e ben fatte e contribuiscono molto a sensibilizzare e guidare gli utenti alla scelta degli strumenti migliori per il loro lavoro senza troppi giri di parole.

Thanks Tim!

venerdì, dicembre 20, 2013

View Depth Override - Alcune considerazioni



Il grande Jeremy Tammik di The Building Coder mi ha fatto l'onore di pubblicare sul suo blog il mio codice relativo al View Depth Override sia per viste 2D sia per viste 3D.
Nei commenti, un lettore di nome Ning, ha delle perplessità riguardo alle coordinate che ho utilizzato nel codice, questa la mia risposta nel tentativo di dipanare i suoi dubbi.
E' una breve storia (ancora non conclusa per altro) del processo che mi ha condotto a determinate scelte per impostare il codice, la scrivo in inglese (perdonate gli erroracci) ma se qualcuno non capisse posso tradurla in italiano nei commenti... ogni aiuto o suggerimento in tal senso è ben accetto!

Questo quanto chiede Ning:

"hi Paolo and Jeremy,

i'm trying to understand that 3DView Depth Override stuff, by using my own simplified code, works OK for plan / section / elevation views, but i have trouble to understand the coordinate system in terms of relationship between 3DView's Cropbox and Outline used in BoundingBoxIntersectsFilter, i assume the followings:
1) Boundingbox of 3DView's Cropbox is in coordinate system on top of the computer screen in which Z is perpendicular to the computer screen
2) Outline used in BoundingBoxIntersectsFilter is in Revit coordinate system

a bit description in your blog will be great, perhaps Jeremy can give a more technical detailed explanation in the future"

Questa la mia risposta:

Hi Ning,
sorry for the late reply, I'll try to make myself clear about what you're asking.
When I tried to code this macro I was at the beginning of my "API journey" and I'm sure I wouldn't be making the same choices if I had to do it again from scratch.
You're assumptions are correct: View BoundingBox has to be transformed into absolute coordinates to work properly as an Outline.
All started with 2D views: view coordinates are realtive to each view and there are three vectors defining the space: the RightDirection (let's say local x axis), the UpDirection (local y axis) and ViewDirection (local z axis, which is orthogonal to the screen as you mentioned).
That said, I guess one can obtain the Outline necessary to the BoundingBoxFilter from here, taking a shortcut and simplyfing the code a bit, but still, you need to convert from local to absolute coordinates to build a proper Outline.
This is also important to implement the subfunction called "Integral", which collects all ElementIds in a series of smaller BoundingBoxes (200 subdivisions for each one of the three segments of the main BoundingBox), because in case of views that are not parallel to the edges of the screen, a single BoundingBox would generate errors in the selection.
When I began to study a macro for 3D views I decided to restrict the code only for perspective views because that made more sense to me; I tried to reuse as much as possible the code I had for 2D views, but I took a different approach to determine the Bounding Box: I choosed to consider the entire Bounding Box of the model (this is the part where Jeremy's blog comes in), then I rotated (it's better say projected, transformed) this overall BoundingBox "parellel" to the perspective view (but keeping the top and the bottom faces parallel to the ground) and then execute the same code for 2D Views.
It's a work in progress though, I couldn't find the Bounding Box of a perspective view as I did before for a 2D view, and that's an issue still opened since I hadn't look into it since I published the code. I'm open to all the help I can get :)
I hope this helped you in a better understanding of what's behind the code.

Cheers


-Paolo


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

puntorevit@gmail.com

mercoledì, dicembre 18, 2013

External Command: Site XYZ Family In & Out



Questo external command esporta le coordinate delle famiglie riferite alle coordinate del Survey Base Point e per differenziarlo da quello precedente il file CSV ha un suffisso "-Site" ma viene sempre salvato sul desktop con il nome del progetto.

Ovviamente il comando considera la project location corrente e non tutte le altre che possono essere presenti.

Qui si trova il codice, qui la DLL, e qui l'ADDIN, i file sono da copaire qui:

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

Potrebbe essere utile anche consultare questo articolo per sbloccare i file .dll

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

puntorevit@gmail.com

External command: XYZ Family In & Out - Update






Ho apportato qualche modifica al codice del post precedente, la versione aggiornata si può trovare qui ed ora consente di aggiornare la posizione delle famiglie modificando il file CSV associato al progetto.
Ho corretto l'esportazione che ora utilizza il punto come separatore decimale così non si confonde con la "," del CSV.
Quando si vuole modificare una famiglia su host da CSV potrebbero verificarsi risultati inattesi poichè prevale la relazione che intercorre tra host e famiglia (quindi lo spostamento c'è ma avviene lungo l'host).

Qui invece l'external command con DLL e ADDIN che vanno copiati in questa directory:

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

Potrebbe essere utile anche consultare questo articolo per sbloccare i file .dll
If you are happy with my code you can show me some gratitude paying what you want on PayPal:

puntorevit@gmail.com

lunedì, dicembre 16, 2013

External Command: Family XYZ Location Point to CSV


Questo comando esterno permette di ricavare un file CSV contenente per ciascuna riga le informazioni relative alle sole famiglie con un singolo punto di inserimento che vengono selezionate:

[Category] , [Family Name] , [ID] , [X] , [Y] , [Z]

Il file CSV viene salvato sul desktop con il nome del file del progetto. Con qualche modifica si può fare per tutte le famiglie di questo tipo senza intervenire con la selezione manuale.

Qui si può leggere il codice sorgente, da qui si può scaricare il file DLL e il relativo ADDIN che vanno copiati in questa directory:

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

Potrebbe essere utile anche consultare questo articolo per sbloccare i file .dll
If you are happy with my code you can show me some gratitude paying what you want on PayPal:

puntorevit@gmail.com

mercoledì, dicembre 11, 2013

External Commands: Miter Joint By Picking - Lines Chain Total Length






Su richiesta ecco gli external commands di queste due macro che avevo pubblicato in precedenza qui e qui.

Lines Chain Total Length (addin) (dll)

Wall Miter Joint by Picking: (addin) (dll)

Tutti i file sono da copiare in questa directory:

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

Potrebbe essere utile anche consultare questo articolo per sbloccare i file .dll

lunedì, dicembre 09, 2013

Formule utili per parametrizzare una tangente a due archi


Può tornare utile per parametrizzare dei profili o dei tracciati.

Update:

Nel caso si volesse trovare l'altra tangente non speculare a quella precedente, il metodo grafico da utilizzare è lo stesso ma le formule cambiano leggermente:



Chain Dimension

Per oggetti modello (muri e linee) esiste la possibilità di restituire la lunghezza totale di una concatenazione di elementi.
Questa funzionalità però non esiste per le linee di dettaglio, con questa macro è possibile ottenere la lunghezza delle linee selezionate (sia di modello sia di dettaglio), sia concatenate sia separate.
La macro tiene conto dell'unità di misura del progetto e restituisce il valore in metri se il sistema utilizzato è quello metrico e in piedi se è imperiale. Se serve posso fare l'external command.

Filled region on 3D Views - My EUR RTC 2013 Trick



Durante il Revit Technology Conference 2013 a Delft c'è stata una sessione di "Tips and Tricks", e alla fine ognuno poteva contribuire con un proprio suggerimento se lo desiderava.
Io ho descritto la procedura per inserire una filled region in tavola, ma senza Revit sotto mano, solo raccontadolo a parole, questo il vecchio post a cui facevo riferimento.
Sono stato deriso, preso per pazzo, criticato... io però credo sia worthsharing, meritevole di essere condiviso.

Un piccolo video per dimostrare un'applicazione possibile, come ad esempio creare delle filled region per delle viste 3D, senza ricorrere a stratagemmi più complessi.

giovedì, dicembre 05, 2013

Miter joint by picking






In questo video si vede come si possa cambiare il tipo di join terminali dei muri semplicemente cliccandoci sopra. Credit a Harry Mattison di Boost Your BIM da cui ho preso spunto.

WallJoinMiterByPick source code

mercoledì, dicembre 04, 2013

View Depth Override - the CAD side of the moon



Qualche tempo fa mi è stato chiesto nei commenti come poter unificare le linee delle diverse tonalità di grigio una volta esportate da Revit dopo avere utilizzato il View Depth Override.
Per prima cosa si deve impostare l'esportazione dei formati CAD da Revit su TrueColour e utilizzare le impostazioni byLayer e le sostituzioni byEntity.
Una volta in AutoCAD si deve caricare il GreyMerge.lsp alla riga di comando digitando "appload".
Digitando poi GREYMERGE si richiama il comando che inserisce i due layer "_Grey-1" e "_Grey-2" attribuendo loro rispettivamente i colori RGB 128,128,128 e 192,192,192.
Successivamente gli oggetti vengono spostati di layer concordemente al loro colore, si potrà quindi impostare tutto su byLayer.

GreyMerge.lsp

Trovare il raggio di un arco ribassato



Qualche volta capita di dover realizzare dei componenti parametrici con la forma in figura di cui però non si conosce esattamente il valore del raggio dell'arco, come ad esempio da un rilievo.
Mentre la costruzione geometrica è abbastanza semplice, la parametrizzazione può essere più complessa se non si tengono presente alcune proprietà geometriche dei triangoli e delle circonferenze.
Sapendo che l'angolo alla circonferenza del diametro di un cerchio è sempre a 90°, usando il teorema di Pitagora e le proporzioni tra triangoli simili è possibile ricavare in modo abbastanza semplice i parametri che servono a definire il componente come da formula riportata in figura.




venerdì, novembre 29, 2013

Auto Floor Maker - Core Boundaries





Un veloce aggiornamento: aggiungere il file .dll nella stessa cartella e sostituire il file .addin con il seguente:


AutoFloorMakerCoreBoundaries.dll

AutoFloorMaker.addin

giovedì, novembre 21, 2013

Auto Floor Maker - External Command


Per coloro i quali volessero provare Auto Floor Maker ma non hanno dimestichezza con le macro, ho creato l'External Command e il relativo addin manifest, potete usarlo a vostro rischio e pericolo :D

Se copiate i due file in questa posizione dovrebbe comparire tra gli External Command al primo riavvio di Revit 2014:

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

AutoFloorMaker.addin

AutoFloorMaker.dll

Ecco un video di come usare il comando:



Probabilmente sarà necessario togliere il blocco al file AutoFloorMaker.dll cliccando con il tasto destro > Proprietà e poi "Annulla blocco" in basso a destra e poi riavviate Revit:


Primavera - Update


Ecco un aggiornamento del progetto "primavera" di Antonio Citterio Patricia Viel and Partners.


lunedì, novembre 18, 2013

Drawing shadows - test




Ho appena scoperto la possibilità di tracciare le ombre di oggetti solidi in Revit, ho provato a giocare con il codice presente nel developer manual delle API 2014.
Interessante....

Scavare una superficie topografica



Una delle cose che non si può fare correttamente in Revit è scavare una superficie topografica, ossia creare un volume interrato e ricoprirlo di nuovo con il terreno.
Si possono creare delle famiglie in-place, oppure, più elegantemente, copiare la superficie topografica in un file esterno da collegare, ritagliare la superficie topografica seguendo l'impronta della piattaforma (pad) e impostare per quel file la profondità del retino della topografia pari alla quota dell'estradosso della soletta del volume interrato.
Nelle viste 2D si può vedere che si può intervenire facendo l'override localmente degli elementi in vista e in sezione delle superfici topografiche interessate. In questo modo si può evitare di ricorrere alle filled regione ( i retini) per mascherare la parte di terreno di riporto.

inFORM - Interacting With a Dynamic Shape Display


Fantastico!

sabato, novembre 16, 2013

3D View Tag



In questo post dal blog di Steve Stafford Revit OpEd si ricorda che non si dispone ancora di annotazioni in grado di segnalare la posizione delle viste 3D.
Ho preso spunto da qui per poter creare una macro che inserisse una famiglia di modello generico per ciascuna vista di prospettiva, orientandola correttamente e riportando il nome della vista.
Ovviamente è solo l'effetto finale quello che avevo in mente, non è per niente simile alle annotazioni di Revit che si aggiornano automaticamente con le proprietà delle viste collegate, però funziona per quello che abbiamo a disposizione ora.

Ecco il codice sorgente e la famiglia utilizzata (c'è da inserire un parametro condiviso ma credo siate in grado di ricavarlo da soli):

Codice sorgente 2014

Famiglia GM-3DView.rfa

3D View Depth Override - Update


In questo nuovo video mostro come funziona la versione del View Depth Override per le viste prospettiche.
Dato che non è possibile azionare le macro da una vista prospettica ho trovato un sistema per aggirare il problema.
Con la macro ViewListWrite viene creato un file di testo sul desktop chiamato [MyProjectName]-3DViews.txt, in cui vengono elencate per ciascuna riga le viste di prospettiva presenti nel progetto.
Con la macro ViewListRead viene eseguito il View Depth Override tante volte quante sono le viste elencate nel file di testo. Questo file di testo è editabile dall'utente ed è quindi possibile decidere su quali viste far eseguire la macro.
Il codice è migliorato dalla prima versione, grazie anche a degli spunti che ho trovato sul blog di Jeremy Tammik the Building Coder, in particolare per l'uso del Linq per determinare i punti di massimo e minimo.
Ho introdotto anche l'uso del Transform per rendere più leggibili le operazioni di calcolo dei punti del BoundingBoxXYZ orientato come la vista, la qual cosa si può felicemente applicare alla versione 2D del View Depth Override.

Si tratta sempre di un work in progress, i commenti sono bene accetti per cercare di migliorare :)

Codice sorgente:
Versione 2012
Versione 2014

venerdì, novembre 15, 2013

Step by step how to use macro code samples


Alcuni lettori non hanno molta dimestichezza con i codici delle macro che rendo pubblici e vorrebbero utilizzarli, così ho realizzato questo piccolo video per guidare passo passo nella creazione delle macro.
Nell'esempio ho utilizzato il codice di Auto Floor Sketch - Update


  1. Creare un nuovo modulo in C#
  2. Creare una nuova macro
  3. Copiare gli using statements all'inizio del codice nell'editor delle macro
  4. Copiare il codice della macro dopo quello generato automaticamente da Revit
  5. Controllare che non ci siano errori
  6. Compilare il codice
  7. Se non ci sono errori adesso si può utilizzare la macro

Gli using statements che inserisco all'inizio del codice sono generalmente i seguenti:

using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Events;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.Collections;
using System.IO;
using System.Linq;


Spero possa essere utile.

giovedì, novembre 14, 2013

Auto Floor Sketch - Update


Questo è un aggiornamento della macro che ora aggiunge dei vuoti nel pavimento di finitura basati sul perimetro degli eventuali altri oggetti che definiscono le chiusure dei locali.
In particolare per i locali sottotetto considera l'altezza di calcolo dei livelli pari a zero temporaneamente per creare il pavimento sulla massima estensione possibile, dopo di che lo riporta nella posizione scelta dall'utente.
E' leggermente più lento ma è più preciso. I locali che non sono propriamente racchiusi non vengono considerati, mentre i locali ottenuti anche dalle linee di delimitazione invece si.

mercoledì, novembre 13, 2013

Ordinare Alfabeticamente i Riquadri di Definizione - Sort Scope Boxes Alphabetically

Una delle seccature maggiori in Revit riguarda l'impossibilità di ordinare alfabeticamente alcuni oggetti che invece seguono l'ordine di creazione.
Fra questi ci sono i riquadri di definizione, gli scope boxes, che quando sono molti obbligano gli utenti a scrollare in tutta la lista senza avere la possibilità di ritrovare in ordine alfabetico i nomi che sono stati assegnati ai singoli oggetti.
In realtà non è possibile fare molto da questo punto di vista se non adeguarsi a come Revit ripropone questo elenco di oggetti (a quanto pare in base all'ID dell'oggetto che, anche se può variare, purtroppo non può essere modificato direttamente dall'utente).
Per questo motivo ho creato una macro che aggiunge in automatico al nome degli scope boxes un prefisso numerico crescente che corrisponde alla posizione di ciascun oggetto nell'elenco.
Il flusso di lavoro potrebbe essere il seguente: dopo aver creato gli scope boxes che servono, si assegna contestualmente un nome significativo per poterli distinguere. Si effettua un'associazione alle viste di pianta e solo dopo si procede con la macro.

Partendo da una situazione di questo tipo, con i nomi non in ordine alfabetico:



Facendo agire la macro si ottiene questo:


In questo modo è possibile almeno rendersi conto di quale "numero" si deve usare a riferimento per quel tipo particolare di piante rendendo più rapido rintracciare gli scope boxes nell'elenco.

Di seguito il codice sorgente per Revit 2012.



venerdì, novembre 08, 2013

Superficie Topografica da linee - la mia versione



Poco tempo fa Matt Harrison di Boost Your BIM ha pubblicato sull'App Exchange di Autodesk un add-in per la creazione di superfici topografiche direttamente selezionando delle linee di modello in Revit.
Nel mio percorso per imparare ad utilizzare le API di Revit ho cercato di replicare il comportamento di questa add-in e ho aggiunto la possibilità di salvare sul desktop un file .CSV con le coordinate dei punti espresse in millimetri.
Non so se sia esattamente questo il tipo di codice che ha usato Matt, ma dall'esecuzione posso notare che il risultato è persino più preciso di quello che si otterrebbe collegando un DWG con le linee di modello.
Resta sempre la limitazione di non poter realizzare direttamente superfici concave per via dell'algoritmo di triangolazione utilizzato da Revit.



using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Events;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.Collections;
using System.Diagnostics;
using System.IO;
using System.Linq;

//Constant to make a conversion from imperial to metric
const double _FeetTomm = 304.8;
//Here is how we can convert units
public static double FeetTomm(double ftValue)
{
return ftValue * _FeetTomm;
}
//New class to limit the selection only to Model Lines
public class LinePickFilter : ISelectionFilter
        {
            public bool AllowElement(Element e)
            {
                return (e.Category.Id.IntegerValue.Equals(
                    (int)BuiltInCategory.OST_Lines));
            }

            public bool AllowReference(Reference r, XYZ p)
            {
                return false;
            }
        }
//Here starts the code
public void TopoFromCurves()
{
UIDocument uidoc = this.ActiveUIDocument;
Document doc = uidoc.Document;
Selection sel = uidoc.Selection;
LinePickFilter LinePickFilter = new LinePickFilter();
//Prompt the user to select lines
IList curves = sel.PickObjects(ObjectType.Element,
LinePickFilter, "Select source lines for topo surface");
IList p =new List();
//Determining the path of the .CSV file
string dtop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string path = String.Concat(dtop, "\\" +
doc.Title.Remove(doc.Title.Length - 4) + "-TopoFromLines.csv");
string output = "";
//We need to start a transaction in order to modify the database of the file
//The title will be visible in the commands list and the journal file
//the using () structure prevents bad behaviours from happening
using (Transaction t = new Transaction(doc, "Topo From Lines"))
{
t.Start();
foreach (Reference r in curves)
{
//Cast each element in the selection as ModelCurves
//to have access to specific properties
ModelCurve e = doc.GetElement(r) as ModelCurve;
foreach (XYZ q in e.GeometryCurve.Tessellate())
{
//Collect all the points from the lines
p.Add(q);
}
}
//Here writes the .CSV file converting from decimal feets to mm
//replacing the comma with a point as a decimal separator
using (StreamWriter sw = new StreamWriter(path, false))
{
foreach (XYZ v in p)
{
output = FeetTomm(v.X).ToString().Replace(",", ".") + ","
+ FeetTomm(v.Y).ToString().Replace(",", ".") + ","
+ FeetTomm(v.Z).ToString().Replace(",", ".");
sw.WriteLine(output);
}
}
//Create the TopoSurface, Refresh and commit the transaction
doc.Create.NewTopographySurface(p);
uidoc.RefreshActiveView();
t.Commit();
}
}

mercoledì, novembre 06, 2013

Trovare l'inclinazione di un piano partendo da 3 quote - metodo grafico


Trovare l'inclinazione di un pavimento è importante per evitare di ricorrere alla modifica degli elementi secondari, in questo modo saremo certi che il pavimento risultante abbia spessore costante e mantenga la capacità di fungere da host per gli elementi ringhiera, senza dare errori nelle quantità dei materiali.
Geometricamente un piano è definito quando conosciamo le quote (Z) di tre punti che vi appartengono.
Nell'immagine sopra ho riportato il metodo grafico per ottenere la linea di massima pendenza del piano.
Si può sfruttare il principio del metodo grafico anche senza conoscere le quote esatte, come spiegherò in un post successivo


lunedì, novembre 04, 2013

Linee di riferimento - Parametrizzare l'angolo di un solido



Nell'editor delle famiglie possiamo utilizzare le linee di riferimento per vincolare le linee che costituiscono il profilo di un solido di estrusione ad esempio per potere controllare l'angolo tra queste linee e dei piani di riferimento.
Il concetto chiave è che la rotazione viene controllata da un parametro angolo su un particolare oggetto, la linea di riferimento, che viene individuata dall'intersezione di due piani.
Le estremità delle linee di riferimento si possono vincolare alle intersezioni fra i piani utilizzando il comando allinea e successivamente bloccando il lucchetto che compare per stabilire il vincolo.
Per tracciare la linea di riferimento è meglio partire da un punto qualsiasi e terminare in corrispondenza dell'intersezione fra i piani di riferimento per favorire le quote automatiche (di default sono nascoste ma sono alla base della relazionalità geometrica di Revit).
Per posizionare la quota angolare invece è meglio partire dal piano di riferimento che resterà fisso e poi cliccare sulla linea di riferimento.
Quando si entra in modalità di tracciamento si deve fare attenzione a selezionare per ciascuna linea il piano di lavoro appropriato: aiutandosi con il tasto TAB e deselezionando dalla toolbar delle opzioni il concatena, si può realizzare il tipo di relazione desiderata.
Questo tipo di procedura si può seguire anche per i componenti di dettaglio.

giovedì, ottobre 31, 2013

Automatic Floor Sketch


Partendo da una selezione dei locali traccia i pavimenti di finitura corrispondenti. Considera solo gli elementi che delimitano il locale.

mercoledì, ottobre 23, 2013

AEC You and Me

Blog interesessantissimo di Julien Benoit, che ho avuto il piacere di conoscere al Revit Technology Conference di Delft.
Una persona squisita, intelligente e appassionata del proprio lavoro come si può facilmente capire dai primi post che sta pubblicando in questi giorni.
Julien è uno dei moderatori di Revitforum.org, collaboratora per uno dei maggiori general contractor in Francia, Bouygues Construction.
Sta cominciando a condividere i progressi che sta facendo nell'esplorazione delle potenzialità di Dynamo nel lavoro di tutti i giorni.
Da seguire.

martedì, ottobre 22, 2013

Text Type Replacement - Codice Sorgente

Visto l'interesse al post precedente pubblico il codice sorgente per la versione 2012




giovedì, ottobre 17, 2013

View Depth Override - 3D


Questa volta sto lavorando sulle viste 3D in prospettiva degli esterni, come si vede dal video l'algoritmo non è ancora perfetto a causa degli errori introdotti dall'angolo tra il punto di vista e il modello.
Ho trovato però un modo più elegante ed efficiente di eseguire i calcoli anche per la macro delle viste 2D.
La fase successiva interesserà le viste 3D degli interni, e quando finalmente sarò pronto per l'Addin si potrà pensare anche all'aggiornamento automatico delle viste dove viene applicato il comando.

Analytical Tracer - Codice Sorgente

Questo il codice sorgente per la versione 2014, funziona solo per elementi quali pilastri strutturali e travi lineari.
Nella versione 2012 purtroppo non sono riuscito a capire come mai non riuscisse a tracciare correttamente le aste analitiche dei pilastri.
Si potrebbero anche differenziare i tipi di linea per travi e pilastri ma occorre differenziarli poi anche nella tabella dell'esportazione in DWG.

Qui si può scaricare il file sorgente:




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

puntorevit@gmail.com

martedì, ottobre 15, 2013

Analytical Tracer


Con questa macro si possono esportare dei modelli unifilari per elementi strutturali rettilinei che altrimenti risulterebbero divisi in 3 segmenti per ciascuna asta del modello analitico.
Ho fatto una prova veloce con la 2014 si accettano suggerimenti :)

lunedì, ottobre 14, 2013

View Depth Override 2014 - Codice Sorgente

A questo link potete trovare il codice per la versione 2014, in questo caso si possono sostituire graficamente anche i motivi di superficie degli oggetti ma non è possibile agire sulle ombre.



TextNote Type Replacement


Ho dovuto scrivere questa piccola macro per controllare che i testi con lo stesso contenuto inseriti su più tavole avessero il tipo associato corretto.
Morale: non usate i testi!
PLEASE DON'T USE TEXTNOTES!!!

mercoledì, ottobre 09, 2013

View Depth Override - Codice Sorgente


Ecco il codice sorgente per il View Depth Override. Per quelli che non conoscono le API ancora un po' di pazienza e pubblicherò l'add-in per il comando, quella sopra sarà l'icona che pensavo di utilizzare, rende l'idea?

Tanto per cominciare è scritto in C#, testato su Revit Architecture 2012, ecco gli using statements da inserire all'inizio:

using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System.Linq;

Ed ecco il codice vero e proprio, ho inserito dei commenti in inglese per renderlo comprensibile a più persone, nel caso non fosse chiaro chiedete e proverò a spiegarmi meglio:

private XYZ MaxVertex2(XYZ a, XYZ b)
        {
            //Given two points determines the maximum of the Bounding Box that encloses them
            double X = a.X;
            double Y = a.Y;
            double Z = a.Z;
            if (Math.Round(b.X, 5) > X)
                X = b.X;
            if (Math.Round(b.Y, 5) > Y)
                Y = b.Y;
            if (Math.Round(b.Z, 5) > Z)
                Z = b.Z;
            XYZ max = new XYZ(X, Y, Z);
            return max;
        }
        private XYZ MinVertex2(XYZ a, XYZ b)
        {
            //Given two points determines the minimum of the Bounding Box that encloses them
            double X = a.X;
            double Y = a.Y;
            double Z = a.Z;
            if (Math.Round(b.X, 5) < X)
                X = b.X;
            if (Math.Round(b.Y, 5) < Y)
                Y = b.Y;
            if (Math.Round(b.Z, 5) < Z)
                Z = b.Z;
            XYZ min = new XYZ(X, Y, Z);
            return min;
        }
        private ICollection Integral(XYZ min1, XYZ max1, XYZ min2, XYZ max2)
        {
            //If the view is not parrallel to X or Y axis in Global Coordinates,
            //the selecting process is done using an integral approach
            //each segment is subdivided into a high number of subdivisions (200)
            //and smaller bounding boxes are used to filter the objects
            //that's the reason why with a non-parallel view the command is slower
            //This is the list of ElementId created and immediatly cleared
            ICollection ids = new FilteredElementCollector(this.ActiveUIDocument.Document)
            .WhereElementIsNotElementType()
            .ToElementIds();
            ids.Clear();
            foreach (Document doc in this.Application.Documents)
            {
                int subdivisions = 200;
                //Here determines the minimum and the maximum point for the segment based on the four vertices
                //that have been passed from the other function
                XYZ a = MinVertex2(min1, max1);
                XYZ a1 = a;
                XYZ b = MaxVertex2(min1, max1);
                XYZ c = MinVertex2(min2, max2);
                XYZ d = MaxVertex2(min2, max2);
                XYZ increment = (d - b) / subdivisions;
                for (int i = 0; i < subdivisions; i++)
                {
                    //This is tricky: sometimes if the view is perfectly parallel something
                    //about the vertices goes wrong (I guess there's a small tolerance)
                    //Anyway to reduce the amount of calculations if the coordinates are the same
                    //at the fifth decimal digit I assumed the coordinates to be equal
                    //I know it isn't perfect but it worked for me
                    if (Math.Round(a.X, 5) == Math.Round(b.X, 5) || Math.Round(a.Y, 5) == Math.Round(b.Y, 5))
                    {
                        i = subdivisions + 1;
                        a = MinVertex2(a1, d);
                        b = MaxVertex2(a1, d);
                    }
                    Outline ol = new Outline(a, b);
                    if (ol.IsEmpty == false)
                    {
                        //Here comes the filtering part where I tried to avoid all kinds of objects
                        //that are not useful for this task because they can't be overridden
                        //such as Element Types or Sketches of Floors/Roofs/ ceilings and so on
                        BoundingBoxIntersectsFilter BBIIF = new BoundingBoxIntersectsFilter(ol);
                        IEnumerable elems = new FilteredElementCollector(doc)
                        .WherePasses(BBIIF)
                        .WhereElementIsNotElementType()
                        .WhereElementIsViewIndependent()
                        .Cast()
                        .Where(q => q.Category != null && q.Category.HasMaterialQuantities);
                        if (elems.Count() > 0)
                        {
                            foreach (Element e in elems)
                            {
                                ids.Add(e.Id);
                            }
                        }
                    }
                    else
                    {
                        a = a + increment;
                        b = b + increment;
                    }
                    a = a + increment;
                    b = b + increment;
                }
            }
            return ids;
        }
        private ICollection IntegralCollection(View view, int i)
        {
            //Here is where the coordinates of the Bounding Box of the view are calculated
            //I don't like that this calculations are repeted each time this function is called (one for each segment)
            //it could be done more efficiently and for sure more clearly using the Transform...
            //but I didn't even know what that was when I recorded the video
            //the double scale is set to 1 because at first I started from the UV Bounding Box,
            //which contains also annotations and not just the model categories
            //I then used the Bounding BOX XYZ and reused the code I wrote before
            XYZ CurrentViewOrigin = view.Origin;
            double scale = 1;
            XYZ VRight = view.RightDirection;
            XYZ VUp = view.UpDirection;
            XYZ Vdir = view.ViewDirection;
            XYZ Vmin = view.CropBox.Min;
            XYZ Vmax = view.CropBox.Max;
            //I used letters for the Vertices of the main Bounding Box
            //rather then numbers for the inner box that defines the middle segment
            //I know this part looks messy but it was good to refresh some algebra concepts :)
            //here is were I should use the Transform
            XYZ Va = new XYZ(CurrentViewOrigin.X + scale * (Vmin.X * VRight.X + Vmin.Y * VUp.X) + Vmax.Z * Vdir.X, CurrentViewOrigin.Y + scale * (Vmin.X * VRight.Y + Vmin.Y * VUp.Y) + Vmax.Z * Vdir.Y, CurrentViewOrigin.Z + scale * (Vmin.X * VRight.Z + Vmin.Y * VUp.Z) + Vmax.Z * Vdir.Z);
            XYZ Vb = new XYZ(CurrentViewOrigin.X + scale * (Vmin.X * VRight.X + Vmax.Y * VUp.X) + Vmax.Z * Vdir.X, CurrentViewOrigin.Y + scale * (Vmin.X * VRight.Y + Vmax.Y * VUp.Y) + Vmax.Z * Vdir.Y, CurrentViewOrigin.Z + scale * (Vmin.X * VRight.Z + Vmax.Y * VUp.Z) + Vmax.Z * Vdir.Z);
            XYZ Vc = new XYZ(CurrentViewOrigin.X + scale * (Vmax.X * VRight.X + Vmax.Y * VUp.X) + Vmax.Z * Vdir.X, CurrentViewOrigin.Y + scale * (Vmax.X * VRight.Y + Vmax.Y * VUp.Y) + Vmax.Z * Vdir.Y, CurrentViewOrigin.Z + scale * (Vmax.X * VRight.Z + Vmax.Y * VUp.Z) + Vmax.Z * Vdir.Z);
            XYZ Vd = new XYZ(CurrentViewOrigin.X + scale * (Vmax.X * VRight.X + Vmin.Y * VUp.X) + Vmax.Z * Vdir.X, CurrentViewOrigin.Y + scale * (Vmax.X * VRight.Y + Vmin.Y * VUp.Y) + Vmax.Z * Vdir.Y, CurrentViewOrigin.Z + scale * (Vmax.X * VRight.Z + Vmin.Y * VUp.Z) + Vmax.Z * Vdir.Z);
            XYZ Ve = new XYZ(CurrentViewOrigin.X + scale * (Vmin.X * VRight.X + Vmin.Y * VUp.X) + Vmin.Z * Vdir.X, CurrentViewOrigin.Y + scale * (Vmin.X * VRight.Y + Vmin.Y * VUp.Y) + Vmin.Z * Vdir.Y, CurrentViewOrigin.Z + scale * (Vmin.X * VRight.Z + Vmin.Y * VUp.Z) + Vmin.Z * Vdir.Z);
            XYZ Vf = new XYZ(CurrentViewOrigin.X + scale * (Vmin.X * VRight.X + Vmax.Y * VUp.X) + Vmin.Z * Vdir.X, CurrentViewOrigin.Y + scale * (Vmin.X * VRight.Y + Vmax.Y * VUp.Y) + Vmin.Z * Vdir.Y, CurrentViewOrigin.Z + scale * (Vmin.X * VRight.Z + Vmax.Y * VUp.Z) + Vmin.Z * Vdir.Z);
            XYZ Vg = new XYZ(CurrentViewOrigin.X + scale * (Vmax.X * VRight.X + Vmax.Y * VUp.X) + Vmin.Z * Vdir.X, CurrentViewOrigin.Y + scale * (Vmax.X * VRight.Y + Vmax.Y * VUp.Y) + Vmin.Z * Vdir.Y, CurrentViewOrigin.Z + scale * (Vmax.X * VRight.Z + Vmax.Y * VUp.Z) + Vmin.Z * Vdir.Z);
            XYZ Vh = new XYZ(CurrentViewOrigin.X + scale * (Vmax.X * VRight.X + Vmin.Y * VUp.X) + Vmin.Z * Vdir.X, CurrentViewOrigin.Y + scale * (Vmax.X * VRight.Y + Vmin.Y * VUp.Y) + Vmin.Z * Vdir.Y, CurrentViewOrigin.Z + scale * (Vmax.X * VRight.Z + Vmin.Y * VUp.Z) + Vmin.Z * Vdir.Z);
            XYZ V1 = Ve + (Va - Ve) * 2 / 3;
            XYZ V2 = Vf + (Vb - Vf) * 2 / 3;
            XYZ V3 = Vg + (Vc - Vg) * 2 / 3;
            XYZ V4 = Vh + (Vd - Vh) * 2 / 3;
            XYZ V5 = Ve + (Va - Ve) / 3;
            XYZ V6 = Vf + (Vb - Vf) / 3;
            XYZ V7 = Vg + (Vc - Vg) / 3;
            XYZ V8 = Vh + (Vd - Vh) / 3;
            //This function returns a list of ElementId to be overridden depending on which one of
            //the three segments the objects fall in
            ICollection list = new FilteredElementCollector(ActiveUIDocument.Document)
            .WhereElementIsNotElementType()
            .ToElementIds();
            list.Clear();
            if (i == 0)
            {
                list = Integral(Va, V2, Vd, V3);
            }
            else
            {
                if (i == 1)
                {
                    list = Integral(V1, Vf, V4, Vg);
                }
                else
                {
                    list = Integral(V5, Vf, V8, Vg);
                }
            }

            return list;
        }
        public void ViewDepthOverride()
        {
            //known issues: doesn't work with linked files and 3D Views
            UIDocument uidoc = this.ActiveUIDocument;
            Document doc = uidoc.Document;
            //Creates the lists of ElementId to pass to the Projection Color Override by Element
            //those are just empty container at the moment
            ICollection ids0 = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Levels).ToElementIds();
            ICollection ids1 = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Levels).ToElementIds();
            ICollection ids2 = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Levels).ToElementIds();
            ids0.Clear();
            ids1.Clear();
            ids2.Clear();
            View CurrentView = doc.ActiveView;
            //It works fine for 2D views, building sections and elevations for example
            //it should work also with floor plans and even tilted Detail Views
            //but it wasn't my goal when I started
            //won't work for a 3D View
            int clip = CurrentView.get_Parameter(BuiltInParameter.VIEWER_BOUND_FAR_CLIPPING).AsInteger();
            //If the far clipping is not active the default depth is 10 feet and won't work correctly
            if (clip == 0)
            {
                TaskDialog.Show("View Depth Override", "In order to use this macro far clipping must be activated.");
            }
            else
            {
                //If the far clipping is active then the view depth can be subdivided into 3 segments:
                //foreground (0)
                //middle (1)
                //background (2)
                ids0 = IntegralCollection(CurrentView, 0);
                ids1 = IntegralCollection(CurrentView, 1);
                ids2 = IntegralCollection(CurrentView, 2);
                //Just a check to handle some common errors, for instance not even one
                //ElementId was found in the foreground view interval
                if (ids0.Count == 0)
                {
                    TaskDialog.Show("View Depth Override", "Something went wrong in the closer segment.\n\nPlease adjust the view depth to include some objects.");
                    ElementId e = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls).FirstElement().Id;
                    ids0.Add(e);
                    ids1.Add(e);
                    ids2.Add(e);
                }
                else
                {
                    //Again just a check to handle some common errors, in this case not even one
                    //ElementId was found in the background view interval
                    //because the view depth is too much rather then just enough to enclos
                    //the objects in the model
                    if (ids2.Count == 0)
                    {
                        TaskDialog.Show("View Depth Override", "Something went wrong in the farther segment to be overridden in Grey 192.\n\nPlease check that the view depth in the current view is just enough to include the objects you need.");
                        ElementId e = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls).FirstElement().Id;
                        ids2.Add(e);
                        ids1.Add(e);
                    }
                }
            }
            //Begins the transaction to override the elements
            using (Transaction t = new Transaction(doc, "View Depth Override"))
            {
                t.Start();
                while (ids0.Count > 0)
                {
                    //Stores the color for the foreground
                    Color Color0 = CurrentView.get_ProjColorOverrideByElement(ids0);
                    if (ids1.Count != 0)
                    {
                        //Overrides the middle segment
                        CurrentView.set_ProjColorOverrideByElement(ids1, new Color((byte)128, (byte)128, (byte)128));
                    }
                    else
                    {
                        //Just a precaution, not sure it is really necessary
                        TaskDialog.Show("View Depth Override", "Something went wrong in the middle segment to be overridden in Grey 128.\n\nPlease check that the view depth in the current view is just enough to include the objects you need.");
                        break;
                    }
                    if (ids2.Count != 0)
                    {
                        CurrentView.set_ProjColorOverrideByElement(ids2, new Color((byte)192, (byte)192, (byte)192));
                    }
                    else
                    {
                        //Overrides the background segment
                        TaskDialog.Show("View Depth Override", "Something went wrong in the farther segment to be overridden in Grey 192.\n\nPlease check that the view depth in the current view is just enough to include the objects you need.");
                        break;
                    }
                    //Resets the foreground color in case of objects overlapping
                    //foreground and middle segment
                    CurrentView.set_ProjColorOverrideByElement(ids0, Color0);
                    break;
                }
                doc.Regenerate();
                uidoc.RefreshActiveView();
                t.Commit();
            }
        }  


martedì, ottobre 08, 2013

View Depth Override

Da qualche tempo mi sto interessando più da vicino al mondo della personalizzazione di Revit attraverso l'implementazione delle API.
Una dei primi comandi su cui sto lavorando è il View Depth Override ossia la sostituzione automatica delle linee di proiezione degli oggetti in funzione della profondità di campo della vista.

Qui c'è un video dimostrativo:



Il concetto è semplice: per viste di sezione o prospetto, si imposta la profondità della vista e si esegue il comando. La profondità della vista viene divisa in tre settori (primo piano, intermedio e sfondo), vengono effettuate delle sostituzioni grafiche (grigio 128 per il settore intermedio e grigio 192 per quello di sfondo) per simulare la profondità della vista.
Il comando viene eseguito anche se non ci sono oggetti in primo piano, quindi la posizione della vista rispetto al modello ha effettivamente rilevanza per il risultato finale.
Al momento non funziona per i file collegati ed è un comando di tipo "fire and forget" ossia viene eseguito una volta e poi non si aggiorna automaticamente se intervengono cambiamenti nel modello, ma non escludo si possa intervenire per eliminare questi inconvenienti.
Se interessa posso pubblicare il comando ma devo prima testarlo sulle release successive, tenuto conto che lo faccio più per passione e non intendo diventare un programmatore :)

Update qui!