#-----------------------------------------------------------------------
			#Descripcion del programa
"""
Este programa tiene por objeto determinar cuales son los coeficientes de 
sustentacion y el coeficiente de momentos respecto al centro aerodinamico
de un perfil perteneciente a la serie NACA de 4 digitos, a partir del 
metodo de perfil Joukowski, el cual hace una transformacion conforme de 
una circunsferencia en el plano complejo, al plano zeta. A su vez, este
programa realiza la conversion de los datos a flujo compresible (cuando 
el numero de mach sea mayor a 0.3) mediante la transformacion de 
Prandtl-Glauert, la cual establece que para un mismo perfil, con mismo 
angulo de ataque, los coeficinetes de sustentacion y momentos deben ser
afectados en proporcion al factor 1/beta, donde beta es la raiz cuadrada
de uno menos el numero de mach al cuadrado. Cabe aclarar que esto solo es
valido para perfiles Bidimensionales y que se en Regimen Subsonico.
Por este motivo el numero de mach debe ser menor a 0.9 y mayor o igual a 0
Otro dato a tener en cuenta, es que los valores de Cl hallados, dan muy 
buenos resultados en la zona lineal de la curva, por este motivo, se 
establecio que el presente programa tenga como limite superior los 15*
y como limite infererior -5*
Cuando los calculos sean realizados de forma correcta, aparecera un 
cartel informandolo, caso contrario, en que los datos infresados no sean
validos, los calculos no se realizaran, y aparecera un cartel avisando 
que los datos suministrados son incorrectos
"""
#-----------------------------------------------------------------------
			#Importar librerias y limpieza de datos
			
			
import os				#Limpieza
os.system("clear")

import math				#Para poder usar funciones matematicas trigonometricas, raices y el numero Pi

import Tkinter as tk	#Llamar al Tkinter
from Tkinter import *

import ttk				#Es para la creacion de pestanas
from ttk import *

import tkMessageBox		#Para poder colocar mensajes
#-----------------------------------------------------------------------
				#Condiciones iniciales


w_max=600.0     	#Ancho de ventana
h_max=300.0     	#Alto de ventana
c=400. 				#Cuerda del perfil
x1=[]				#Lista de puntos en X (circunsferencia)
y1=[]				#Lista de puntos en Y (circunsferencia)
zeda=[]				#Lista de puntos en X (perfil)
eta=[]				#Lista de puntos en Y (perfil)
corrimientoX=250 	#Corriemiento en X para el grafico del perfil
corrimientoY=150 	#Corriemiento en Y para el grafico del perfil
distX=500			#Posicion de la lista de corrdenadas en la presentacion (X)
distY=550			#Posicion de la lista de corrdenadas en la presentacion (Y)

#-----------------------------------------------------------------------
				#Definicion de funciones

"""
La funcion validar es la que inicia los calculos
Si los datos ingresados son incorrectos, informara con un cartel que deben volver
a cargarse los mismos
Si los datos son corrector, llamara a la funcion calcular para obtener los valores
y cuando termine, informara con un cartel, avisando al usuario que ya puede cambiar
de pestana para que visualice lo que desea
Condiciones: Naca de 4 digitos, angulo de ataque entre -5 y 15 (zona lineal)
y numero de mach subsonico (entre 0 y 0.9)
Cuando se cumpla con esto, aparecera un cartel informando que los calculos
se realizaron de forma correcta, caso contrario, un mensaje pidiendo que se
vuelvan a ingresar los datos
"""				
def validar():
	if len(perfil.get())==4 and -5<float(alfa.get())<15 and 0<=float(mach.get())<0.9:
		calcular()
		tkMessageBox.showinfo(message="      Calculo Completado\nYa puede cambiar de pestana",title="Felicidades")
	else:
		tkMessageBox.showwarning('Cuidado','Numero incorrecto!\nVuelva a ingresar')
	return

"""
La funcion calcular setea en las variables string un texto+una transformacion a str 
de lo que se obtiene en los datos de la caja de texto
Luego llama a la funcion joukowski
"""
def calcular():
	naca.set('Perfil NACA:                   '+(str)(perfil.get()))
	angulo_ataque.set('Angulo de Ataque:        '+(str)(alfa.get())+"*")
	numero_mach.set('Numero de Mach:         '+(str)(mach.get()))
	joukowski()
	return

