import numpy as np
import tkinter as tk
import os, pickle, shelve, sys
from math import *

class cpunto3D:
    def __init__(self, x, y, z,idnumero,color):
        self.x=x                  # Coordenadas del punto en unidades de pantalla
        self.y=y              # Coordenadas del punto en unidades de pantalla 3D
        self.z=z                    # Coordenadas del punto en unidades de geometria
        self.idnumero=idnumero
        self.color=color
class cpunto2D:
    def __init__(self, x, y,color):
        self.x=x                  # Coordenadas del punto en unidades de pantalla
        self.y=y              # Coordenadas del punto en unidades de pantalla 2D
        self.color=color
        #self.idpunto=idpunto    #numero de identificacion
        
class cborde:
    def __init__(self, b, e,color,ancho):
        self.b=b                  # Coordenadas del punto en unidades de pantalla
        self.e=e              # Coordenadas del punto en unidades de pantalla 2D
        self.color=color
        self.ancho=ancho


class Lienzo(tk.Canvas):
    def __init__(self, ventana, width, height):
        self.ancho=width
        self.alto=height
        super().__init__(ventana, width=width, height=height)
        self.pack()

class Cosa:
    def __init__(self, lienzo,archivo):
        self.lienzo = lienzo

        self.vert3D=[]         #es la lista con las coordenadas en 3D de los vertices del objeto
        self.vert2D=[]           #es la lista con las coordenadas de dibujo en 2d
        self.arista=[]           # es la lista de las aristas



        self.archivo=archivo
        self.vertices=[]    # coordenadas de los vertices en posicion original
        self.verti_mov=[]       # coordenadas de los vertices movidos

        buff=[]
        
       
        f=open(self.archivo,'r')
        buff=f.readlines() 
        f.close
        #print(self.archivo,len(self.vertices),buff)
        for i in range(len(buff)):
            bb=buff[i]
    
        j=0                        
        for i in range(len(buff)):
            bb=buff[i]
            bb1=bb.find("(")
            bb2=bb.find(")")
            bb3=bb.find("{")
            bb4=bb.find("}")
        
            if bb[0]=="P":
                indice=int(bb[bb1+1:bb2])
                contenido=bb[bb3+1:bb4].split(",")
                idnumero= indice#j
                j=j+1
                
                kolor=contenido[4]
                #idnumero=int(contenido[3])
                # aca multiplico y corro para modificarlo en el desarrollo
                z= float(contenido[2])*1
                y= float(contenido[1])*1
                x= float(contenido[0])*1
                self.vertices.append(cpunto3D(x,y,z,idnumero,kolor))
                self.verti_mov.append(cpunto3D(x,y,z,idnumero,kolor))
                #print "kolor",kolor
                #print ("P",j)
            elif bb[0]=="L":     
                indice=int(bb[bb1+1:bb2])
                #print "indice ", indice, len(arista)
                contenido=bb[bb3+1:bb4].split(",")
                if archivo.split(".")[1]=="geox":
                    
                    b=int(contenido[0])
                    e=int(contenido[1])
                    colo=str(contenido[2])
                    ancho=str(contenido[3])
                    self.arista.append(cborde(b,e,colo ,ancho))
                    #print "inicio-fin",b,e
                else:
                    arista.append(cborde(int(contenido[0]),int(contenido[1]),"black",1))
            else:
                print ("otrascosa","-"+bb[0]+"-")
     

    def mueve(self,roll,pitch,yaw,tx,ty,tz):
        self.roll=roll
        self.pitch=pitch
        self.yaw=yaw
        self.tx=tx
        self.ty=ty
        self.tz=tz
        t=np.zeros((4,4))
        #print("paso",self.tx,self.ty,self.tz)
        t[0,0]=cos(self.yaw)*cos(self.roll)+sin(self.yaw)*sin(self.pitch)*sin(self.roll)
        t[0,1]=cos(self.pitch)*sin(self.roll)
        t[0,2]=-sin(self.yaw)*cos(self.roll)+cos(self.yaw)*sin(self.pitch)*sin(self.roll)
        t[0,3]=-(self.tx*t[0,0]+self.ty*t[0,1]+self.tz*t[0,2])
        t[0,3]=-self.tx
        t[1,0]=-cos(self.yaw)*sin(self.roll)+sin(self.yaw)*sin(self.pitch)*cos(self.roll)
        t[1,1]=cos(self.pitch)*cos(self.roll)
        t[1,2]=sin(self.yaw)*sin(self.roll)+cos(self.yaw)*sin(self.pitch)*cos(self.roll)
        t[1,3]=-(self.tx*t[1,0]+self.ty*t[1,1]+self.tz*t[1,2])
        t[1,3]=-self.ty
        t[2,0]=sin(self.yaw)*cos(self.pitch)
        t[2,1]=-sin(self.pitch)
        t[2,2]=cos(self.yaw)*cos(self.pitch)
        t[2,3]=-(self.tx*t[2,0]+self.ty*t[2,1]+self.tz*t[2,2])
        t[2,3]=-self.tz
        t[3,0]=0
        t[3,1]=0
        t[3,2]=0
        t[3,3]=1
        #print(t)
        for i in range(len(self.vertices)):
            self.verti_mov[i].x=self.vertices[i].x*t[0,0]+self.vertices[i].y*t[0,1]+self.vertices[i].z*t[0,2]+t[0,3]
            self.verti_mov[i].y=self.vertices[i].x*t[1,0]+self.vertices[i].y*t[1,1]+self.vertices[i].z*t[1,2]+t[1,3]
            self.verti_mov[i].z=self.vertices[i].x*t[2,0]+self.vertices[i].y*t[2,1]+self.vertices[i].z*t[2,2]+t[2,3]
        

    def escala(self,x,x1,y1,x2,y2):
        return (y1-y2)/(x1-x2)*(x-x1)+y1
    
    def dibujar(self,observador,pie,mira_hacia,distancia):
        self.observador=observador
        self.pie=pie
        self.mira_hacia=mira_hacia
        self.distancia=distancia
        v2=[]       # creo esta lista para llenar con los puntos s dibujar en 2D
        #print("llll",type(self.pie))
        for i in range(len(self.vertices)):
            v2.append(cpunto2D(0.0,0.0,"blue"))
        
        tipo_proyec="p"
        distancia=self.distancia
        p=[]

        p.append(self.observador)
        p.append(self.mira_hacia)
        #valores auxiliares
        for i in range(len(self.verti_mov)):
            #print(len(self.vertices))
            a=p[0].x-p[1].x
            b=p[0].y-p[1].y
            c=p[0].z-p[1].z
            
            modu=(sqrt(a**2+b**2+c**2))
            a=a/modu
            b=b/modu
            c=c/modu
            
            p_a=p[0].x-self.pie.x
            p_b=p[0].y-self.pie.y
            p_c=p[0].z-self.pie.z
            p_modu=(sqrt(p_a**2+p_b**2+p_c**2))
            
            p_a=p_a/p_modu
            p_b=p_b/p_modu
            p_c=p_c/p_modu
            vec_pie=np.array([p_a,p_b,p_c])
            
            alfa=p[0].x-self.verti_mov[i].x
            beta=p[0].y-self.verti_mov[i].y
            gama=p[0].z-self.verti_mov[i].z
 
            modu=(sqrt(alfa**2+beta**2+gama**2))
            alfa=alfa/modu
            beta=beta/modu
            gama=gama/modu
            
            p4x=p[0].x-distancia*a
            p4y=p[0].y-distancia*b
            p4z=p[0].z-distancia*c

    
            d=-(a*p4x+b*p4y+c*p4z)


            if tipo_proyec=="c":
                #print(i,a,alfa,b,beta,c,gama,"---",a*alfa+b*beta+c*gama)
                lam=(a*(p4x-p[0].x)+b*(p4y-p[0].y)+c*(p4z-p[0].z))/(a*alfa+b*beta+c*gama)
                p5x=p[0].x+lam*alfa
                p5y=p[0].y+lam*beta
                p5z=p[0].z+lam*gama
            else:
                lam=(a*(p4x-self.vertices[i].x)+b*(p4y-self.vertices[i].y)+c*(p4z-self.vertices[i].z))/(a*a+b*b+c*c)
                p5x=self.verti_mov[i].x+lam*a
                p5y=self.verti_mov[i].y+lam*b
                p5z=self.verti_mov[i].z+lam*c


            t=(a*(p4x-p[0].x)+b*(p4y-p[0].y)+c*(p4z-p[0].z))/(a**2+b**2+c**2)

            p3x=p[0].x+t*a
            p3y=p[0].y+t*b
            p3z=p[0].z+t*c


            vision=np.array([[a,b,c]])
            perpend=np.cross(vision,vec_pie)
            perpend2=np.cross(vision,perpend)

            M=np.zeros((4,4))
             
            # calculo el punto de insersion del nuevo sistema de coordenadas
            p3=np.array([1,p3x,p3y,p3z])
            #print("vision",vision)
            #print("pie",vec_pie)
            #print("perpend",perpend)
            #print("perpend2",perpend2)
            #print("------")
            #np.reshape(p3,[1,4])
            #M[:,0]=p3
            #M[1,1:]=vision
            #M[2,1:]=perpend
            #M[3,1:]=perpend2         
            M[:,0]=p3
            M[0,1:]=np.array([0,0,0])
            M[1,1]=vision[0,0]
            M[2,1]=vision[0,1]
            M[3,1]=vision[0,2]
            M[1,2]=perpend[0,0]
            M[2,2]=perpend[0,1]
            M[3,2]=perpend[0,2]
            M[1,3]=perpend2[0,0]
            M[2,3]=perpend2[0,1]
            M[3,3]=perpend2[0,2]
            #print(M)

            Pmat=np.array([1,     p5x,       p5y,       p5z])
 

            Q=np.dot(np.linalg.inv(M),Pmat)

            v2[i].x=round(Q[2],0)*-1 # multiplico por -1 porque la terna obtenida por los productos vectoriales 
            v2[i].y=round(Q[3],0)*-1 # me queda orientada al reves

        
        for i in range(len(self.arista)):

            # aca busco el x,y en el mundo real de una punta de la linea
            x1 = v2[self.arista[i].b].x
            y1 = v2[self.arista[i].b].y
            # aca busco el x,y en el mundo real de una punta de la linea
            x2 = v2[self.arista[i].e].x
            y2 = v2[self.arista[i].e].y
            
            # aca escalo el mundo real a la ventana
            
            colores=self.arista[i].color
            #print(i,x1,y1,x2,y2,self.lienzo.ancho)
            x1=self.escala(x1,w_w_min,0.,w_w_max,self.lienzo.ancho)
            y1=self.escala(y1,w_h_min,self.lienzo.alto,w_h_max,0.)
            x2=self.escala(x2,w_w_min,0.,w_w_max,self.lienzo.ancho)
            y2=self.escala(y2,w_h_min,self.lienzo.alto,w_h_max,0.)
            
            self.lienzo.create_line(x1, y1, x2, y2, width=2, fill=colores)
        



