#--------------------------------------------------------------------
# funz13.py - by Claudio Fin 2008
#--------------------------------------------------------------------

import Tkinter
from random import randint
from math import sin, cos, hypot, pi,log

#--------------------------------------------------------------------
# Plottaggio funzione matematica 3D
#--------------------------------------------------------------------

class Tgrafico3d:
    def config (self,
        canvas, xorig, yorig, xwidth, zheight, minz, maxz):
        self.xorig=xorig   ; self.yorig=yorig
        self.xwidth=xwidth ; self.ywidth=int(round(xwidth/2.0))
        self.minz=minz     ; self.maxz=maxz
        self.zheight=zheight
        self.C=canvas


    def bordi_retro(self):
        self.C.create_line(self.xorig+self.ywidth-1,
            self.yorig-self.zheight+1-self.ywidth+1,
            self.xorig+self.ywidth-1,
            self.yorig-self.ywidth+1,
            fill="blue", dash=1)
        self.C.create_line(self.xorig+self.ywidth-1,
            self.yorig-self.ywidth+1,
            self.xorig+self.ywidth-1+self.xwidth-1,
            self.yorig-self.ywidth+1,
            fill="blue", dash=1)
        self.C.create_line(self.xorig,
            self.yorig,
            self.xorig+self.ywidth-1,
            self.yorig-self.ywidth+1,
            fill="blue", dash=1)


    def bordi_front(self):
        self.C.create_line(self.xorig,
            self.yorig,
            self.xorig+G.xwidth,
            self.yorig,
            fill="blue")
        self.C.create_line(self.xorig,
            self.yorig,
            self.xorig,
            self.yorig-self.zheight,
            fill="blue")
        self.C.create_line(self.xorig+self.xwidth-1,
            self.yorig,
            self.xorig+self.xwidth-1,
            self.yorig-self.zheight,
            fill="blue")
        self.C.create_line(self.xorig,
            self.yorig-self.zheight+1,
            self.xorig+self.xwidth,
            self.yorig-self.zheight+1,
            fill="blue")
        self.C.create_line(self.xorig,
            self.yorig-self.zheight+1,
            self.xorig+self.ywidth-1,
            self.yorig-self.zheight+1-self.ywidth+1,
            fill="blue")
        self.C.create_line(self.xorig+self.xwidth-1,
            self.yorig-self.zheight+1,
            self.xorig+self.ywidth-1+self.xwidth-1,
            self.yorig-self.zheight+1-self.ywidth+1,
            fill="blue")
        self.C.create_line(self.xorig+self.xwidth-1,
            self.yorig,
            self.xorig+self.ywidth-1+self.xwidth-1,
            self.yorig-self.ywidth+1,
            fill="blue")
        self.C.create_line(self.xorig+self.xwidth-1,
            self.yorig,
            self.xorig+self.ywidth-1+self.xwidth-1,
            self.yorig-self.ywidth+1,
            fill="blue")
        self.C.create_line(self.xorig+self.ywidth-1+self.xwidth-1,
            self.yorig-self.ywidth+1,
            self.xorig+self.ywidth-1+self.xwidth-1,
            self.yorig-self.ywidth+1-self.zheight+1,
            fill="blue")
        self.C.create_line(self.xorig+self.ywidth-1,
            self.yorig-self.zheight+1-self.ywidth+1,
            self.xorig+self.ywidth-1+self.xwidth-1,
            self.yorig-self.zheight+1-self.ywidth+1,
            fill="blue")


    def zmap(self,z):
        return round( z * self.kz - self.kz2 )


    def plotta(self,zarray):
        self.C.delete("all")
#        self.bordi_retro()
        
        # calcolo variabili di lavoro
        npunti=len(zarray)
        self.kz = -self.zheight / (self.maxz-self.minz)
        self.kz2 = self.minz * self.kz
        segmx = (self.xwidth - 1.0) / (npunti-1.0)
        segmy = (self.ywidth - 1.0) / (npunti-1.0)
        hsegmx = segmx/2.0

        #plottaggio grafico
        iy=npunti-1
        while iy>0:
            iym1=iy-1
            se=iym1*hsegmx
            sf=iym1*segmy
            sb=iy*segmy
            sc=iy*hsegmx
            for ix in xrange(npunti-1):
                ixp1=ix+1
                sd=ixp1*segmx
                sa=ix*segmx
                x1 = round( self.xorig + sa + sc ) 
                y1 = round( self.yorig - sb +               \
                            self.zmap(zarray[ix][iy]) )
                x2 = round( self.xorig + sd + sc )
                y2 = round( self.yorig - sb +               \
                            self.zmap(zarray[ixp1][iy]) )
                x3 = round( self.xorig + sd + se )
                y3 = round( self.yorig - sf +               \
                            self.zmap(zarray[ixp1][iym1]) )
                x4 = round( self.xorig + sa + se )
                y4 = round( self.yorig - sf +               \
                            self.zmap(zarray[ix][iym1]) )
                self.C.create_polygon(x1, y1, x2, y2,
                                      x3, y3, x4, y4,
                                      fill="black",
                                      outline="green")
            iy -= 1


#        self.bordi_front()
        

#--------------------------------------------------------------------
# Calcola la funzione matematica e la fa plottare 
#--------------------------------------------------------------------
    
def funz(x,y):
    r=hypot(x,y)+0.00000001
    return sin(r)/r

def disegna(C,amp):
    G.config(C, 10, 330, 350, 200, -1.0, 1.0)
    npunti=29
    zarray=[ [0]*npunti for i in xrange(npunti) ]

    # valori minimi e massimi assi x e y
    minx=-3*pi ; maxx=3*pi
    miny=-3*pi ; maxy=3*pi

    # calcolo punti funzione
    segmx=(maxx-minx)/(npunti-1)
    segmy=(maxy-miny)/(npunti-1)
    for ix in xrange(npunti):
        for iy in xrange(npunti):
            zarray[ix][iy]=funz(                 \
            minx + segmx*ix, miny + segmy*iy ) * \
            (amp/1000.0)
    
    G.plotta(zarray)

#--------------------------------------------------------------------
# Definisce la finestra dell'applicazione
#--------------------------------------------------------------------

class Finestra:
    def __init__ (self):
        self.form1=Tkinter.Tk()
        self.frame1=Tkinter.Frame(self.form1)
        self.canv1=Tkinter.Canvas(self.frame1)
        self.canv1.configure(width=540, height=300, bg="black")
        self.frame1.grid(row=0,column=0)
        self.canv1.grid(row=0, column=0)
        self.amp=0
        self.vel=100
        self.poll()

        
    def poll(self):
        disegna(self.canv1,self.amp)
        self.canv1.update()
        self.amp+=self.vel
        if self.amp>700 or self.amp<-700: self.vel *=-1
        self.canv1.after(20,self.poll)
       
#--------------------------------------------------------------------

G=Tgrafico3d()        #crea oggetto plottaggio grafico
F = Finestra()        #crea oggetto finestra grafica
F.form1.mainloop()    #avvia ciclo eventi finestra