#  caras7_1

from Tkinter import *
#from Numeric import *
from math import *
from numpy import *
import pickle


archivo = open("mouse_e.txt", "r")
e=pickle.load(archivo)
archivo.close()
archivo = open("mouse_v.txt", "r")
vert=pickle.load(archivo)
archivo.close()
archivo = open("mouse_f.txt", "r")
f=pickle.load(archivo)
archivo.close()


#ne=12 #numero de bordes
#nv=8 #numero d evertices
#nf=6 #numero de caras

ne=len(e)
nv=len(vert)
nf=len(f)

print "bordes",ne,"vertices",nv,"caras",nf
print "e",e
print
print "vert",vert
print
print "f",f

# defino variables globales
w_max=500.0 # ancho de ventana
h_max=500.0 # alto de ventana
w_min=0.0
h_min=0.0
x_min=-100.0    # rango de las xdefdef
x_max=100.0
y_min=-100.0    #rango de las y
y_max=100.0
t=zeros([4,4], float)

#defino variables iniciales
#estilo="perspectiva"
estilo="paralelo"
#forma_disp="visible" 
forma_disp="alambre"
d=-100.0    #distancia del observador al plano de proyeccion
dw=-100.0   #distancia del plano de proyeccion al origen de coordenadas
pi=3.14159
tx=0.0
ty=0.0
tz=0.0
roll=0.0
pitch=0.0
yaw=0.0

flag=0      # bandera de entrada a los vertices
pp=0
puntos=[]
# esto es la tabla de las caras
# cada una tiene el numero de un borde que la compone

#f=zeros([nf,8],Int) # inicializo la matriz f, en los subindices 1 a 3 voy a poner el numero de los vertices para calcular el vector normal
# el 4 no se usa
# del 5 al 7 pongo las componentes del vector perpendicular
#f[0][0]=0
#f[1][0]=4
#f[2][0]=9
#f[3][0]=10
#f[4][0]=11
#f[5][0]=8

#f.resize([5])
#f[4]=5

# el subindice indica el nro de vertice y los subindice
# 0,x   1,y   2,z
# aca los cargo por fila
#vert=zeros([nv,4],Float)
vert1=zeros([nv,4],float)   #defino un vector para llenar con los puntos rotados

#defino como estan formados lo bordes
# 0 inicio 1 fin
#e=zeros([ne,8], Int)
#
# primer subindice, es el numero de borde
# segundo subindice
#   0-vertice de inicio
#   1-vertice de fin
#   2-cara de la izquierda
#   3-cara de la derecha
#   4-borde anterior recorriendo cara izq en sentido reloj
#   5-borde siguiente recorriendo cara izq en sentido reloj
#   6-borde anterior recorriendo cara derecha en sentido reloj
#   7-borde siguiente recorriendo cara derecha en sentido reloj

# esto de aca abajo lo hago para ver como estan los datos
#for i in range(ne):
#   dum=[i]
#   for j in range(8):
#       dum.append(e[i][j]) 
#   print dum




def search_edge(xe,xf):
    # esta es una busqueda recursiva de los vertices que componen un lado
    # xe es el borde
    # xf es la cara
    global e
    global pp   # es la variable de entorno que guarda el borde con la que estoy llamando inicialmente
    global flag #bandera para diferenciar la primera vez que encuentro la cara
    global puntos   # lista de entorno para guardar los puntos de la cara
    print "----"," borde ",xe,"cara ",xf,"flag",flag,"borde llamad",pp
    if (xe==pp and flag >0): # or flag>2:
#       print "retorno", flag
        return
    else:   
        flag=flag+1
        if e[xe][2]==xf:
            e_next=e[xe][5]
            f_next=e[xe][2]
            puntos.append(e[xe][1]) # guardo el punto final del borde
        elif e[xe][3]==xf:
            e_next=e[xe][7]
            f_next=e[xe][3]
            puntos.append(e[xe][0]) # guardo el punto final del borde
        else:
            e_next=99
            f_next=98
        print " prox vert",e_next,"prox cara",f_next
        search_edge(e_next,f_next)
    
# transforma x del dominio x_min x_max
# al dominio w_min w_max (eje horizontal)
# al poner por ejemplo x_min=x_min estoy usando variable global para pasar
# como argumento
def escala_x(x,x_min=x_min,x_max=x_max,w_min=w_min,w_max=w_max):
    if x < x_max and x > x_min:
        d = (x-x_min)/(x_max-x_min) *(w_max-w_min)+w_min
        #print d
        return d
    else:
        return -1

# transforma y del dominio y_min y_max
# al dominio h_min h_max
def escala_y(y,y_min=y_min,y_max=y_max,h_min=h_min,h_max=h_max):
    if y < y_max and y > y_min:
        d = h_max-((y-y_min)/(y_max-y_min) *(h_max-h_min)+h_min)
        #print d
        return d
    else:
        return -1
    