#################################
#CUERPO
#################################

def regla_pitch(x):
    pitch = float(x)
    canvas.delete("all")
    terna.dibujar(observador_iso,pie_iso,mira_hacia_iso,distancia_iso)
    cubo.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo.dibujar(observador_iso,pie_iso,mira_hacia_iso,distancia_iso)
    
    canvas1.delete("all")
    terna_sup.dibujar(observador_sup,pie_sup,mira_hacia_sup,distancia_sup)
    cubo_sup.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_sup.dibujar(observador_sup,pie_sup,mira_hacia_sup,distancia_sup)
    
    canvas2.delete("all")
    terna_alz.dibujar(observador_alz,pie_alz,mira_hacia_alz,distancia_alz)
    cubo_alz.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_alz.dibujar(observador_alz,pie_alz,mira_hacia_alz,distancia_alz)

    canvas3.delete("all")
    terna_lat.dibujar(observador_lat,pie_lat,mira_hacia_lat,distancia_lat)
    cubo_lat.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_lat.dibujar(observador_lat,pie_lat,mira_hacia_lat,distancia_lat)

def regla_yaw(x):
    yaw = float(x)
    canvas.delete("all")
    terna.dibujar(observador_iso,pie_iso,mira_hacia_iso,distancia_iso)
    cubo.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo.dibujar(observador_iso,pie_iso,mira_hacia_iso,distancia_iso)
    
    canvas1.delete("all")
    terna_sup.dibujar(observador_sup,pie_sup,mira_hacia_sup,distancia_sup)
    cubo_sup.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_sup.dibujar(observador_sup,pie_sup,mira_hacia_sup,distancia_sup)
    
    canvas2.delete("all")
    terna_alz.dibujar(observador_alz,pie_alz,mira_hacia_alz,distancia_alz)
    cubo_alz.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_alz.dibujar(observador_alz,pie_alz,mira_hacia_alz,distancia_alz)

    canvas3.delete("all")
    terna_lat.dibujar(observador_lat,pie_lat,mira_hacia_lat,distancia_lat)
    cubo_lat.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_lat.dibujar(observador_lat,pie_lat,mira_hacia_lat,distancia_lat)
    
