#  caras7_1

from Tkinter import *
from Numeric import *
from math import *

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)
	# dibuja cuadraditos de abajo a la derecha
	b.create_line(470,490,500,490,fill="red",width=1)
	b.create_line(470,490,470,500,fill="red",width=1)
	b.create_line(480,490,480,500,fill="red",width=1)
	b.create_line(490,490,490,500,fill="red",width=1)

	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)


def mouse_wheel(event):
	global pitch
	global roll	
	global yaw
	global tipo_rot

	if event.num == 5:
		if tipo_rot=="pitch":
			pitch-=.1
		if tipo_rot=="roll":
			roll-=.1
		if tipo_rot=="yaw":		
			yaw -= .1
	if event.num == 4:
		if tipo_rot=="pitch":
			pitch+=.1
		if tipo_rot=="roll":
			roll+=.1
		if tipo_rot=="yaw":		
			yaw += .1
	print tipo_rot
	dibujo()

def coordenadas(event):
	#print "clicked at", event.x, event.y
	return 

def rotacion(event):
	global tipo_rot
	if event.y > 490 and event.y<500:
		tipo_rot="nada"
		if event.x>470 and event.x<480:
			tipo_rot="pitch"
		if event.x>480 and event.x<490:
			tipo_rot="roll"
		if event.x>490 and event.x<500:
			tipo_rot="yaw"
	#print event.y, event.x	
	#print tipo_rot
	return tipo_rot


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.bind("<Button-4>", mouse_wheel)
w.bind("<Button-5>", mouse_wheel)

# esto de aqui abajo imprime en ventana de texto las coordenadas del mouse
#w.bind("<Motion>", coordenadas)
w.bind("<Motion>", rotacion)
w.mainloop()
		
