Il Bar dell'Ingegneria

Excel --> DXF

« Older   Newer »
 
  Share  
.
  1.     +2   +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    In questo topic intendo riportare le funzioni e procedure dedicate alla creazione di un file .dxf a partire da una tabella dati composta in un qualsiasi foglio excel.
    La tabella può contenere i dati relativi alle primitive (Entities) previste nel formato R12 del Dxf ed in particolare:
    - linee
    - polilinee
    - punti
    - archi
    - cerchi
    - testi
    in un numero qualsiasi di occorrenze. In questo modo sarà possibile creare un unico dxf in cui sono disegnate più polilinee o piu segmenti o archi o cerchi.


    Le funzioni/procedure qui trattate saranno poi trasferite nel Sagomario e sarà quindi possibile creare il dxf anche per i profili accoppiati.

    NZWUO7H
     
    Top
    .
  2.     +1   +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    Come prima cosa ci serve il nome del file che creeremo e per questo dedicheremo il primo rigo della tabella a contenere il nome proposto nel dialogo di salvataggio. Nel sagomario potrebbe per esempio essere il nome del profilo scelto.

    Poi ci serve poter selezionare da dialogo standard di salvataggio del file sia il nome che intendiamo dare al file (modificando quello proposto) e sia la cartella dove depositarlo.
    Per questo utilizzerò il dialogo standard di excel relativo al Save As, anche se questo dà il problema di non poter variare l'estensione del file se non tra quelli tipici di file excel. Risolverò la questione da codice facendo togliere l'estensione che ci restituisce il dialogo e sostituendola con .dxf.

    ecco quindi la funzione:


    CODICE
    Function salvaFile(ByRef NomeFile As String) As Boolean

    ' seleziona il nome del file da salvare
    ' attraverso il dialogo standard "salva con nome2 di excel
    ' toglie l'estensione .xls ed aggiunge l'estensione .dxf
    ' restituisce
    ' vero: se, nella finestra, è stato scelto il nome
    ' ed è stato premuto ok
    ' falso altrimenti
    ' Il nome del file scelto è contenuto nella variabile NomeFile passata per argomento

    ' Non viene eseguito alcun controllo di esistenza del file
    ' o di file già in uso.

       Dim fd As FileDialog
       Dim Sel As String
       Set fd = Application.FileDialog(msoFileDialogSaveAs)
       With fd
           .Title = "Crea DXF"
           .InitialFileName = ThisWorkbook.Path & "\" & NomeFile
           If .Show = -1 Then
               Sel = .SelectedItems(1)
               NomeFile = VBA.Mid(Sel, 1, Len(Sel) - 5) + ".dxf"
               salvaFile = True
           Else
               salvaFile = False
           End If
       End With
       Set fd = Nothing
    End Function


    Per la scelta del nome del file da creare utilizzo uno dei dialoghi standard che vediamo nel corso di un normale utilizzo di excel.
    Vi sono quattro tipi di dialoghi disponibili (vedi link che segue Tipi di dialoghi ) tra questi l'unica scelta possibile è il dialogo "save as " (salva con nome), dato che gli altri dialoghi si aspettano la selezione di un file gia presente nel disco rigido.

    Con l'istruzione

    fd.InitialFileName = ThisWorkbook.Path & "\" & NomeFile

    fisso la cartella dove depositare il file dxf creato uguale alla cartella che contiene il file excel che chiama la funzione. Se questa cartella ha limitazioni dei diritti di scrittura apparira la finestra che avvisa di cambiare il percorso.

    La scelta del dialogo tipo "save as" pone però qualche problema:

    - non è possibile modificare la lista dei filtri di file e quindi saranno proposti solo i file di tipo excel nelle varie versioni e formati
    Pertanto il file in uscita dal dialogo avrà una estensione diversa da .dxf.
    Per poter eseguire autocad direttamente da excel col disegno creato è necessario che il nome del file abbia estensione .dxf altrimenti non viene riconosciuto da autocad come file che può gestire.

    Ho pensato quindi di rimuovere da codice l'estensione attribuita dal dialogo e sostituirla con .dxf.
    Ma qui sorge altro problema che consiste nel fatto che le estensioni previste nel filtro del dialogo possono avere sia tre caratteri sia quattro caratteri.

    Io ho ipotizzato che l'utente in excel 2007 non cambi l'iniziale estensione "xlsx" ed ho quindi sottratto i quattro caratteri finali sostituendoli con "dxf".
    Ma dato che il foglio sarà distribuito anche per excel 2003, la cui estensione principale è "xls" (tre caratteri), può accadere che l'utente scelga un nome con un solo carattere ed il risultato, sottraendo quattro caratteri dal nome, sarà un nome costituito dalla sola estensione .dxf.

    Quindi un avviso per chi usa excel 2003 è quello di dare un nome di almeno due caratteri per evitare l'errore.

    Edited by afazio - 23/8/2014, 23:42
     
    Top
    .
  3.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    Vediamo adesso per ciascuna delle primitive che voglio far disegnare cosa ci serve.

    La polilinea.

    Per disegnare la polilinea ci serve l'elenco delle coordinate dei suoi vertici e gli eventuali smussi/raccordi presenti nei vertici.
    ho pensato quindi di scrivere nella prima colonna la parola chiave "Polilinea" e nella seconda il numero dei vertici che compongono la polilinea.
    A questo punto, avuto il numero dei vertici Nv della polilinea dedichiamo Nv righe atte a contenere le coordinate x,y,z dei vertici ed il parametro "smusso" del vertice.

    Il formato della tabella prenderebbe questa forma:

    IjGPoFA

    da codice farò leggere il contenuto della prima colonna del rigo iesimo e se questo è uguale alla parola chiave "Polilinea", faro leggere il contenuto della seconda colonna e lo deposito nella variabile Nvi. Quindi opero un ciclo che va dal rigo successivo (i+1) al rigo (i+1+Nv) leggendo i dato della terza, quarta quinta e sesta colonna depositandoli nelle variabili x,y,z,k.

    Lo "smusso o raccordo" è il parametro che viene indicato col nome "bulge" nella guida inglese per la scrittura dei dati di una polilinea e rappresenta la tangente del quarto dell'angolo (in radianti) formato tra i due lati della polilinea convergenti nel vertice in questione.
    Il segno dello smusso è positivo se per passare dal lato antecedente al lato successivo, l'arco viene percorso in senso antiorario, negativo altrimenti. Se al parametro "bulge" viene dato segno opposto a quello sopra stabilito, si otterrano "bulbi" cioè archi di cerchio con punti di attacco ai lati della polilinea ortogonali a questi ultimi (anzichè tangenti).

    Fin qui ho descritto il formato della tabella dati che dovremo creare in un foglio excel.
    Adesso vediamo come scrivere i dati in un file conformemente al formato dxf nella sua versione R12

    Lo schema è il seguente:

    - primo passo: aprire la polilinea o in altre parole indicare che i blocchi dati a seguire si riferiscono ad una polilinea.

    - secondo passo: scrivere i vertici

    - ultimo passo: chiudere la polilinea o in altre parole indicare che i blocchi dei dati relativi alla polilinea in questione sono terminati.

    Ecco la sub che "apre" una poliilinea:

    CODICE
    Sub dxf_open_poly(ByVal n_file As Integer, A As Integer)
       Print #n_file, "0"
       Print #n_file, "POLYLINE"
       
       Print #n_file, "5"
       Print #n_file, VBA.Hex(A)
       
       Print #n_file, "8"
       Print #n_file, "0"
       
       Print #n_file, "66"
       Print #n_file, "1"
       
       Print #n_file, "10"
       Print #n_file, "0.0"
       
       Print #n_file, "20"
       Print #n_file, "0.0"
       
       Print #n_file, "30"
       Print #n_file, "0.0"
    End Sub


    Occorre sapere che un file di tipo dxf è strutturato come una sequenza di coppie di valori, ognuno su una riga separata.
    Il primo valore e’ chiamato codice di gruppo, e specifica a quale tipo di dati appartiene il secondo valore

    Alcuni codici di gruppo sono fissi nel sensoc he hanno un significato ben determinato. Cosi per esempio il codice di gruppo 10 indica che il valore che lo segue è un Double e rappresenta la coordinata x di un punto
    IL codice "0" indica che il dato che segue è una stringa.
    Se la stringa è il nome di una entita predefinita in autocad significa che tutti i dati che seguono si riferiscono a questo tipo di entità.

    Il codice "5" indica che il dato seguente rappresenta l'ID dell'entità, un numero unico (non devono esistere due ID uguali. Non ci devono essere salti tra un ID ed il successivo. L'ID deve essere dato in esadecimale

    Il codice di gruppo "62" rappresenta il colore (un intero tra 0 (bylayer) e 255. Se questo codice viene omesso allora si assume il defalut "ByLayer".

    Il codice di gruppo "66" indica il vertices-follow flag che non ho ben capito cosa faccia e che ho riscontrato dalle prove di salvataggio di polilinea che ho condotto, viene assunto sempre pari a 1

    i codici di gruppo "10", "20","30" sono:
    10, 20, 30 (polyline elevation - 30 supplies elevation, 10 and 20 are always set to zero)

    il codice di gruppo "8" non so cosa fa ma ho visto che viene sempre impostato a zero. Penso sia legato alla tridimensinalità o meno della polilinea.
    . Indica il layer --> Vedere intervento di zax.
    Alla sub, come vedete, si devono passare:
    - il numero del file aperto in scrittura
    - il numero dell'ID da attribuire all'entità

    Per comodità passo quest'ultimo dato come un intero ed all'atto della scrittura lo trasformo in esadecimale con la funzione VBA.Hex().

    Salto per adesso il secondo passo e presento il codice relativo al terzo passo della scrittura di una polilinea in unfile .dxf.

    CODICE
    Sub dxf_close_poly(ByVal n_file As Integer, A As Integer)
       Print #n_file, "0"
       Print #n_file, "SEQEND"
       
       Print #n_file, "5"
       Print #n_file, VBA.Hex(A)
       
       Print #n_file, "8"
       Print #n_file, "0"
    End Sub


    Qui la parola chiave che chiude la poliline è "SEQUEND" (fine della sequenza dei vertici. Anche alla chiusura della polilinea deve essere attribuito un ID.

    Anche in questo caso alla sub vengono passati i due dati:

    - il numero del file aperto in scrittura
    - il numero dell'ID da attribuire

    Vediamo adesso il secondo passo, quello che scrive la sequenza dei vertici.

    ecco la sub:

    CODICE
    Sub dxf_vertex(ByVal n_file As Integer, A As Integer, x As Double, y As Double, z As Double, k As Double)

       Print #n_file, "0"
       Print #n_file, "VERTEX"
       
       Print #n_file, "5"
       Print #n_file, VBA.Hex(A)
       
       Print #n_file, "8"
       Print #n_file, "0"
       
       Print #n_file, "10"
       Print #n_file, Punto(x)
       Print #n_file, "20"
       Print #n_file, Punto(y)
       Print #n_file, "30"
       Print #n_file, Punto(z)
       
       Print #n_file, "42"
       Print #n_file, Punto(k)
       
    End Sub


    La parola chiave che indica che trattasi di un vertice è "VERTEX" con codice di gruppo "0"

    alla sub occorre passare i seguenti dati:
    - il numero del file aperto in scrittura
    - il numero dell'ID da attribuire al vertice
    - coordinata x del vertice
    - coordinata y del vertice
    - coordinata z del vertice
    - smusso k nel vertice
    Notate che il codice di gruppo relativo allo "smusso/bulge" è il "42"

    Naturalmente la sub deve essere chiamata tante volte quanti sono i vertici presenti nella polilinea.

    Qui vi annoto il fatto che nel file dxf i dati numerici decimali devono avere come separatore il punto e non la virgola. Ho quindi costruito una funzione in modo che qualsiasi sia l'impostazione di excel i dati numerici vengano sempre salvati col punto decimale.

    CODICE
    Function Punto(numero As Double) As String

    Dim Testo As String
    Dim testo1 As String
    Dim lung As Integer
    Dim i As Integer
    Dim carattere As String

    numero = Round(numero, 16)
    Testo = VBA.LTrim(VBA.RTrim(VBA.Str(numero)))
    lung = Len(Testo)
    testo1 = ""
    For i = 1 To lung + 1
       carattere = VBA.Mid(Testo, i, 1)
       If carattere = "," Then carattere = "."
       testo1 = Testo + carattere
    Next
    Punto = VBA.RTrim(VBA.LTrim(testo1))
    End Function


    Edited by afazio - 24/8/2014, 13:52
     
    Top
    .
  4.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    Continuando nell'analisi dei dati necessari per ciascuna delle primitive che vogliamo disegnare abbiamo:

    Per il punto:
    - sono necessarie le tre coordinate x, y, z
    Per la Linea:
    - sono necessarie le coordinate xi, yi, zi del punto di inizio e le coordinate xf, yf e zf del punto finale
    Per il cerchio:
    - sono necessarie le coordinate xc, yc, zc del suo centro ed il raggio r
    Per l'arco di cerchio:
    - sono necessarie le coordinate xc, yc, zc del suo centro, il raggio r, l'angolo di partenza e l'angolo di fine arco.
    Per il Testo:
    - sono necessari il testo da inserire, le coordinate xt, yt, zt del punto di inserimento, l'altezza h del testo e l'inclinazione del testo.

    Ho riassunto tutto quanto nella seguente tabella che rappresenta come intendo strutturare i dati da dare in pasto alla procedura che crea il file .dxf.

    dT1EABM
     
    Top
    .
  5.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    Ecco la procedura che scrive il punto all'interno del file dxf.

    CODICE
    Sub dxf_Point(ByVal n_file As Integer, A As Integer, x As Double, y As Double, z As Double)
       Print #n_file, "0"
       Print #n_file, "POINT"
       
       Print #n_file, "5"
       Print #n_file, VBA.Hex(A)
       
       Print #n_file, "8"
       Print #n_file, "0"
       
       Print #n_file, "10"
       Print #n_file, Punto(x)
       Print #n_file, "20"
       Print #n_file, Punto(y)
       Print #n_file, "30"
       Print #n_file, Punto(z)
    End Sub


    notare che i due parametri numero del file in scrittura (n_file) ed ID dell'elemento (A) sono sempre presenti ed in questo caso sono presenti anche i tre parametri che indicano le coordinate del punto.
    Per quanto riguarda il codice di gruppo "8" ho fatto delle prove omettendolo ed il risultato è stato che... in file dxf non riporta proprio nulla ed Autocad si blocca con una richiesta di pressione del tasto enter per continuare. Concludo quindi che la sua presenza è fondamentale.


    In merito all'entità punto vi segnalo il fatto che questo saraà visualizzato con il contrassegno quasi invisibile tipico di Autocad. Potete poi sceglier qualsiasi altro contrassegno dal menu autocad Formato-->Stile punto ...
     
    Top
    .
  6.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    Ecco la sub che scrive un segmento nel file dxf:

    CODICE
    Sub dxf_line(ByVal n_file As Integer, A As Integer, X1 As Double, y1 As Double, z1 As Double, x2 As Double, y2 As Double, z2 As Double)
       Print #n_file, "0"
       Print #n_file, "LINE"
       
       Print #n_file, "5"
       Print #n_file, VBA.Hex(A)
       
       Print #n_file, "8"
       Print #n_file, "0"
       
       Print #n_file, "10"
       Print #n_file, Punto(X1)
       Print #n_file, "20"
       Print #n_file, Punto(y1)
       Print #n_file, "30"
       Print #n_file, Punto(z1)
       
       Print #n_file, "11"
       Print #n_file, Punto(x2)
       Print #n_file, "21"
       Print #n_file, Punto(y2)
       Print #n_file, "31"
       Print #n_file, Punto(z2)
    End Sub


    Qui faccio notare oltre alla immancabile presenza dei codici di gruppo "0" relativo al tipo di entità, "5" relativo all 'ID ed "8" relativo a non so cosa ma essenziale, vi sono i codici di gruppo "11", "21", "31" relativi alle coordinate del secondo punto.

    Il cerchio:

    CODICE
    Sub dxf_circle(ByVal n_file As Integer, A As Integer, xc As Double, yc As Double, zc As Double, r As Double)
       Print #n_file, "0"
       Print #n_file, "CIRCLE"
       
       Print #n_file, "5"
       Print #n_file, VBA.Hex(A)
       
       Print #n_file, "8"
       Print #n_file, "0"
       
       Print #n_file, "10"
       Print #n_file, Punto(xc)
       Print #n_file, "20"
       Print #n_file, Punto(yc)
       Print #n_file, "30"
       Print #n_file, Punto(zc)
       
       Print #n_file, "40"
       Print #n_file, Punto(r)
    End Sub


    L'arco di cerchio:

    CODICE
    Sub dxf_Arc(ByVal n_file As Integer, A As Integer, xc As Double, yc As Double, zc As Double, _
                  r As Double, alfa1 As Double, alfa2 As Double)
       Print #n_file, "0"
       Print #n_file, "ARC"
       
       Print #n_file, "5"
       Print #n_file, VBA.Hex(A)
       
       Print #n_file, "8"
       Print #n_file, "0"
       
       Print #n_file, "10"
       Print #n_file, Punto(xc)
       Print #n_file, "20"
       Print #n_file, Punto(yc)
       Print #n_file, "30"
       Print #n_file, Punto(zc)
       Print #n_file, "40"
       Print #n_file, Punto(r)
       
       Print #n_file, "50"
       Print #n_file, Punto(alfa1)
       Print #n_file, "51"
       Print #n_file, Punto(alfa2)
    End Sub


    Ed infine il testo:

    CODICE
    Sub dxf_Text(ByVal n_file As Integer, A As Integer, x As Double, y As Double, z As Double, _
                  h As Double, alfa As Double, Testo As String)
       Print #n_file, "0"
       Print #n_file, "TEXT"
       
       Print #n_file, "5"
       Print #n_file, VBA.Hex(A)
       
       Print #n_file, "8"
       Print #n_file, "0"
       
       Print #n_file, "10"
       Print #n_file, Punto(x)
       Print #n_file, "20"
       Print #n_file, Punto(y)
       Print #n_file, "30"
       Print #n_file, Punto(z)
       Print #n_file, "40"
       Print #n_file, Punto(h)
       
       Print #n_file, "50"
       Print #n_file, Punto(alfa)
       
       Print #n_file, "1"
       Print #n_file, Testo
    End Sub


    La chiamata a queste sub avviene attraverso una procedura che legge i dati dalla tabella, distingue di che si tratta e chiama quindi all'azione le varie specifiche sub.
    Ma la sub principale deve anche:
    - aprire ilf ile in scrittura
    - aprire il file dxf
    - leggere i dati dalla tabella e fare le chiamate opportune
    - chiudere il file dxf
    - chiudere il file inscrittura

    Illustrerò la procedura principale domani.

    buona notte
     
    Top
    .
  7.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Member
    Posts
    2,939
    Reputation
    +187

    Status
    Offline
    Afazio, ti confermo che il codice "8" indica che nel rigo successivo Autocad legge il nome del layer a cui l'entità appartiene.

    In pratica il codice "8" è presente per tutte le entità di disegno (linee, punti, cerchi, testi, ecc.) che compongono il disegno.

    Dovrebbero esserci anche altri codici, come quello per il colore, il tipo di linea (per linee e polilinee), e nelle versioni più recenti di Autocad anche per lo spessore delle linee, ed altre cose, che comunque possono essere 'ricomprese' con la sola indicazione del layer, e che se non diversamente specificate vengono prelevate dal default del layer stesso.

    In ogni caso, il file dxf è un file di testo puro. Con una formattazione specifica, che nel corso delle versioni si è via via lievemente incasinata. La versione R12 a cui tu faresti riferimento, a parte che fa da specchietto delle allodole per la tua età, è effettivamente abbastanza semplice da manipolare.

    Come tutti i file di questo genere, il formato prevede un "header", ossia una intestazione con una serie di informazioni di sistema, suddivisa in sezioni, ed infine la sezione realmente importante che è quella denominata "ENTITIES" che contiene proprio tutte le entità di disegno che verranno visualizzate a video.

    All'interno della sezione "ENTITIES" ogni singolo 'pezzo' di disegno (un punto, una linea, una polilinea, ecc.) inizia con il codice 0
    Poi rigo per rigo vengono specificate le altre caratteristiche dell'entità da disegnare (8 per il layer, 10,20,30 per le coordinate x,y,z del punto o per il primo punto di un segmento - 11,21,31 per le coordinate del punto finale come già puntualizzata da afazio).
    Nel caso del codice 8 il nome del layer che comparirà nel rigo successivo deve essere preventivamente dichiarato nell'apposita "LAYER TABLE" che è contenuta nell'HEADER.

    Criterio simile hanno i retini e le quote. Sono entità di disegno contenute nella sezione ENTITIES, ma 'richiamano' modelli e specifiche che devono essere contenute nell'HEADER.
    E' questo uno dei motivi per cui buona parte delle uscite in dxf dei nostri programmi strutturali hanno le quote fatte a lineette, e non hanno mai alcun retino.
     
    Top
    .
  8.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    CITAZIONE (zax2013 @ 24/8/2014, 10:30) 
    Afazio, ti confermo che il codice "8" indica che nel rigo successivo Autocad legge il nome del layer a cui l'entità appartiene.

    In pratica il codice "8" è presente per tutte le entità di disegno (linee, punti, cerchi, testi, ecc.) che compongono il disegno.

    Dovrebbero esserci anche altri codici, come quello per il colore, il tipo di linea (per linee e polilinee), e nelle versioni più recenti di Autocad anche per lo spessore delle linee, ed altre cose, che comunque possono essere 'ricomprese' con la sola indicazione del layer, e che se non diversamente specificate vengono prelevate dal default del layer stesso.

    In ogni caso, il file dxf è un file di testo puro. Con una formattazione specifica, che nel corso delle versioni si è via via lievemente incasinata. La versione R12 a cui tu faresti riferimento, a parte che fa da specchietto delle allodole per la tua età, è effettivamente abbastanza semplice da manipolare.

    Come tutti i file di questo genere, il formato prevede un "header", ossia una intestazione con una serie di informazioni di sistema, suddivisa in sezioni, ed infine la sezione realmente importante che è quella denominata "ENTITIES" che contiene proprio tutte le entità di disegno che verranno visualizzate a video.

    All'interno della sezione "ENTITIES" ogni singolo 'pezzo' di disegno (un punto, una linea, una polilinea, ecc.) inizia con il codice 0
    Poi rigo per rigo vengono specificate le altre caratteristiche dell'entità da disegnare (8 per il layer, 10,20,30 per le coordinate x,y,z del punto o per il primo punto di un segmento - 11,21,31 per le coordinate del punto finale come già puntualizzata da afazio).
    Nel caso del codice 8 il nome del layer che comparirà nel rigo successivo deve essere preventivamente dichiarato nell'apposita "LAYER TABLE" che è contenuta nell'HEADER.

    Criterio simile hanno i retini e le quote. Sono entità di disegno contenute nella sezione ENTITIES, ma 'richiamano' modelli e specifiche che devono essere contenute nell'HEADER.
    E' questo uno dei motivi per cui buona parte delle uscite in dxf dei nostri programmi strutturali hanno le quote fatte a lineette, e non hanno mai alcun retino.

    Ok. Mi hai chiarito il significato del codice "8". Indica illayer dove viene posizionata l'entità.

    E' anche vero che un file dxf si compone di varie sezione, tra cui come hai detto l'intestazione, ma è ancheverso che in un file dxf di semplice fattura esso puo' Mancare. Infatti il file dxf che produrrò avrà unica sezione composta "ENTITIES" ed è appunto per questo che come bvalore del codice di gruppo "8" attribuisco il valore "0" che poi sarebbe il layer di default comunque presente in un file autocad.

    Magari poi con l'avanzare dell'età mi avventurero' anche nella scrittura di un HEADER e di un TABLES più avanzate
     
    Top
    .
  9.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    L'intervento di zax oltre a chiarirmi l'otto mi ha facilitato la successiva esposizione.

    Sappiamo quindi che un file dxf si compone di varie sezioni ed in particolare delle sezioni:

    Sezione HEADER - contiene informazioni generali sul disegno. Ogni parametro, come è in generale, si compone dal codice di gruppo e dal valore ad esso associato. I due campi si trovano su righe separate.
    La sezione Header inizia con
    "0"
    "SECTION"
    "2
    "HEADER"

    e finisce con
    "0"
    "ENDSEC"


    Sezione TABLES Questa sezione contiene la definizione dei tipi come per esempio:
    - tabella dei tipi di linea
    - tabella dei layer
    - tabella degli stili di testo
    - tabella degli stili di dimensione
    - ed altro...
    La sezione inizia con
    "0"
    "SECTION"
    "2
    "TABLES"

    e termina con
    "0"
    "ENDSEC"

    Sezione BLOCKS - Questa sezione contiene la definizione dei blocchi di disegno.

    Sezione ENTITIES - In questa sezione sono contenuti tutti gli elementi grafici del disegno inclusi i riferimenti ai blocchi presenti.
    Occorre distinguere il blocco presente nella sezione BLOCKS da quello eventualmente presente in questa sezione. Il primo fa parte di un elenco i cui elementi non necessariamente devono essere presenti nel disegno, mentre il secondo, che è un riferimento ad un elemento dell'elenco dei blocchi, sarà presente nel disegno.

    La sezione inizia con
    "0"
    "SECTION"
    "2
    "ENTITIES"

    e termina con
    "0"
    "ENDSEC"

    Sezione END OF FILE che chiude il file dxf ed è costituito dalla copia ri righe:
    "0"
    "EOF"


    Non è strettamente necessario che nel file vi siano tutte le sezioni possibili; le sezioni HEADER, TABLES, BLOCKS possono mancare, mentre non può mancare la sezione ENTITIES.

    E' chiaro che se manca la sezione BLOCKS nella sezione ENTITIES non possiamo inserire alcun riferimento a blocchi presenti nel disegno, cosi come se manca la sezione TABLES non possiamo attribuire ad una primitiva grafica (come per esempio una polilinea) un attributo di tipoLinea (come per esempio una linea tratteggiata)o uno stile particolare ad un quache elemento o un layer non definito.

    In assenza delle sezioni HEADER, TABLES, BLOCKS, autocad si limiterà a leggere solo gli elementi grafici presenti nella sezione ENTITIES e si creerà l'ambiente minimo standard ove sono presenti valori di default per gli elementi che devono essere per forza presenti; per esempio non puo' esistere un disegno autocad senza alcun layer e quindi autocad crea di suo il layer "0"

    Per poterla avere a disposizione in questo topic, riporto una tabella con i codici di gruppo ed il loro significato (fino a 1000).

    6TvtEkY
    OKN9vWA
     
    Top
    .
  10.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    Ricordando che avevo fatto disegnare le superficie 3D delle vela attraverso excel, ho pensato di estendere il formato della tabella inserendo anche la possibilita di disegnare superficie 3D a tre o quattro vertici.
    In realtà il tipo di enità è unico sia per superficie a tre che a quattro vertici, quindi in ogni caso devono essere scritte le coordinate di 4 punti (nel caso di superfici a 3 vertici, il quarto vertice si pone uguale al terzo. Per non aumentare il numero delle colonne ho quindi deciso di scrivere nelal tabella dati dxf i quattro vertici distinti su due righe diverse.

    In ogni caso la sub che scrive una superficie 3D è il seguente:

    CODICE
    Sub dxf_3DSurface(ByVal n_file As Integer, A As Integer, x1 As Double, y1 As Double, z1 As Double, _
                                                            x2 As Double, y2 As Double, z2 As Double, _
                                                            x3 As Double, y3 As Double, z3 As Double, _
                                                            x4 As Double, y4 As Double, z4 As Double)
                                                           
       Print #n_file, "0"
       Print #n_file, "3DFACE"
       
       Print #n_file, "5"
       Print #n_file, VBA.Hex(A)
       
       Print #n_file, "8"
       Print #n_file, "0"
       
       Print #n_file, "10"
       Print #n_file, Punto(x1)
       Print #n_file, "20"
       Print #n_file, Punto(y1)
       Print #n_file, "30"
       Print #n_file, Punto(z1)
       
       Print #n_file, "11"
       Print #n_file, Punto(x2)
       Print #n_file, "21"
       Print #n_file, Punto(y2)
       Print #n_file, "31"
       Print #n_file, Punto(z2)
       
       Print #n_file, "12"
       Print #n_file, Punto(x3)
       Print #n_file, "22"
       Print #n_file, Punto(y3)
       Print #n_file, "32"
       Print #n_file, Punto(z3)
       
       Print #n_file, "13"
       Print #n_file, Punto(x4)
       Print #n_file, "23"
       Print #n_file, Punto(y4)
       Print #n_file, "33"
       Print #n_file, Punto(z4)
       
    End Sub
     
    Top
    .
  11.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    Inizio a scrivere la sub che gestisce tutte le chiamate.

    In questa dovremo stabilire il nome del file quindi aprire un canale in scrittura del file.
    Poi scriveremo i dati iniziali del file dxf, a seguire ci sarà la scrittura delle varie entità previa lettura rigo per rigo dei in tabella e quindi scrivere i dati di chiusura del file dxf e chiudere il canale aperto.



    CODICE
    Sub Crea_DXF()

    Dim count As Long 'contatore delle righe della tabella dei dati
    Dim TabellaDati As Variant ' qui trasferisco la tabella dati dxf letta dal foglio
    Dim nomeProposto As String
    TabellaDati = Range("tabella")
    count = LBound(TabellaDati) ' parto dal primo rigo della tabella che contiene il nome del file proposto
    nomeProposto = TabellaDati(count, 1)

    If salvaFile(nomeProposto) Then
       Dim FileNumber As Long
       FileNumber = FreeFile

       Open nomeProposto For Output As #FileNumber ' qui si puo' verificare l'errore di file in uso
       ' qui devo gestire l'errore se il file è già in uso da autocad
       
       Call dxf_open_file(FileNumber) ' chiama la sub che scrive i dati iniziali nel file dxf
       
       ' qui devo inserire la gestione dei vari tipi di elementi grafici
       ' scorrendo la tabella dei dati dxf
       
       Call dxf_close_file(FileNumber) ' chiama la sub che scrive i dati finali nel file dxf
       Close #FileNumber ' chiudo il canale del file e dò il messaggio di creazione avvenuta
       MsgBox "Creazione dxf eseguita. Premendo ok si apre Autocad col profilo disegnato"

    Else
       ' si arriva qui solo se nel dialogo di scelta del nome del file si è premuto annulla
       MsgBox "Creazione dxf annullata"
    End If
       
    End Sub


    Per fare avviare Autocad con aperto il file dxf che abbiamo finito di scrivere occorre prima ddichiarare una funzione della libreria di sistema schell32.dll

    Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long


    e quindi all'interno della sub che gestisce le chiamate e subito dopo aver chiuso il filenumber relativo al fuile dxf creato, dare l'istruzione:

    CODICE
    ...............

       Close #FileNumber
       MsgBox "Creazione dxf eseguita. Premendo ok si apre Autocad col profilo disegnato"
       ShellExecute 0, vbNullString, nomeProposto, vbNullString, "", 1


    Questa ultima istruzione non fa altro che aprire ilf ile creato con l'applicazione che può aprire questo tipo di file. Questo significa che se il file creato non avesse l'estensione .dxf non potremmo aprire il file oppure che se nel vostro sistema avete legato al file dxf altro programma cad allora viene aperto il file col programma cad specificato nella tabella di sistema.
    Se l'estensione del file fosse .txt allora il file si aprirebbe col notepad.
    Infatti se provate a cambiare l'estensione da .dxf a .txt nella funzione SalvaFile() vedrete aprire il notepad anziché autocad

    CODICE
    Function salvaFile(ByRef NomeFile As String) As Boolean

    'Prova per vedere se si apre notepad

       Dim fd As FileDialog
       Dim Sel As String
       Set fd = Application.FileDialog(msoFileDialogSaveAs)
       With fd
           .Title = "Crea DXF"
           .InitialFileName = ThisWorkbook.Path & "\" & NomeFile
           If .Show = -1 Then
               Sel = .SelectedItems(1)
               NomeFile = VBA.Mid(Sel, 1, Len(Sel) - 5) + ".txt"
               salvaFile = True
           Else
               salvaFile = False
           End If
       End With
       Set fd = Nothing
    End Function
     
    Top
    .
  12.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    Vediamo adesso la parte di codice che gestisce le entita e le raltive chiamata.

    Qui dovremo scorrere la tabella rigo dopo rigo fino al raggiungimento dell'ultimo rigo della tabella dati. In seguito pero' vi proporrò una sorprendente variante.

    Per questo sfrutto un loop While utilizzando come variabile di controllo il contatore Count che ho gia dimensionato.
    Il loop sarà eseguito finchè il contatore delle righe è minore o uguale al numero totale delle righe contenute in tabella.

    Ecco la struttura

    CODICE
    puntatore = 100 'inizializzo l'ID delle entità da inserire nel code 5
       count = count + 1 ' parto dal secondo rigo dato che il primo contiene il nome del file
       While count <= UBound(TabellaDati)
       oggetto = TabellaDati(count, 1) ' leggo il tipo di oggetto da disegnare
       Select Case oggetto
               Case "Punto"
                   XX = TabellaDati(count, 3)
                   YY = TabellaDati(count, 4)
                   ZZ = TabellaDati(count, 5)
                   Call dxf_Point(FileNumber, puntatore, XX, YY, ZZ)
                   puntatore = puntatore + 1
                   count = count + 1
                   
               Case "Linea"

                   
               Case "Cerchio"

                   
               Case "Arco"

               
               Case "Testo"

               
               Case "Polilinea"

                   
               Case "Superficie3D"

               Case Else
                   count = count + 1
           End Select
       Wend


    Qui vediamo delle nuove variabili (che devono pertanto essere dimensionate a monte:

    - puntatore - è la variabile che mi stabilisce l'ID dell'entità. Ho assunto il suo valore iniziale pari a 100.
    Questo si deve incrementare ogni qualvolta che viene scritta una qualsiasi entità nel file dxf.

    - oggetto - è la variabile che contiene il dato letto dalla prima colonna della tabella dati e cioè il tipo di entita a cui si riferisce il rigo.

    - XX, YY, ZZ - tre variabili atte a contenere le coordinate x,y,z lette dalle colonne 3, 4 e 5 della tabella dati

    Notate che dopo la chiamata Call dxf_Point(FileNumber, puntatore, XX, YY, ZZ) è necessario incrementare di 1 sia il puntatore (ID dell'entità) e sia il contatore count (rigo dove leggere i nuovi dati).

    Altra cosa da segnalare è il fatto che se la variabile oggetto non contiene una delle entità che abbiamo deciso di far disegnare, il codice non si blocca ma va semplicemente avanti considerando il rigo successivo.

    I casi relativi al segmento, al cerchio, all'arco di cerchio ed al testo sono abbastanza semplici, occorre solo dimensionare altre variabili.

    CODICE
    Case "Linea"
                   XX = TabellaDati(count, 3)
                   YY = TabellaDati(count, 4)
                   ZZ = TabellaDati(count, 5)
                   XX1 = TabellaDati(count, 6)
                   YY1 = TabellaDati(count, 7)
                   ZZ1 = TabellaDati(count, 8)
                   Call dxf_line(FileNumber, puntatore, XX, YY, ZZ, XX1, YY1, ZZ1)
                   puntatore = puntatore + 1
                   count = count + 1
                   
               Case "Cerchio"
                   XX = TabellaDati(count, 3)
                   YY = TabellaDati(count, 4)
                   ZZ = TabellaDati(count, 5)
                   raggio = TabellaDati(count, 6)

                   Call dxf_circle(FileNumber, puntatore, XX, YY, ZZ, raggio)
                   puntatore = puntatore + 1
                   count = count + 1
                   
               Case "Arco"
                   XX = TabellaDati(count, 3)
                   YY = TabellaDati(count, 4)
                   ZZ = TabellaDati(count, 5)
                   raggio = TabellaDati(count, 6)
                   a1 = TabellaDati(count, 7)
                   a2 = TabellaDati(count, 8)
                   Call dxf_Arc(FileNumber, puntatore, XX, YY, ZZ, raggio, a1, a2)
                   puntatore = puntatore + 1
                   count = count + 1
               
               Case "Testo"
                   Testo = TabellaDati(count, 2)
                   XX = TabellaDati(count, 3)
                   YY = TabellaDati(count, 4)
                   ZZ = TabellaDati(count, 5)
                   altezzaT = TabellaDati(count, 6)
                   a1 = TabellaDati(count, 7)
                   Call dxf_Text(FileNumber, puntatore, XX, YY, ZZ, altezzaT, a1, Testo)
                   puntatore = puntatore + 1
                   count = count + 1


    Ecco infine il caso della polilinea edl caso della superficie 3D.

    CODICE
    Case "Polilinea"
                   NVertici = TabellaDati(count, 2)
                   count = count + 1
                   Call dxf_open_poly(FileNumber, puntatore)
                   puntatore = puntatore + 1
                   For i = 1 To NVertici
                       XX = TabellaDati(count, 3)
                       YY = TabellaDati(count, 4)
                       ZZ = TabellaDati(count, 5)
                       KK = TabellaDati(count, 6)
                       Call dxf_vertex(FileNumber, puntatore, XX, YY, ZZ, KK)
                       puntatore = puntatore + 1
                       count = count + 1
                   Next
                   Call dxf_close_poly(FileNumber, puntatore)
                   puntatore = puntatore + 1
                   
               Case "Superficie3D"
                   NVertici = TabellaDati(count, 2)
                   XX = TabellaDati(count, 3)
                   YY = TabellaDati(count, 4)
                   ZZ = TabellaDati(count, 5)

                   XX1 = TabellaDati(count, 6)
                   YY1 = TabellaDati(count, 7)
                   ZZ1 = TabellaDati(count, 8)
                   
                   count = count + 1
                   XX2 = TabellaDati(count, 3)
                   YY2 = TabellaDati(count, 4)
                   ZZ2 = TabellaDati(count, 5)
                   If NVertici = 3 Then
                       XX3 = XX2
                       YY3 = YY2
                       ZZ3 = ZZ2
                   Else
                       XX3 = TabellaDati(count, 6)
                       YY3 = TabellaDati(count, 7)
                       ZZ3 = TabellaDati(count, 8)
                   End If
                   Call dxf_3DSurface(FileNumber, puntatore, XX, YY, ZZ, XX1, YY1, ZZ1, XX2, YY2, ZZ2, XX3, YY3, ZZ3)
                   puntatore = puntatore + 1
                   count = count + 1


    Naturalmente le nuove variabili presenti devono essere definite a monte della sub.

    Notate che nal caso della polilinea faccio prima leggere il numero dei vertici che la compongono e quindi istituisco in ciclo for che legge solo le colonne delle coordinate saltando quindi la lettura della prima colonna.

    Nel caso di superficie 3d dopo aver letto il numero dei vertici (che puo' essere 3 o 4) faccio leggere i dati du due righe consecutive e ponendo le coordinate del quarto vertice uguali a quelle del terzo nel caso in cui il numero dei vertici è 3.
     
    Top
    .
  13.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    Eccco la prima sorpresa nella struttura della tabella.

    Mettere la parola FINE

    Chi mi obbliga a scorrere l'intera tabella? E se volessi terminare la lettura dei dati in tabella in qualsiasi punto?
    Basta mettere la parola "FINE" all'inizio dell'ultimo rigo da leggere e fare uscire dal ciclo While il codice saltando alla chiusura del file dxf ed alla sua visualizzazione.

    ecco quindi la struttura della tabella dei dati

    oyl6bKp

    mentre il codice relativo alla parola "FINE" è il seguente:

    CODICE
    Case "FINE"
                   count = UBound(TabellaDati) + 1


    che non fa alro che porre il count (variabile di controllo del loop While) al numero di righe presenti in tabella + 1. In questo modo il codice esce dal loop e prosegue con le istruzioni di chiusura e visualizzazione del file.

    Qualcuno penserà:
    "Ottimo, ma che scemata è mai questa? Che senso ha formare una tabella con mille righe se poi ne vogliamo utilizzare 10 mettendo la parla FINE all'inizio del decimo rigo? E che senso ha dare in pasto alla sub una tabella con 1000*8= 8000 dati di tipo variant quando che in realtà ne saranno utilizzati appena 10*8=80 ?".
     
    Top
    .
  14.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    Intanto potete scaricare la prima l'ultima versione funzionante di questo progetto.

    Progetto Consolle DXF v 0.52.n

    In questo file c'e' la "forma" con le specifiche relative alla tabella dati ed una tabella di prova in cui ho messo insieme le coordinate di un profilo Omega uno diritto ed uno specchiato, un paio di segmenti qualche cerchio, un arco, un testo, un punto ed infine ho inserito una di quella forma a vela che avevao disegnato ai tempi delle tensostrutture.

    Provate a vedere se funziona anche da voi.

    Poi potrete anche notare accanto alla tabella delle specifiche una serie di paroline che rappresentano il valore che intendo aggiungere alle procedure di creazione di un file dxf.
    Tutto sommato il codice fin qui presentato è banale e anche in forme diverse può essere trovato in rete (non credo per l'uso con excel), e pertanto benchè scritte dal sottoscritto fin dalle prime versioni del sagomario (se ne trova traccia il questo topic del 2007 Sagomario e DXF ) non hanno nulla di originale.

    Quel che intendo aggiungere sono le operazioni sulle entità presenti in tabella come per esempio il mirror, le traslazioni le rotazione la scala, la deformazione.

    Edited by afazio - 28/10/2015, 10:41
     
    Top
    .
  15.     +1   -1
     
    .
    Avatar

    Advanced Member

    Group
    Administrator
    Posts
    8,163
    Reputation
    +294

    Status
    Offline
    Non ho ancora scritto nulla in proposito alle operazioni, sono solo delle idee che da qualche giorno mi frullano in testa.
    Cerco di spiegarmi con un esempio.

    considerate la seguente tabella

    HBcaUnI

    Ad un certo punto il codice leggerà la parola "Trasla". Ed allora si dovrà creare lo stesso elemento indicato dalla cella Nrigo, ma traslato delle quantità indicate Δx, Δy, Δz.
    Stessa cosa se trova una qualsiasi altra delle parole chiavi che ho specificato.
    In pratica l'operazione indicata agirà riproducendo l'entità della qualei sono già presenti i dati in tabella ma eseguendo l'operazione specificata nella prima colonna. I dati da "operare" saranno trovati nel rigo indicato in seconda colonna (NRigo).

    Perchè tutto questo?
    Questo nasce dal fatto che lo scopo per cui ho voluto rivedere le funzioni sono quelle del disegno di profili variamente accoppiati e l'accoppiamento di un profilo con se stesso altro non è che una simmetria. Perchè quindi riscrivere i dati che ho già? Perche scervellarsi sul foglio a comporre altra tabella di coordinate in cui varia solo l'orientamento e la posizione del profilo che già ho?

    Ed a questo punto ho pensato, ma se aggiungo la possibilità di specchiare perchè non aggiungere tutte le altre possibilità "possibili"? Potrebbero tornare utili per una qualche applicazione che prevede il disegno di entità traslate, ruotate, rototraslate o scalate.

    Edited by afazio - 24/8/2014, 19:03
     
    Top
    .
153 replies since 23/8/2014, 14:58   15955 views
  Share  
.