#rutina de rotacion
def matriz_rot(roll,pitch,yaw,tx,ty,tz):
    
    t[0][0]=cos(yaw)*cos(roll)+sin(yaw)*sin(pitch)*sin(roll)
    t[0][1]=cos(pitch)*sin(roll)
    t[0][2]=-sin(yaw)*cos(roll)+cos(yaw)*sin(pitch)*sin(roll)
    #t[0][3]=-(tx*t[0][0]+ty*t[0][1]+tz*t[0][2])
    t[0][3]=-tx
    t[1][0]=-cos(yaw)*sin(roll)+sin(yaw)*sin(pitch)*cos(roll)
    t[1][1]=cos(pitch)*cos(roll)
    t[1][2]=sin(yaw)*sin(roll)+cos(yaw)*sin(pitch)*cos(roll)
    #t[1][3]=-(tx*t[1][0]+ty*t[1][1]+tz*t[1][2])
    t[1][3]=-ty
    t[2][0]=sin(yaw)*cos(pitch)
    t[2][1]=-sin(pitch)
    t[2][2]=cos(yaw)*cos(pitch)
    #t[2][3]=-(tx*t[2][0]+ty*t[2][1]+tz*t[2][2])
    t[2][3]=-tz
    t[3][0]=0
    t[3][1]=0
    t[3][2]=0
    t[3][3]=1
    return

#rutina de dibujo
def dibujo():
    i=0
    matriz_rot(roll,pitch,yaw,tx,ty,tz)
    b.delete(ALL)
    for i in range(nv):
        #print i
        vert1[i][0]=vert[i][0]*t[0][0]+vert[i][1]*t[0][1]+vert[i][2]*t[0][2]+vert[i][3]*t[0][3]
        vert1[i][1]=vert[i][0]*t[1][0]+vert[i][1]*t[1][1]+vert[i][2]*t[1][2]+vert[i][3]*t[1][3]
        vert1[i][2]=vert[i][0]*t[2][0]+vert[i][1]*t[2][1]+vert[i][2]*t[2][2]+vert[i][3]*t[2][3]
        vert1[i][3]=vert[i][0]*t[3][0]+vert[i][1]*t[3][1]+vert[i][2]*t[3][2]+vert[i][3]*t[3][3]
    for j in range(nf): #nf
        #print
        
        color="black"
        if j==0:
            color="navy"
        elif j==1:
            color="red"
        elif j==2:
            color="green"
        elif j==3:
            color="blue"
        elif j==4:
            color="yellow"
        elif j==5:
            color="cyan"
        elif j==6:
            color="grey"
        elif j==7:
            color="gold"
        elif j==8:
            color="pink"
        elif j==9:
            color="coral"
        elif j==10:
            color="cyan"    
        else:
            color="black"
        # armos cuatro lista para guardar las ccordenadas a dibujar por el pligono
        l=[]
        #ly=[]
        lv=[]
        for i in range(len(supunt[j])):
                        
            if estilo=="perspectiva":
                #print "perspectiva" 
                coefini=d+dw-vert1[supunt[j][i]][2] # coordenada z del vertice de inic del lado i
                coeffin=d+dw-vert1[supunt[j][i]][2]  # coordenada z del vertice de fin del lado i
                
                l.append(escala_x(d*vert1[supunt[j][i]][0]/coefini))
                l.append(escala_y(d*vert1[supunt[j][i]][1]/coefini))
                lv.append(f[j][i])
            else:   
                #print "paralelo"   
                l.append(escala_x(vert1[supunt[j][i]][0]))# coord x del vertice de inicdel lado i
                l.append(escala_y(vert1[supunt[j][i]][1]))# coord y del vertice de inicdel lado i
                lv.append(supunt[j][i]) 
        #print j,estilo,lv
        vect_normal(j)
        v=[0,0,1] # vector de vision
        #print " prod escal",prod_escalar(v,vect_normal(j)),"+++++"
        print "cara",nf,l
        if forma_disp=="visible":
            if prod_escalar(v,vect_normal(j))<=0 :
                b.create_polygon(l,fill=color,outline="black",width=1)

        elif forma_disp=="alambre":
            b.create_polygon(l,fill="",outline="black",width=1)

def per_rec():
    global estilo
    if estilo=="perspectiva": 
        estilo="paralelo"
    else:
        estilo="perspectiva"        
    dibujo()

def vis_alam():
    global forma_disp
    if forma_disp=="visible": 
        forma_disp="alambre"
    else:
        forma_disp="visible"
    print estilo        
    dibujo()

def regla_tx(x):
    global tx
    tx = float(x)
    print " Tx" ,tx
    dibujo()

def regla_ty(x):
    global ty
    ty = float(x)
    print " Ty" ,ty
    dibujo()