def regla_roll(x):
    roll = float(x)
    canvas.delete("all")
    terna.dibujar(observador_iso,pie_iso,mira_hacia_iso,distancia_iso)
    cubo.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo.dibujar(observador_iso,pie_iso,mira_hacia_iso,distancia_iso)
    
    canvas1.delete("all")
    terna_sup.dibujar(observador_sup,pie_sup,mira_hacia_sup,distancia_sup)
    cubo_sup.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_sup.dibujar(observador_sup,pie_sup,mira_hacia_sup,distancia_sup)
    
    canvas2.delete("all")
    terna_alz.dibujar(observador_alz,pie_alz,mira_hacia_alz,distancia_alz)
    cubo_alz.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_alz.dibujar(observador_alz,pie_alz,mira_hacia_alz,distancia_alz)

    canvas3.delete("all")
    terna_lat.dibujar(observador_lat,pie_lat,mira_hacia_lat,distancia_lat)
    cubo_lat.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_lat.dibujar(observador_lat,pie_lat,mira_hacia_lat,distancia_lat)

def regla_tx(x):
    tx = float(x)
    canvas.delete("all")
    terna.dibujar(observador_iso,pie_iso,mira_hacia_iso,distancia_iso)
    cubo.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo.dibujar(observador_iso,pie_iso,mira_hacia_iso,distancia_iso)
    
    canvas1.delete("all")
    terna_sup.dibujar(observador_sup,pie_sup,mira_hacia_sup,distancia_sup)
    cubo_sup.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_sup.dibujar(observador_sup,pie_sup,mira_hacia_sup,distancia_sup)
    
    canvas2.delete("all")
    terna_alz.dibujar(observador_alz,pie_alz,mira_hacia_alz,distancia_alz)
    cubo_alz.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_alz.dibujar(observador_alz,pie_alz,mira_hacia_alz,distancia_alz)

    canvas3.delete("all")
    terna_lat.dibujar(observador_lat,pie_lat,mira_hacia_lat,distancia_lat)
    cubo_lat.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_lat.dibujar(observador_lat,pie_lat,mira_hacia_lat,distancia_lat)

