Grafica della tartaruga in due e in tre dimensioni


    A partire dal modulo per la grafica del prof. John M. Zelle Ph. D. Wartburg College
(graphics.py manualetto dello stesso autore graphics.pdf)
è possibile ampliare le capacità grafiche alla grafica della tartaruga sia nel piano che nello spazio.

    Nel modulo graftarta2.py si definisce una classe Graf che discende dalla classe GraphWin del modulo graphics.py e che quindi gode di tutti i metodi definiti per quest'ultima e che si possono ritrovare nel manualetto graphics.pdf .

    Per utilizzare la classe Graf bisogna innanzitutto importarla:
from graftarta2 import Graf
Sarà allora possibile ottenere una istanza della classe scrivendo ad esempio:
t=Graf("nome", 600,400)
Si ottiene una finestra grafica con il titolo "nome" e di dimensioni 600X400 pixels su cui poter eseguire i grafici che interessano.

    Le coordinate cartesiane di questa finestra sono quelle "elettroniche" con l'origine nel vertice in alto a sinistra e l'asse y diretto verso il basso. Per ottenere un riferimento cartesiano classico con l'asse y diretto verso "l'alto", si può utilizzare il metodo "coordinate" della classe Graf:
t.coordinate(-50,-40,50,40)
in questo modo si avrà un riferimento cartesiano con le x che variano da -50 a +50 e le y da -40 a +40 con gli assi orientati come solitamente si fa nella didattica della matematica e della fisica.
t.coordinate(-50,-40,50,40,True)
    E' possibile ottenere il disegno degli assi e delle tacche di numerazione semplicemente aggiungendo True:

Nel linguaggio Python è possibile infatti scrivere delle funzioni che abbiano un numero variabile di parametri con la condizione che i parametri facoltativi seguano quelli obbligatori e che i parametri facoltativi abbiano comunque un valore anche quando non li si richiami nella esecuzione. Ecco la prima riga della definizione del metodo:
def coordinate(self, xi,yi,xs,ys,assi=False)
self sta ad indicare l'istanza della classe, poi abbiamo xinferiore, yinferiore, xsuperiore, ysuperiore (vertici in basso a sinistra e in alto a destra della finestra), il valore automaticamente assegnato ad assi è False. Se invece si aggiunge True come nell'esempio precedente, la stessa funzione esegue il disegno degli assi.

assi cartesiani

Volendo adesso eseguire il grafico di una funzione continua si può utilizzare il metodo della classe Graf chiamato grafico:

def grafico(self,f,xi,xs,passo=0.5):
            """grafico di f fra xinf e xsup"""

Una volta definita la funzione f, considerando l'istanza t di Graf, come sopra, si può eseguire il grafico con:

t.grafico(f,xi,xs)

Se si vuole disegnare un punto, si può ricorrere ad un metodo ereditato dalla classe GraphWin chiamato plot:

t.plot(x,y,"red")

Il riferimento cartesiano è quello stabilito dal metodo coordinate illustrato sopra.
Se si vuole disegnare un segmento, si può fare ricorso all'oggetto grafico Line(Point1,Point2) facente parte come GraphWin del modulo graphics.py del prof. John M. Zelle. Per usare gli oggetti grafici di tale modulo si deve scrivere:

from graphics import *

cioè importa tutte le classi definite in graphics
Per disegnare il segmanto si può scrivere:

linea=Line(Point(x1,y1), Point(x2,y2))
linea.draw(t)

nella seconda riga, t è l'istanza della classe  Graf come definito prima.
 




Grafica della tartaruga

Accanto alla tradizionale grafica cartesiana, si è ultimamente aggiunta una nuova forma di grafica: la "grafica della tartaruga". Con questo termine ci si riferisce ai grafici ottenuti utilizzando un automa (detto tartaruga) che può essere un vero robot che disegna sul pavimento o più modestamente un triangolino sullo schermo che obbedisce ad un repertorio di primitive per disegnare sullo schermo. Sostanzialmente delle primitive di traslazione che lasciano una scia colorata sullo schermo (avanti (dist), assegnaPosizione  asPos(x,y)) o delle primitive di rotazione (destra (ang), assegna direzione asDir(ang) ) che cambiano la direzione verso cui "punta" la tartaruga la sua orientazione.

Per realizzare dei programmi significativi si deve porre grande attenzione allo stato della tartaruga (sostanzialmente posizione e direzione).

