Friday, February 28, 2014

Creazione di oggetti poligonali complessi in Tkinter.

Continuando la riflessione di cui al post precedente, in cui abbiamo visto come recuperare le istruzioni fondamentali per la realizzazione di spostamenti sulla canvas (istruzione M in SVG), realizzazione di linee (istruzione L) e curve (istruzione C), siamo in grado di iniziare a tradurre le istruzioni SVG in Tkinter. Dobbiamo considerare pero' che, mentre in SVG possiamo tracciare il percorso <path> d=' nell'ambito della stessa istruzione, in Tkinter abbiamo delle primitive per la creazione di curve o figure che devono essere realizzate separatamente. Per avere un criterio unificatore, possiamo considerare l'attributo generico 'tag' dei widget, già visto in precedenza, che ci permetterà di usare più oggetti canvas simultaneamente, come fossero un solo oggetto.

E' necessario, prima di andare avanti, chiarire due aspetti. Uno riguarda la differenza tra le istruzioni SVG M, L, C e le corrispondenti minuscole. Le prime indicano riferimenti assoluti, le seconde riferimenti relativi. Nel primo caso vengono indicate le coordinate esatte, nel secondo gli spostamenti.

Altro chiarimento che vi devo riguarda il metodo usato nel post precedente per estrarre le informazioni dal path; la ricerca fatta con l'uso delle espressioni regolari avviene in tutta la stringa, prescindendo dall'ordine.

Pertanto la ricostruzione del tracciato è sicuramente affetta da errori, se non si tiene conto del punto corretto di inizio tracciato della nuova linea o curva.

Ciò detto, riprendiamo a lavorare sul file di estrazione, apportando le correzioni necessarie al codice.


#|/usr/bin/env python
import re

class SVG2Tk:

    import xml.etree.ElementTree as ET
    
    def __init__(self, file_s, file_out):

        self.file_s = open(file_s, 'r')
        self.file_out= open(file_out,'w')

        tree = SVG2Tk.ET.parse(file_s)
        root = tree.getroot()
        self.xmlrecur(root)
        self.file_out.close()
        
        file_in = open(file_out)
        self.tk_out = open('tk_out.txt','w')
        try:
            width=file_in.next()
            height=file_in.next()
            self.tk_out.write('width %sheight %s' % (width, height))
        except Exception:
            print Exception

        while True:
            
            try:
                id_ = file_in.next()
                style = file_in.next()
                d = file_in.next()
                self.tk_out.write('id,' + id_)
                while len(d)>0:
                    pattern1 = r'([M]{1}[\s]*[-\d]*[\.]?[\d]*[\,\s]?[-\d]*[\.]?[\d]*[\s]*)'
                    matchObj = re.match(pattern1, d)
                    if matchObj:
                        string = matchObj.group()
                        d=d.replace(string, "")
                        s_string = re.split(r'[;\s]*',string)
                        string = ','.join(s_string[:-1])
                        self.tk_out.write(string+'\n')
    
                    pattern2 = r'([L]{1}[\s]*[-\d]*[\.]?[\d]*[\,\s]{1}[-\d]*[\.]?[\d]*[\s]*)'
                    matchOb2 = re.match(pattern2, d)
                    if matchOb2:
                        string = matchOb2.group()
                        d=d.replace(string, "")
                        s_string = re.split(r'[;\s]*',string)
                        string = ','.join(s_string[:-1])
                        self.tk_out.write(string+'\n')

                    pattern3 = r'([C]{1}[\s]*)(([-\d]*[\.]?[\d]*[\,\s]{1}[-\d]*[\.]?[\d]*[\s]*){3})'
                    matchOb3 = re.match(pattern3, d)
                    if matchOb3:
                        string = matchOb3.group()
                        d=d.replace(string, "")
                        s_string = re.split(r'[;\s]*',string)
                        string = ','.join(s_string[:-1])
                        self.tk_out.write(string+'\n')

                    pattern4 = r'([z]{1}[\s]*)'
                    matchOb4 = re.match(pattern4, d)
                    if matchOb4:
                        string = matchOb4.group()
                        d=d.replace(string, "")
                        s_string = re.split(r'[;\s]*',string)
                        string = ','.join(s_string[:-1])
                        self.tk_out.write(string+'\n')
                        
            except Exception:
                print Exception
                self.tk_out.close()
                break
                

    def xmlrecur(self,x):
        for i in x:
            if set(['id','style','d']).issubset(i.attrib):
                    self.file_out.write(i.attrib['id'])
                    self.file_out.write('\n')
                    self.file_out.write(i.attrib['style'])
                    self.file_out.write('\n')
                    self.file_out.write(i.attrib['d'])
                    self.file_out.write('\n')
            elif set(['width','height']).issubset(i.attrib):
                self.file_out.write(i.attrib['width'])
                self.file_out.write('\n')
                self.file_out.write(i.attrib['height'])
                self.file_out.write('\n')
                
            else:
                self.xmlrecur(i)

if __name__ == '__main__':
    app = SVG2Tk('EU-Italy.svg','out_xml.txt')

Le correzioni maggiori apportate al codice del post precedente riguardano:

  1. L'uso del solo metodo 'match' delle regular expression, perchè in questo particolare contesto vogliamo che la stringa corrispondente all'attributo 'd' sia consumata man mano che si trova la corrispondenza tra il modello e la prima parte della stringa. Ogni volta che si verifica l'abbinamento, la parte iniziale corrispondente della stringa viene cancellata e la procedura viene iterata fino a consumare tutta la stringa.
  2. Il file SVG sorgente usa solo i codici path M C e L maiuscoli e z minuscolo, per cui la ricerca della lettera iniziale si limita a queste consonanti. Per inciso la lettera z rappresenta il codice di chiusura della poligonale sul punto iniziale.
  3. In questa fase, e sempre in modo temporaneo, creiamo un nuovo file di appoggio, denominato tk_out.txt, in cui scriviamo le stringhe risultanti dalla rilettura del file out_file.txt che viene generato all'inizio. Le stringhe contengono elementi separati da ';' per maggiore agio nella successiva suddivisione. Tutto questo, bene inteso, fino alla stesura finale del codice.

Ci stiamo progressivamente avvicinando al momento della traduzione. Portate pazienza ancora un po'

No comments:

Post a Comment

How to create a virtual linux machine with qemu under Debian or Ubuntu with near native graphics performance

It's been a long time since my latest post. I know, I'm lazy. But every now and then I like to publish something that other people c...