#Codigo para o Projecto da disciplina de Computadores e Programacao
#Aluno: Joao Pedro Martins Rodrigues
#Curso: Licenciatura em Eng. Fisica
#Numero de aluno: 2008111898

#Aluno: Tiago Filipe Pimentel das Neves
#Curso: Licenciatura em Eng. Fisica
#Numero de aluno: 2008116065

'''
Codigo de animacao grafica
'''

import math
from visual import *                                                                  # Importar modulo "Visual" from Vpython by David Scherer --- http://www.vpython.org

###Parametros da janela de animacao
scene = display(title='Insecto na placa quente')
scene.height = 600                                                                    # Dimensoes da janela onde aparece a animacao.
scene.width = 1000
scene.background=(28/225.0,49/225.0,70/225.0)
scene.exit = 0                                                                        # Nao acabar o programa quando a janela for fechada
scene.forward=vector(-0.5,-0.5,-1)
scene.autocenter=0                                                                    # Parametro de camara e iluminacao da cena
scene.autoscale = 1 
scene.lights=distant_light(direction=(1,1,0.4), color=color.gray(0.9))
####

###
vel=2000        #>>>> PC - baixar o valor para computadores com menos capacidade      # vel = Variavel que define a velocidade da animacao. Pode ser alterado em funcao da capacidade de computacao do computador
passovel=250                                                                          # passovel = Passo de alteracao da velocidade pelo utilizador. Pode ser alterado em funcao da capacidade de computacao do computador

###Leitura do ficheiro de dados
f=open('experiencias.txt','r')                                                        # f = Ficheiro onde se encontram registados o comprimento, o angulo de cada salto, ultima posicao e o resultado de cada experiencia
print'\nA Processar . . . . . . . . . .',                                             # Informacao que o computador se encontra a efectuar calculos
ler=f.read()                                                                          # Leitura do ficheiro f
print '. . . . . . . . . .'                                                           # Informacao que o computador se encontra a efectuar calculos
ler=ler.split('FIM\n')                                                                # Criacao de uma lista em que cada elemento sao os dados de cada experiencia
f.close()
###

#Imprimir informacao de controlos da animacao
print   """
###############################################################
                  Controlos de animacao
Rato:
Botao direito - Arraste para rodar a camara
Botao direito + botao esquerdo - Arraste para cima para zoom in
                                  e para baixo para zoom out

Teclado:
Q \t-Sair da serie de animacoes
S \t-Parar animacao
P \t-Pausar/continuar animacao
R \t-Activar/desactivar rasto
+/- \t-Aumentar/diminuir velocidade 
################################################################
"""
# Optou-se por colocar estas variaveis, parametros e ordens fora da definicao da funcao 'animacao' para que nao sejam reinicializados sempre que a funcao for chamada ou para que sejam apenas executadas uma unica vez aquando a importacao do modulo