La grafica della tartaruga è un modo divertente per esplorare la matematica, l'informatica, ma anche per costruire piccole simulazioni in fisica ed anche in altre scienze. L'automa tartaruga è stato inventato da S. Papert ed è stato utilizzato praticamente in tutto il mondo nella didattica a tutti i livelli da quelli più elementari fino a quelli universitari.

Un libro che ha segnato una tappa fondamentale è l'interessantissimo:

"La geometria della tartaruga" di H. Abelson e A. Di Sessa ed. Muzzio

Ricchi di suggerimenti ed idee didatticamente valide sono i due volumi:

"Fisica e Informatica" di M.V. Cecchet e P. Peranzoni ed. Cedam

Esempio:

from graftarta2 import Graf
t=Graf("prova", 500, 300)
t.coordinate(-250,-180,250,180)
def quadrato(lato):
    for k in range(4):
        t.avanti(lato)
        t.destra(90)
quadrato(100)
quadrato(50)

  Si importa il modulo graftarta2 e si scrive la funzione che definisce il quadrato dando come parametro formale il lato. Dopo i due punti, rientro e inizia un ciclo di ripetizioni for con ulteriore rientro. Range(4) origina una lista ordinata di naturali da 0 a 3. In altre parole ripeti quattro volte avanti(lato) e sinistra(90). Da notare che t.destra(90) inizia con la stessa colonna di  t.avanti(lato).
    Per eseguire il programma dalla IDLE si può utilizzare il menù RUN e poi RUN MODULE


Per disegnare poligoni regolari e "stelle" con i lati intrecciati

def poli(lato, angolo):
    t.avanti(lato)
    t.destra(angolo)
    somma = angolo
    while somma % 360 != 0:
        t.avanti(lato)
        t.destra(angolo)
        somma = somma+angolo

  La variabile somma serve a memorizzare l'angolo totale di cui ruota la tartaruga. Se questa somma di angoli forma un angolo di 360 (o un suo multiplo intero) il poligono è completo. Per verificare ciò si utilizza il modulo 360 ovvero il resto nella divisione intera per 360 (nel Python si indica con %). Se il modulo somma % 360 è diverso da zero si manda avanti la tartaruga e la si fa girare ogni volta di un certo angolo. Se questo modulo è zero il ciclo while si interrompe.

   Si possono eseguire i grafici dei poligoni eseguendo tale funzione con valori diversi dell'angolo che in realtà è l'angolo esterno del poligono. Ad esempio poli(lato,72) esegue un pentagono. Poli(lato,144) la stella a cinque punte.
 

stella a cinque punte

stella a 10 punte

poligoni regolari

Un esempio di quadrato ricorsivo:

def quaric(lato):
    if lato > 4:
        for n in range(4):
            t.avanti(lato)
            quaric(lato/2)
            t.destra(90)

quadrato ricorsivo


Un esempio di spirali equiangole:

def spirale(lato, angolo, passo=4):
    while lato < 600:
        t.avanti(lato)
        t.destra(angolo)
        lato = lato + passo

spirale

spirale



    E' possibile utilizzare l'automa tartaruga per delle piccole simulazioni di Fisica.

I rimbalzi di una palla sono un buon esempio di questo tipo di simulazioni.
E' naturale eseguire il grafico delle energie che intervengono nella simulazione per mettere in evidenza la diminuizione dell' energia totale ad ogni rimbalzo:

grafico energie

rimbalzi

Ecco il listato del programma


Grafica nelle tre dimensioni


    Seguendo la linea descritta da Abelson e Di Sessa ne "La Geometria della tartaruga" ed. Muzzio è possibile  dotare la tartaruga delle primitive per farla muovere nello spazio a tre dimensioni.

    dodecagono
Dodecagono (dodici facce che sono pentagoni regolari uguali) disegnato con la grafica della tartaruga.

Primitive per la tartaruga spaziale

Per la rotazione nel piano sono sufficienti i soli comandi Destra(Angolo) e Sinistra(Angolo); nello spazio la situazione diventa molto più complessa. Si può immaginare la tartaruga spaziale associata ad una terna sinistrorsa di versori mutuamente perpendicolari: basta pensare al dito medio, indice e pollice della mano sinistra. Adesso per definire le rotazioni si immagina di lasciare invariato uno solo di questi versori alla volta e di far ruotare gli altri due in un piano perpendicolare a quello rimasto fisso. Per dare un nome a queste rotazioni si può far ricorso a tre termini aeronautici:

terna cartesiana in 3 dimensioni