def regla_tz(x):
    global tz
    tz = float(x)
    print " Tz" ,tz
    dibujo()

def regla_pitch(x):
    global pitch
    pitch = float(x)
    print " Pitch" ,pitch
    dibujo()

def regla_roll(x):
    global roll
    roll = float(x)
    print " Roll" ,roll
    dibujo()

def regla_yaw(x):
    global yaw
    yaw = float(x)
    print " Yaw" ,yaw
    dibujo()

def prod_vectorial(a,b):    
    normal=[]
    ai=a[0]
    aj=a[1]
    ak=a[2]
    bi=b[0]
    bj=b[1]
    bk=b[2]
    normal.append(aj*bk-ak*bj)
    normal.append(-1*(ai*bk-ak*bi))
    normal.append(ai*bj-aj*bi)
    #print normalx,normaly,normalz
    return normal

def prod_escalar(a,b):
    ai=a[0]
    aj=a[1]
    ak=a[2]
    bi=b[0]
    bj=b[1]
    bk=b[2]
    return ai*bi+aj*bj+ak*bk

def modulo_vector(a):
    ai=a[0]
    aj=a[1]
    ak=a[2]
    return sqrt(pow(ai,2)+pow(aj,2)+pow(ak,2))
    
def ang_vector(a,b):
    return arccos(prod_escalar(a,b)/(modulo_vector(a)*modulo_vector(b)))


def vect_normal(c):
    global vert1
    global f
    vec1=[]
    vec1.append(vert1[f[c][2]][0]-vert1[f[c][1]][0])# componente x,y z del vector  que va del punto 2 al 1
    vec1.append(vert1[f[c][2]][1]-vert1[f[c][1]][1])
    vec1.append(vert1[f[c][2]][2]-vert1[f[c][1]][2])
    mod1=modulo_vector(vec1)
    vec1[0]=vec1[0]/mod1
    vec1[1]=vec1[1]/mod1
    vec1[2]=vec1[2]/mod1
    print "vector1", vec1
    vec2=[]
    vec2.append(vert1[f[c][3]][0]-vert1[f[c][1]][0])# componente x,y z del vector  que va del punt 3 al 1
    vec2.append(vert1[f[c][3]][1]-vert1[f[c][1]][1])
    vec2.append(vert1[f[c][3]][2]-vert1[f[c][1]][2])
    mod2=modulo_vector(vec2)
    vec2[0]=vec2[0]/mod2
    vec2[1]=vec2[1]/mod2
    vec2[2]=vec2[2]/mod2
    print "vector2", vec2       
    print "normal",prod_vectorial(vec1,vec2)
    return prod_vectorial(vec1,vec2)


supunt=[]   
for j in range(nf):
#busco cara por cara que bordes la componen
# y armo una lista con cada cadena con los vertices
# 
        
    flag=0
    ppunt=f[j][0]   # guardo en ppunt el numero un borde inicial
    pp=ppunt
    puntos=[]
    search_edge(ppunt,j) #llamo la rutina con el borde ppunt de la cara j
    #print " cara",j,puntos
    print "vert------------"
    print vert
    print "e---------------"
    print e
    print "f---------------"
    print f 
    supunt.append(puntos)   

    f[j][1]=puntos[0] # guardo en la matriz de caras los puntos para calcular
    f[j][2]=puntos[1] # con el producto vectorial la normal a la cara
    f[j][3]=puntos[2]

print supunt


w = Tk()
b = Canvas(w, height=h_max, width=w_max, background="white")
b.grid(row=0,column=0,columnspan=3)

w.button = Button(w, text="QUIT", fg="red", command=w.quit)
w.button.grid(row=1,column=0)

w.button = Button(w, text="Vis/Alam", command=vis_alam)
w.button.grid(row=1,column=1)

w.button = Button(w, text="Persp", command= per_rec)
w.button.grid(row=1,column=2)

w.s=Scale(w,orient="horizontal",command=regla_tx,from_=-10.0,to=10.0,resolution=1.0)
w.s.grid(row=4,column=0)

w.s=Scale(w,orient="horizontal",command=regla_ty,from_=-10.0,to=10.0,resolution=1.0)
w.s.grid(row=4,column=1)

w.s=Scale(w,orient="horizontal",command=regla_tz,from_=-10.0,to=10.0,resolution=1.0)
w.s.grid(row=4,column=2)

w.s=Scale(w,orient="horizontal",command=regla_pitch,from_=-pi,to=pi,resolution=pi/4)
w.s.grid(row=2,column=0)
    
w.s=Scale(w,orient="horizontal",command=regla_yaw,from_=-pi,to=pi,resolution=pi/4)
w.s.grid(row=2,column=1)

w.s=Scale(w,orient="horizontal",command=regla_roll,from_=-pi,to=pi,resolution=pi/4)
w.s.grid(row=2,column=2)


w.mainloop()
        