def regla_ty(x):
    ty = float(x)
    canvas.delete("all")
    terna.dibujar(observador_iso,pie_iso,mira_hacia_iso,distancia_iso)
    cubo.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo.dibujar(observador_iso,pie_iso,mira_hacia_iso,distancia_iso)
    
    canvas1.delete("all")
    terna_sup.dibujar(observador_sup,pie_sup,mira_hacia_sup,distancia_sup)
    cubo_sup.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_sup.dibujar(observador_sup,pie_sup,mira_hacia_sup,distancia_sup)
    
    canvas2.delete("all")
    terna_alz.dibujar(observador_alz,pie_alz,mira_hacia_alz,distancia_alz)
    cubo_alz.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_alz.dibujar(observador_alz,pie_alz,mira_hacia_alz,distancia_alz)

    canvas3.delete("all")
    terna_lat.dibujar(observador_lat,pie_lat,mira_hacia_lat,distancia_lat)
    cubo_lat.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_lat.dibujar(observador_lat,pie_lat,mira_hacia_lat,distancia_lat)

def regla_tz(x):
    tz = float(x)
    canvas.delete("all")
    terna.dibujar(observador_iso,pie_iso,mira_hacia_iso,distancia_iso)
    cubo.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo.dibujar(observador_iso,pie_iso,mira_hacia_iso,distancia_iso)
    
    canvas1.delete("all")
    terna_sup.dibujar(observador_sup,pie_sup,mira_hacia_sup,distancia_sup)
    cubo_sup.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_sup.dibujar(observador_sup,pie_sup,mira_hacia_sup,distancia_sup)
    
    canvas2.delete("all")
    terna_alz.dibujar(observador_alz,pie_alz,mira_hacia_alz,distancia_alz)
    cubo_alz.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_alz.dibujar(observador_alz,pie_alz,mira_hacia_alz,distancia_alz)

    canvas3.delete("all")
    terna_lat.dibujar(observador_lat,pie_lat,mira_hacia_lat,distancia_lat)
    cubo_lat.mueve(roll,pitch,yaw,tx,ty,tz)
    cubo_lat.dibujar(observador_lat,pie_lat,mira_hacia_lat,distancia_lat)

def salida():
    exit()

tx=0.0
ty=0.0
tz=0.0
roll=0.0
pitch=0.0
yaw=0.0


ventana = tk.Tk()
ventana.geometry("300x300+400+800")
ventana.title("ISO")

ventana1=tk.Tk()
ventana1.geometry("300x300+100+800")
ventana1.title("SUPERIOR")

ventana2=tk.Tk()
ventana2.geometry("300x300+100+50")
ventana2.title("VERTICAL")

ventana3=tk.Tk()
ventana3.geometry("300x300+400+50")
ventana3.title("LATERAL")