Beccheggia(angolo)
E’ il movimento che consiste nel tenere fisso il pollice e nel ruotare le altre due dita, per analogia al movimento delle le galline quando beccano. Analogamente con il comando Imbarda(angolo)
resta fisso l'indice e ruotano le altre due dita, mentre con
Rolla
(angolo)
resta fisso il medio e ruotano le altre due dita.

Dopo aver così stabilito le tre primitive per le rotazioni nello spazio,  si stabilisce che la traslazione della tartaruga si realizzi nella direzione individuata dal dito medio con il comando avanti3d (per distinguersi da Avanti valido nel piano). Con il corredo di queste quattro primitive è possibile eseguire disegni nelle tre dimensioni senza la necessità di far ricorso alle coordinate cartesiane dei punti. Questo aspetto rende la “Geometria della tartaruga” molto interessante sia dal punto di vista matematico sia didattico che informatico.

Per fare un esempio sul modo di eseguire disegni nelle tre dimensioni ecco di seguito il listato di due procedure. La prima serve a disegnare un rettangolo di dimensioni lato1 ed lato2. Questa procedura viene utilizzata dalla procedura parallelepipedo che ha come scopo quello di disegnare un parallelepipedo di dimensioni a, b, c.:

def rettangolo(lato1,lato2,t):
    for k in range(2):
        t.avanti3d(lato1)
        t.imbarda(math.pi/2)
        t.avanti3d(lato2)
        t.imbarda(math.pi/2)

disegno di un rettangolo
In rosso il rettangolo definito prima

def parallelepipedo(a,b,c):
    t.rolla(math.pi/2)
    for k in range(2):
        rettangolo(a,c,t)
        t.pennasu()
        t.avanti3d(a)
        t.pennagiu()
        t.beccheggia(-math.pi/2)

        rettangolo(b,c,t)
        t.pennasu()
        t.avanti3d(b)
        t.pennagiu()
        t.beccheggia(-math.pi/2)
    t.rolla(-math.pi/2)
 
parallelepipedo  
In rosso il parallelepipedo definito prima

L’esecuzione del rettangolo si basa sul ripetere due volte un certo insieme di istruzioni: andare avanti di lato1, imbardare di un angolo retto (dove Pi ha il significato di P greco), andare avanti di lato2, imbardare di un angolo retto. Analogamente anche la procedura parallelepipedo sfrutta la ripetizione due volte dello stesso insieme di istruzioni. Un aspetto importante delle procedure è che bisogna porre attenzione affinché lo stato della tartaruga (sostanzialmente direzione e posizione) rimanga invariato dopo l’esecuzione di ciascuna procedura. Ad esempio nella procedura rettangolo la rotazione totale dovuta a quattro volte imbarda(Pi/2), corrisponde ad un angolo giro cioè la tartaruga riassume lo stesso orientamento iniziale. Anche nella procedura parallelepipedo, alla rotazione iniziale rolla(Pi/2) corrisponde alla fine una rotazione opposta rolla(-Pi/2) che riporta lo stato della tartaruga alla situazione iniziale


due ottaedri
Due ottaedri regolari (ciascuno ha otto facce formate da triangoli equilateri uguali)

icosaedro regolare

Icosaedro regolare (20 facce formate da  triangoli equilateri uguali)

tre tetraedri
Tre tetraedri (quattro facce formate da  triangoli equilateri uguali)

tre cubi
Tre cubi

La definizione di cubo è la seguente:

def cubo(lato,t):
    for j in range(4):
        for k in range(4):
            t.avanti3d(lato)
            t.beccheggia(math.pi/2)
        t.avanti3d(lato)
        t.imbarda(math.pi/2)

E' chiaro che una volta definito in generale il cubo sarà possibile disegnare qualunque cubo al variare del lato e dello stato iniziale della tartaruga.


cubo ricorsivo
Cubo ricorsivo

Con una chiamata ricorsiva (cuboric(lato/4.0,t)) inserita nella definizione di cubo si ottiene il grafico precedente:

def cuboric(lato,t):
    if lato>0.2:
        for j in range(4):
            for k in range(4):
                t.avanti3d(lato)
                t.beccheggia(math.pi/2)
                cuboric(lato/4.0,t)
            t.avanti3d(lato)
            t.imbarda(math.pi/2)

Le definizioni per i poliedri regolari con cui sono stati eseguiti i grafici precedenti sono complesse e si trovano nel file cub2.txt

gaussiana in tre dimensioni
Il grafico in tre dimensioni di una gaussiana