###Funcao animacao
def animacao(nexp,corinsect=(0,0,1)):                                                # Funcao que cria uma animacao grafica da experiencia introduzida no parametro nexp, com a cor introduzida em corinsect e velocidade escolhida no parametro velocidade
    'animacao(nexp,corinsect=(1,1,1))\nVer a animacao da experiencia n. "nexp" com a cor "corinsect" e velocidade "velocidade"'

    scene.visible=1                                                                  # Garante que a janela de animacao esta aberta

    ### Criacao de variaveis
    global vel                                                                       # Utiliza-se a variavel global velocidade para que as alteracoes a velocidade sejam guardadas entre diferentes chamadas da funcao.
    key=''                                                                           # Criacao da variavel 'key' que vai corresponder a entradas de teclado. E necessario cria-la no inicio da funcao para evitar o erro de variavel nao definida dado pela condicao de paragem do ciclo 'for' (ciclo de saltos) caso nao se tenha nenhuma entrada de teclado ate entao. 
    dt=0.01  #>>>> PC - aumentar o valor para computadores com menos capacidade      # Intervalo entre actualizacoes de posicao. Saltos de tempo (tempo virtual que difere do tempo real e depende da capacidade de processamento do computador). Quanto mais pequeno for este valor maior sera a precisao dos calculos de posicao do insecto. Escolhe-se um valor razoavel tendo em conta o compromisso precisao de calculos-poder de processamento do computador.
                                                                                     # Pode ser alterado para um valor maior para correr em computadores menos potentes
    salto=0                                                                          # salto = Contagem dos saltos ja efectuados
    ###
    
    ###Criar objectos graficos
    placa=box(pos=(0,-0.5,0),length=100,height=1,width=60,color=(212/225.0,212/225.0,212/225.0))          # Criar a placa

    insect=sphere(pos=(0,0,0),radius=0.7,color=corinsect)                                                 # Criar o insecto na origem do referencial
    insect.trail = curve(pos=[(0,0,0)],radius=0.05,color=insect.color)                                    # Criar o rasto so insecto
    insect.trail.visible=0                                                                                # Esconder o rasto do insecto

    pontos=points(pos=[(0,0,0)],size=4,color=insect.color)                                                # Criar o conjunto de pontos onde o insecto toca a placa

    leg=label(pos=insect.pos,text='Exp %i\nSalto %i'%(nexp,salto), xoffset=20,yoffset=12,space=insect.radius,height=14,border=6,font='sans',line=0) # Criar a legenda onde aparece o numero da experiencia, o numero do salto e no final o resultado da experiencia
    ###

    ###Leitura do ficheiro de dados
    listaexp=ler[nexp-1].split('\n')                                                # listaexp = Lista com os dados da experiencia escolhida pelo utilizador
    
    comp=float(listaexp[1][12:])                                                    # comp = Comprimento dos saltos. Valor do primeiro elemento da lista excluindo os primeiros 12 caracteres relativos a palavra 'Comprimento:'

    ###Ciclo de experiencia
    for i in listaexp[3:-4]:                                                        # Ciclo de realizacao dos saltos com um angulo lido da lista. Exclui-se o 1. elemento da lista = comprimento do salto e o 2. = 0.0 (quando comeca a experiencia o angulo do ultimo salto feito pelo insecto e por defeito 0). Excluem-se tambem os ultimos elementos que sao a posicao final e o resultado da experiencia.
        teta=1.4                                                                    # teta = Angulo com que a velocidade inicial do salto faz com o plano da placa         

        ainsect=vector(0,-9.8,0)                                                    # ainsect = Vector aceleracao a que o insecto esta sujeito
        v=math.sqrt(comp*abs(ainsect)/math.sin(2*teta))                             # v = Modulo da velocidade inicial do salto. Calculado a partir das equacoes do alcance de um projectil para uma aceleracao e angulo de tiro determinados
        vinsect=vector(math.cos(float(i)),math.tan(teta),math.sin(float(i)))  /  abs(vector(math.cos(float(i)),math.tan(teta),-math.sin(float(i)))) * v  #vinsecto= Vector Velocidade inicial de cada salto. Versor velocidade inicial * modulo da velocidade

        posi=vector(insect.x,insect.y,insect.z)                                     # posi - Posicao inicial de cada salto
        posf=posi+vector(cos(float(i)),0,sin(float(i)))*comp                        # posf - Posicao final de cada salto calculada com grande precisao

        salto+=1                                                                    # Acrescenta um valor a contagem dos saltos para efeitos de actualizacao de legenda
        leg.text='Exp %i\nSalto %i'%(nexp,salto)                                    # Actualiza a legenda

        ###Ciclo de salto
        while 1:                                                                    # Ciclo de salto

            ###-Controlos de teclado                                                # Controlos de teclado. Escolheu-se esta parte do programa para colocar estes controlos pois e o ciclo mais frequente
            if scene.kb.keys:                                                       # Condicao que verifica se se encontra alguma entrada de teclado em fila de espera
                key=scene.kb.getkey()                                               # key - Primeira entrada de teclado na fila de espera
                if key=='p' or key=='P':                                            # Controlo para pausar/continuar a animacao.
                    print '||'
                    while 1:
                        key2=scene.kb.getkey()                                      # Espera por uma nova entrada de teclado 'P'
                        if key2=='p' or key2=='P':
                            print '>'
                            break
                if key=='r' or key=='R':                                            # Controlo para activar/desactivar o rasto do insecto.
                    if insect.trail.visible==1:
                        insect.trail.visible=0
                    else:
                        insect.trail.visible=1
                elif key=='+':                                                      # Controlo de teclado para aumentar a velocidade da animacao.
                    vel+=passovel
                    print 'Velocidade:',vel
                elif key=='-' and vel>passovel:                                     # Controlo de teclado para diminuir a velocidade da animacao. Condicao de comparacao impede que a velocidade chegue a 0
                    vel-=passovel
                    print 'Velocidade:',vel
                else:
                    pass
            ###

            rate(vel)                                                               # Traduz a velocidade da animacao. Isto especifica que o ciclo nao sera executado mais que 'vel' vezes por segundo.
      
            vinsect=vinsect+ainsect*dt                                              # Segundo as leis do movimento, vf = vi + a t e xf = xi + v t. 
            insect.pos=leg.pos=insect.pos+vinsect*dt

            insect.trail.append(pos=insect.pos)                                     # Adicionar um ponto ao rasto do insecto
    
            if insect.y<0:                                                          # O salto acaba quando o insecto volta a poisar na placa
                #print 'ERRO',insect.pos-posf #teste
                insect.pos=posf                                                     # Corrige-se a posicao final do salto. E necessario fazer isto pois a posicao final do salto realizado pela animacao nao coincide exactamente com a posicao final que se esperaria. Isto so aconteceria se dt tendesse para 0. Ou seja, quanto menor for dt mais precisa e a animacao. Para evitar ter dt muito pequenos o que sobrecarregaria o computador com calculos e evitar que os erros desta imprecisao se propaguem de uns saltos para os outros, corrige-se a posicao final com uma formula muito mais precisa.  
                pontos.append(posf)                                                 # Cria-se um ponto que corresponde a posicao final do salto
                break                                                               # Termina-se o salto
        ###

        ###Controlos de teclado
        if key=='s' or key=='S':                                                    # Condicao de paragem da experiencia por ordem de teclado. Caso tenha sido introduzido um 's' ou 'S' pelo utilizador ele ficou guardado na variavel 'key' (caso nao tenham sido introduzidas mais ordens de teclado ate ao final do salto (ciclo while) onde foi introduzido 'p' ou 'P') valida a condicao. 
            insect.pos=leg.pos=(float(listaexp[-3]),0,float(listaexp[-2]))          # Colocar o insecto e a legenda na posicao final da experiencia lida do ficheiro
            break
        if key=='q' or key=='Q':                                                    # Condicao de paragem das experiencias por ordem de teclado. Caso tenha sido introduzido um 'q' ou 'Q' pelo utilizador ele ficou guardado na variavel 'key' (caso nao tenham sido introduzidas mais ordens de teclado ate ao final do salto (ciclo while) onde foi introduzido 'p' ou 'P') valida a condicao. 
            insect.pos=leg.pos=(float(listaexp[-3]),0,float(listaexp[-2]))          # Colocar o insecto e a legenda na posicao final da experiencia lida do ficheiro
            return 'quit'                                                           # A funcao devolve a string para que possa ser intrepertado pelo modulo principal para interromper o ciclo de representacao das experiencias
        ###

    ###Resultado da experiencia
    
    if listaexp[-4]=='Morreu':
        leg.text='Exp. %i\nMorreu'%(nexp)                                           # Actualizacao da legenda e da cor do insecto conforme o resultado da experiencia
        #insect.color=color.red
    else:
        leg.text='Exp. %i\nSalto %i\nSobreviveu'%(nexp,len(listaexp)-7)
        #insect.color=color.green
    ###


def limpar():
    print "Limpar scene"
    global scene
    
    scene.visible=0


    ###Parametros da janela de animacao
    scene = display(title='Insecto na placa quente')
    scene.height = 600                                                                    # Dimensoes da janela onde aparece a animacao.
    scene.width = 1000
    scene.background=(28/225.0,49/225.0,70/225.0)
    scene.exit = 0                                                                        # Nao acabar o programa quando a janela for fechada
    scene.forward=vector(-0.5,-0.5,-1)
    scene.autocenter=0                                                                    # Parametro de camara e iluminacao da cena
    scene.autoscale = 1 
    scene.lights=distant_light(direction=(1,1,0.4), color=color.gray(0.9))
    ####



animacao(1)
limpar()
animacao(2)
limpar()
animacao(3)
