Visualizzazione post con etichetta csv. Mostra tutti i post
Visualizzazione post con etichetta csv. Mostra tutti i post

martedì, gennaio 28, 2014

Dynamo - CSV to XYZ





Partendo da un file CSV ho cercato di ottenere attraverso Dynamo dei punti di riferimento nell'ambiente delle masse o dei modelli generici adattivi, avevo infatti notato che esisteva già nei custom nodes un nodo che avrebbe dovuto fare al caso mio.
Tuttavia esistono due tipi di problemi: il primo banale è che non vedo all'interno della definizione del nodo  a cosa possa corrispondere l'input "multiplier", il secondo è che i valori accettati in input devono essere stringhe numeriche con la virgola per separatore decimale, la qual cosa non si presenta mai per un file CSV per non generare confusione visto che la virgola assolve la funzione di delimitatore dei valori.

Ho scritto quindi la definizione dell'esempio nel video che va copiata qui:

C:\Autodesk\Dynamo\Core\definitions

per creare le triplette XYZ a partire da un CSV. Da prima ho impostato come delimitatore la stringa che "va a capo" (ho premuto invio all'interno del campo per inserire la stringa) ed ho applicato il nodo Split String. Questo genera una lista di stringhe di dimensione pari al numero di righe del CSV.
Per poterle manipolare e ricavare le coordinate si deve applicare ancora uno Split String a ciascun elemento della lista appena creata, stavolta però utilizzando come delimitatore la virgola (è come se stessimo estraendo i valori da una riga del file CSV). Per fare questo su ogni elemento della lista occorre applicare un nodo Map, che per sintassi richiede in input una funzione e una sequenza di valori.
Personalmente ho trovato poco chiara la struttura della funzione di input f(x), perché è un nodo che rimane grigio. Quello che viene sottointeso è che la funzione in grigio viene applicata ad un elemento che deriva dalla sequenza.
Nella fattispecie si ottiene una lista di tre coordinate X[0],Y[1],Z[2] per ciascuna riga del file CSV.
Se per qualsiasi motivo il file dovesse troncarsi o avere un ritorno a capo questo genererebbe un errore nella procedura, così ho introdotto un controllo per eliminare l'ultima lista con meno di 3 elementi di coordinate.



Con Get from List composto a ParseString (un custom node per restituire correttamente i valori delle stringhe numeriche nel file CSV) si ottengono le liste dei valori di tutte le coordinate X, Y e Z, è poi banale ottenere le triplette per le entità geometriche XYZ che servono a generare i punti di riferimento in Revit.

Come precauzione i valori ottenuti dal CSV sono moltiplicati per un valore 1, cambiando il quale si può scalare il risultato del nodo (va tenuto presente che le unità di misura interne di Revit sono i piedi decimali).


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

puntorevit@gmail.com

Dynamo - ParseString



Ho notato che la funzione presente nel core di Dynamo che consente di effettuare il parsing di una stringa di testo (convertire la "natura" della variabile da testo a numero) non funziona correttamente per i testi che hanno per separatore decimale il punto al posto della virgola.
Per questo motivo ho deciso di scrivere un nodo in grado di effettuare il parsing per "stringhe numeriche" in modo più flessibile.
Questa volta ho cercato un approccio "purista" al problema, senza ricorrere agli script dei linguaggi di programmazione, ma soltanto ricorrendo ai nodi presenti nelle daily build di Dynamo anche se è più laborioso, sicuramente mi ha fatto scoprire alcune strutture che possono tornare utili in altre circostanze.
Questa la definizione del nodo che va copiata qui:

C:\Autodesk\Dynamo\Core\definitions

Quando si inserisce una stringa che rappresenta un numero possiamo avere o un numero intero o dei decimali; per i decimali il separatore che siamo abituati ad utilizzare può essere o il punto "." oppure la virgola "," (Revit internamente usa la virgola e questo è proprio il motivo per cui il nodo String to Number presente di default produce un errore nel caso del punto come separatore decimale).

Se pensiamo però agli output più tradizionali come ad esempio un CSV, il delimitatore dei valori è una virgola e per non generare confusione si utilizza il punto per i decimali. Diventa quindi importante poter gestire correttamente qualsiasi tipo di stringa numerica.

La struttura quindi della stringa sarà:

Parte intera  - Separatore decimale - Parte decimale          

Il nodo Split String permette di creare delle liste a partire da una stringa dividendo la stessa quando incontra un delimitatore. Se inseriamo quindi una stringa numerica e una stringa contenente il separatore decimale otteniamo come risultato una lista di due elementi, rispettivamente all'indice [0] ciò che sta prima del delimitatore partendo da sinistra (la parte intera) e all'indice [1] ciò che rimane (la parte decimale), proprio perché il delimitatore può comparire una sola volta all'interno della stringa numerica.
Utilizzando Get from List è possibile estrarre la stringa corrispondente alla parte intera e quella decimale, per i quali utilizzando Stirng to Number si ottengono due numeri interi. Per ottenere il valore corretto della parte decimale basterà dividerlo per una potenza di 10, con esponente pari alla lunghezza della stringa della parte decimale. Sommando poi i valori della parte intera e di quella decimale, si ottiene il valore corretto.
Ecco un esempio, le stringhe sono comprese tra "" :

stringa numerica = "12.3456"
stringa parte intera= "12"
stringa parte decimale= "3456"
lunghezza stringa parte decimale= 4
valore parte intera = 12
valore parte decimale= 3456/10^4=0.3456
valore finale = 12+0.3456=12.3456

Per semplicità ho creato due copie della stessa procedura (anche se ammetto non sia la soluzione più elegante) una valida quando il separatore è il punto, e l'altra valida per la virgola. Per fare questo ci sono più nodi If che permettono di eseguire una serie di istruzioni piuttosto che un'altra a seconda dell'esito di un test.
In particolare se il separatore decimale esiste per la stringa numerica, la lista risultante da Split String avrà un numero di elementi maggiore di uno, in caso contrario la stringa numerica rappresenta un valore intero.
If you are happy with my code you can show me some gratitude paying what you want on PayPal:

puntorevit@gmail.com

Topo to CSV - External command


Prendendo spunto da un'applicazione già vista e da un possibile uso dell'External Command precedente, ho creato questo exporter per i punti delle superfici topografiche.
Viene creato un file CSV sul desktop che riporta per ciascuna riga le coordinate XYZ di un punto espresse in piedi decimali.

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

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

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