Per eseguire i grafici cartesiani nelle tre dimensioni è stato definito un metodo della classe Graf chiamato disegnapunto3d(a,b,c,colore) che disegna un punto colorato sullo schermo di coordinate (a,b,c).

Le linee rosse sono state ottenute fissando la terza coordinata (la z) e facendo variare le x. Mentre le linee verdi sono state ottenute fissando la x e facendo variare la z. La y viene calcolata come funzione di due variabili x e z.

cubo con circonf


Grafica nelle due dimensioni

Metodi della classe Graf

       def coordinate(self, xi,yi,xs,ys,assi=False):
                """ stabilisce le coordinate cartesiane per la finestra grafica
                    xi yi coord. vertice in basso a sinistra
                    xs ys coord. vertice in alto a destra
                    ovvero le x nell'intervallo xinferiore, xsuperiore
                    le y nell'intervallo yinferiore ysuperiore
                    se si pone assi True, disegna gli assi e le tacche """
   
        def colorePenna(self,colore):
            self.colore_penna=colore

        def spessorePenna(self,num):
            self.spessore_penna=num

        def asPos(self,x,y):
            """ assegna alla tarta la posizione x, y """
           
        def grafico(self,f,xi,xs,passo=0.5):
            """grafico di f fra xinf e xsup"""
        
        def pennasu(self):
   
        def pennagiu(self):
           
        def nascondi_palla(self):
            
        def mostra_palla(self):
       
        def nascondi_tarta(self):
           
        def mostra_tarta(self):
          
                  
        def avanti(self,dist):
       
    
        def destra(self,angolo):
           
        def verso(self,x,y):
            """ restituisce l'angolo di cui deve girare la tarta per dirigersi
                verso il punto x, y """
           
        def asDir(self,angolo):
            """ assegna una Direzione alla tarta; asDir(verso(x,y)) """

Grafica nelle tre dimensioni

Metodi della classe Graf


         def imbarda(self,angolo):
            """S cost rotazione dell'aereo intorno al proprio asse dal basso in alto;
                destra e sinistra in un piano"""
            
         def imbardaR(self,angolo):
            """YR cost rotazione dell'aereo intorno al proprio asse dal basso in alto;
                destra e sinistra in un piano"""
           
        def beccheggia(self,angolo):
            """self.A cost oscillazioni della nave da poppa a prua"""
            
           
        def beccheggiaR(self,angolo):
            """self.ZR cost oscillazioni della nave da poppa a prua"""
            
           

        def rolla(self,angolo):
            """self.H cost oscillazioni della nave mantenendo fisso l'asse poppa prua"""
            
       def rollaR(self,angolo):
            """self.self.XR cost oscillazioni della nave mantenendo fisso l'asse poppa prua"""
       
       def avanti3d(self,dist):
   
       def disegnapunto3d(self,a,b,c, colore):
    
       def aspos3d(self,a,b,c):
        

Attributi della classe Graf    

  
      
        def __init__(self,title="Graphics Window",width=200, height=200, autoflush=False):
                """ la classe Graf discende dalla classe GraphWin del modulo
                     graphics """
       
            self.coordx=0
            self.coordy=0
            self.direz=0
            self.penna_su=False
            self.spessore_penna=1
            
            self.tarta_visibile=True
            self.palla_visibile=False
            
            self.H=V3(1,0,0)
                self.S=V3(0,1,0)
                self.A=V3(0,0,1)

                self.XR=V3(1,0,0)
                self.YR=V3(0,1,0)
                self.ZR=V3(0,0,1)

                self.P=V3(0,0,0)
                self.E=V3(0,0,0)
                self.P2d=V(0,0)

Colori scelti a caso

Utilizzando il modulo graphics (graphics.py del dott. Zelle, manualetto dello stesso autore graphics.pdf)  è possibile utilizzare una funzione chiamata color_rgb(...) che riporta il "nome" di un colore assegnati i valori di rosso, verde e blu (RGB), ciascuno variabile fra 0 e 255. Il metodo random.randint(n_iniz, n_fin) (modulo random) restituisce un intero casualmente scelto fra n_iniz ed n_fin, estremi compresi. Per semplificare la scrittura è possibile in Python una cosa prodigiosa e cioè definire un letterale e porlo uguale al nome del metodo ad esempio:

rr=random.randint

e poi utilizzarlo al posto del nome completo

nome= str(color_rgb(rr(0,255),rr(0,255),rr(0,255)))

Trovato il nome del colore scelto casualmente lo si usa con:

colorePenna(nome)

e cioè con il metodo della classe Graf colorePenna(colore)

binomiale e curva di Gauss