"""
La funcion joukowski en primer lugar borra lo que habia en las listas globales de puntos
Crea la variable local NACA a la cual asigna lo que se obtiene en perfil (caja de datos)
Como es un string, comparte las propiedades de las listas, por lo que, se pueden pedir 
determinadas posiciones del string NACA
Los ultimos dos digitos de la serie naca representan el espesor del perfil en porcentaje de la cuerda
El primer digito reprensenta la curvaruta en porentaje de la cuerda
Luego comienza el metodo joukowski y asigna los valores de Cl y Cmac como si fueran
string, con el objetivo de poder controlar la cantidad de decimales (fisicamente, la parte entera en la 
mayor parte de los casos es de solamente un digito, por este motivo es posible controlar los decimales, ya que
se conoce la parte entera
Dentro de un while se asignan los valores de la listas de puntos de la circunsferencia
y el perfil asociado a la misama. Para esto se recorre angulos de 0 a 2 Pi, con saltos de 0.1
Por ultimo llama a la funcion dibujar, para poder graficar el perfil, y luego limpia las variables de compresible
y pregunta si el mach es mayor a 0.3, llama a la funcion compresible con los datos de cl,cma,Minf
Caso contrario, en la pestana 2, correspondiente a los datos de salida compresible, coloca el mensaje
diciendo que el flujo es incompresible, por lo tanto no hace nada"""
def joukowski():
	x1=[]			#Lista de X (circunsferencia)
	y1=[]			#Lista de Y (circunsferencia)
	zeda=[]			#Lista de X (perfil)
	eta=[]			#Lista de Y (perfil)
	NACA=perfil.get()
	espesor=float(NACA[2:4])/100
	curvatura=float(NACA[0])/100
	e=espesor/1.299
	h=c/(4*(1+e**2))
	p=e*h
	m=2*curvatura*(p+h)
	a=math.sqrt((p+h)**2+m**2)
	beta=math.atan(m/(p+h))
	ataque=alfa.get()*math.pi*1/180.
	cl=(8*math.pi*a*math.sin(ataque+beta))/c
	cl_incompresible.set('Cl incompresible:         '+(str)(cl)[0:5])
	cma=-4*math.sin(2*beta)*((h/c)**2)
	cmca_incompresible.set('Cmca incompresible:     '+(str)(cma)[0:7])
	Minf=float(mach.get())
	theta=0.			#Angulo de barrido
	while theta<2*math.pi:
		x=(a*math.cos(theta)-p)
		y=(a*math.sin(theta)+m)
		x1.append(x)
		y1.append(y)
		zeda.append(x+((x*(h**2)/((x**2)+(y**2)))))
		eta.append(y-((y*(h**2)/((x**2)+(y**2)))))
		theta=theta+0.1
	dibuja(zeda,eta)
	cl_compresible.set(" ")
	cmca_compresible.set(" ")
	naca2.set(" ")
	angulo_ataque2.set(" ")
	numero_mach2.set(" ")
	mensaje.set(" ")
	#A continuacion se analiza si el flujo es compresible o incompresible
	if Minf>0.3:
		compresible(cl,cma,Minf)
	else:
		mensaje.set(" El Minf es menor a 0.3\n\nEl flujo es incompresible")
		e11=Label(pes2,textvariable=mensaje).place(x=200,y=100)
	return 
	
"""
La funcion compresible, llamada en la funcion joukowski, transforma los datos
de cl y cmca incompresibles a valores compresibles, utilizando la transformacion 
de Prandtl Glauret (Regla II en la materia Aerodinamica Terica), la cual permite mantener el mismo perfil de incompresible, y
obtener como se comporta en compresible, simplemente dividiendo por el valor de beta.
Tener en cuenta que esta transformacion da muy buenos resultados cuando se considera 
que el problema es bidimensional, el cual es el caso."""
def compresible(cl,cma,Minf):
	betamach=math.sqrt(1-Minf**2)
	cl_comp=cl/betamach
	cl_compresible.set('Cl compresible:           '+(str)(cl_comp)[0:5])
	cmca_comp=cma/betamach
	cmca_compresible.set('Cmca compresible:       '+(str)(cmca_comp)[0:7])
	naca2.set('Perfil NACA:                   '+(str)(perfil.get()))
	angulo_ataque2.set('Angulo de Ataque:        '+(str)(alfa.get())+"*")
	numero_mach2.set('Numero de Mach:         '+(str)(mach.get()))
	e8=Label(pes2,textvariable=naca2).place(x=w_max/3,y=30)
	e9=Label(pes2,textvariable=angulo_ataque2).place(x=w_max/3,y=80)
	e10=Label(pes2,textvariable=numero_mach2).place(x=w_max/3,y=130)
	return

"""
La funcion dibuja se encarga de graficar el perfil Naca y a su vez
presentar una tabla de puntos del perfil
"""
def dibuja(x,y):
    canvas.delete(tk.ALL)
    i=0
    for i in range(len(x)-1):
		canvas.create_line(corrimientoX+x[i],corrimientoY-y[i],corrimientoX+x[i+1],corrimientoY-y[i+1])
    canvas.create_text(distX,15,text='X')
    canvas.create_text(distX+25,15,text="|")
    canvas.create_text(distY,15,text='Y')
    canvas.create_text(distX,15,text='______')
    canvas.create_text(distY,15,text='______')
    i=0
    j=0
    interlinea=15 	#Es para dejar espacio entre los renglones de la tabla de puntos
    while i<62:
		coordx=str(x[i])[:5]
		coordy=str(y[i])[:5]
		canvas.create_text(distX,30+interlinea*j,text=(coordx))
		canvas.create_text(distX+25,30+interlinea*j,text=("|"))
		canvas.create_text(distY,30+interlinea*j,text=(coordy))
		i=i+4		#Con esto, salteo 4 puntos, para que la tabla muestre 10, en caso contrario no entraria en la pantalla
		j=j+1 		#Esto es para los renglones de la lista de puntos
    return