ventana4=tk.Tk()
ventana4.geometry("300x300+800+50")
ventana4.title("MOVIMIENTOS")
# variables del mundo
w_w_min=-100.   
w_w_max=100.
w_h_min=-100.
w_h_max= 100.




# Crear el lienzo y pasarlo a los objetos que lo necesiten
canvas = Lienzo(ventana, width=300, height=300)
canvas1 = Lienzo(ventana1, width=300, height=300)
canvas2 = Lienzo(ventana2, width=300, height=300)
canvas3 = Lienzo(ventana3, width=300, height=300)

# Crear los objetos y pasar el lienzo y los puntos extremos

objeto="oreja_obj.geox"

cubo = Cosa(canvas,objeto)
terna= Cosa(canvas,"terna_obj.geox")

cubo_sup = Cosa(canvas1,objeto)
terna_sup= Cosa(canvas1,"terna_obj.geox")

cubo_alz = Cosa(canvas2,objeto)
terna_alz= Cosa(canvas2,"terna_obj.geox")

cubo_lat = Cosa(canvas3,objeto)
terna_lat= Cosa(canvas3,"terna_obj.geox")


# Dibujar el objeto en el lienzo
# iso
plano_obs=250
observador_iso=cpunto3D(200,200,200,0,"blue")
pie_iso=cpunto3D(200,200,0,0,"blue")
mira_hacia_iso=cpunto3D(100,100,100,0,"blue")
distancia_iso=plano_obs
#print("ISO-----------------------")
cubo.dibujar(observador_iso,pie_iso,mira_hacia_iso,distancia_iso)
terna.dibujar(observador_iso,pie_iso,mira_hacia_iso,distancia_iso)

#superior
observador_sup=cpunto3D(15,15,200,0,"blue")
pie_sup=cpunto3D(15,16,200,0,"blue")
mira_hacia_sup=cpunto3D(15,15,100,0,"blue")
distancia_sup=plano_obs
#print("SUP-----------------------")
cubo_sup.dibujar(observador_sup,pie_sup,mira_hacia_sup,distancia_sup)
terna_sup.dibujar(observador_sup,pie_sup,mira_hacia_sup,distancia_sup)

#alzada
observador_alz=cpunto3D(15,200,15,0,"blue")
pie_alz=cpunto3D(15,200,14,0,"blue")
mira_hacia_alz=cpunto3D(15,100,15,0,"blue")
distancia_alz=plano_obs
#print("VER-----------------------")
cubo_alz.dibujar(observador_alz,pie_alz,mira_hacia_alz,distancia_alz)
terna_alz.dibujar(observador_alz,pie_alz,mira_hacia_alz,distancia_alz)

#lateral
observador_lat=cpunto3D(200,15,15,0,"blue")
pie_lat=cpunto3D(200,15,14,0,"blue")
mira_hacia_lat=cpunto3D(100,15,15,0,"blue")
distancia_lat=plano_obs
#print("LAT-----------------------")
cubo_lat.dibujar(observador_lat,pie_lat,mira_hacia_lat,distancia_lat)
terna_lat.dibujar(observador_lat,pie_lat,mira_hacia_lat,distancia_lat)


lab_rot=tk.Label(ventana4,text="ROTACION")
lab_rot.grid(row=5,column=0,sticky=tk.SE)
wpitch=tk.Scale(ventana4,orient="horizontal",command=regla_pitch,from_=-pi,to=pi,resolution=pi/16,bg="green")
wpitch.grid(row=6,column=0)

wyaw=tk.Scale(ventana4,orient="horizontal",command=regla_yaw,from_=-pi,to=pi,resolution=pi/16,bg="blue")
wyaw.grid(row=7,column=0)

wroll=tk.Scale(ventana4,orient="horizontal",command=regla_roll,from_=-pi,to=pi,resolution=pi/16,bg="red")
wroll.grid(row=8,column=0)


lab_tras=tk.Label(ventana4,text="TRASLACION")
lab_tras.grid(row=5,column=3,sticky=tk.SE)
wtx=tk.Scale(ventana4,orient="horizontal",command=regla_tx,from_=-100,to=100,resolution=5)
wtx.grid(row=6,column=3)

wty=tk.Scale(ventana4,orient="horizontal",command=regla_ty,from_=-100,to=100,resolution=5)
wty.grid(row=7,column=3)

wtz=tk.Scale(ventana4,orient="horizontal",command=regla_tz,from_=-100,to=100,resolution=5)
wtz.grid(row=8,column=3)

wtz.button_reset = tk.Button(ventana4, text="Salir", command= salida, bg="yellow")
wtz.button_reset.grid(row=9,column=9)


ventana.mainloop()