#-----------------------------------------------------------------------
					#Programa Principal

#Abro la ventana TK					
ventana=tk.Tk()

						#Variables
						
perfil=StringVar() 				#Es el ingreso del numero del perfil
naca=StringVar() 				#Es utilizado para presentar datos en incompresible
naca2=StringVar()				#Es utilizado para presentar datos en compresible

alfa=DoubleVar()				#Es el ingreso del angulo de ataque en grados
angulo_ataque=StringVar()		#Es utilizado para presentar datos en incompresible
angulo_ataque2=StringVar()		#Es utilizado para presentar datos en compresible

mach=DoubleVar()				#Es el ingreso del numero de Mach
numero_mach=StringVar()			#Es utilizado para presentar datos en incompresible
numero_mach2=StringVar()		#Es utilizado para presentar datos en compresible

cl_incompresible=StringVar()	#Coresponde al Cl incompresible
cmca_incompresible=StringVar()	#Corresponde al Cmca incompresible

cl_compresible=StringVar()		#Corresponde al Cl compresible
cmca_compresible=StringVar()	#Corresponde al Cmca compresible

mensaje=StringVar()				#Es el mensaje al ser llenado cuando el flujo es incompresible



				#Creacion de pestanas 
				
notebook=ttk.Notebook(ventana)
notebook.pack(fill='both',expand='yes')

""" Notas
fill='both' hace que rellene en vertical y horizontal
xpand='yes'hace que se expanda, siempre que no se choque con otro componente)
"""

pes0=ttk.Frame(notebook) 						#Pestana cero
pes1=ttk.Frame(notebook) 						#Pestana uno
pes2=ttk.Frame(notebook)						#Pestana dos
pes3=ttk.Frame(notebook)						#Pestana tres
notebook.add(pes0,text='Datos de entrada')		#Titulo de pestana 0
notebook.add(pes1,text='Incompresible')			#Titulo de pestana 1 
notebook.add(pes2,text='Compresible')			#Titulo de pestana 2 
notebook.add(pes3,text='Grafico')				#Titulo de pestana 3



					#Pestana de datos (INPUT)					
#Los ei y wi son textos/etiquetas
e0=Label(pes0,text='Perfil: ').place(x=20,y=50)
w0=Label(pes0,text='*Debe ser un Naca de 4 digitos').place(x=330,y=50)
e1=Label(pes0,text='Alfa: ').place(x=20,y=100)
w1=Label(pes0,text='*Angulo en grados entre -5 y 15').place(x=330,y=100)
e2=Label(pes0,text='Mach: ').place(x=20,y=150)
w2=Label(pes0,text='*Numero de Mach debe ser menor a 0.9').place(x=330,y=150)
#Las cajai permiten ingresar los datos, corresponde a las variables de texto antes declaradas
caja0=Entry(pes0,textvariable=perfil).place(x=120,y=50)
caja1=Entry(pes0,textvariable=alfa).place(x=120,y=100)
caja2=Entry(pes0,textvariable=mach).place(x=120,y=150)
#Agrego boton, este llama a la funcion "validar"
boton=Button(pes0,text='Calcular',command=validar).place(x=250,y=200)



			#Pestana de salida incompresible (OUTPUT 1)
"""Los ei son textos los cuales presentan salidas, los textos variables correspondientes
a los varoles obtenidos por el metodo"""
e3=Label(pes1,textvariable=naca).place(x=w_max/3,y=30)
e4=Label(pes1,textvariable=angulo_ataque).place(x=w_max/3,y=80)
e5=Label(pes1,textvariable=numero_mach).place(x=w_max/3,y=130) 
e6=Label(pes1,textvariable=cl_incompresible).place(x=w_max/3,y=180)
e7=Label(pes1,textvariable=cmca_incompresible).place(x=w_max/3,y=230)



			#Pestana de salida compresible (OUTPUT 2) 
"""Los ei son textos los cuales presentan salidas, los textos variables correspondientes
a los varoles obtenidos por el metodo"""
e11=Label(pes2,textvariable=cl_compresible).place(x=w_max/3,y=180)
e12=Label(pes2,textvariable=cmca_compresible).place(x=w_max/3,y=230)



					#Pestana grafica (OUTPUT 3)
#Creacion del canvas para que ocupe toda la pestana 3 y que sea de fondo blanco
canvas = Canvas(pes3,bg='white')
canvas.pack(fill = BOTH, expand = 1)
canvas.update()



#Tamano y titulo de la ventana
ventana.geometry('600x300')
ventana.title('Generador Joukowski by Carbonel')

mainloop()
#-----------------------------------------------------------------------
