#!/usr/bin/python
# -*- encoding: utf-8 -*-

from tkinter import *
import random
import math

# Gravitacija
g = 9.8 * 10  # 1 meter = 10 točk na zaslonu

# Preprost primer animacije s Tkinter.

class Nihalo():
    '''Dvojno nihalo.'''

    def __init__(self, width, height, l1, l2, m1, m2):
        self.width = width
        self.height = height
        self.l1 = l1
        self.l2 = l2
        self.m1 = m1
        self.m2 = m2
        # Začetna pozicija
        self.th1 = random.uniform(0.0, 2.0 * math.pi)
        self.th2 = random.uniform(0.0, 2.0 * math.pi)
        # Začetna hitrost
        self.om1 = random.uniform(-math.pi, math.pi)
        self.om2 = random.uniform(-math.pi, math.pi)

    def pozicija1(self):
        """Pozicija prve mase"""
        x1 = self.width/2 + self.l1 * math.sin(self.th1)
        y1 = self.height/2 + self.l1 * math.cos(self.th1)
        return (int(x1), int(y1))

    def pozicija2(self):
        """Pozicija druge mase"""
        x2 = self.width/2 + self.l1 * math.sin(self.th1) + self.l2 * math.sin(self.th2)
        y2 = self.height/2 + self.l1 * math.cos(self.th1) + self.l2 * math.cos(self.th2)
        return (int(x2), int(y2))

    def energija(self):
        potencialna = (- (self.m1 + self.m2) * g * self.l1 * math.cos(self.th1) -
                         self.m2 * g * self.l2 * math.cos (self.th2))
        kineticna = (0.5 * self.m1 * self.l1**2 * self.om1**2 +
                     0.5 * self.m2 * (self.l1**2 * self.om1**2 + self.l2**2 * self.om2**2 +
                                      2 * self.l1 * self.l2 * self.om1 * self.om2 * math.cos(self.th1 - self.th2)))
        return potencialna + kineticna

    def premakni(self, dt):
        '''Izračunaj novo stanje krogle po preteku časa dt.'''
        # Tole smo pokradli iz:
        # - http://www.phy.davidson.edu/StuHome/chgreene/Chaos/Double%20Pendulum/theory.htm
        # - http://scienceworld.wolfram.com/physics/DoublePendulum.html
        imenovalec = 2 * self.m1 + self.m2 - self.m2 * math.cos (2 * (self.th1 - self.th2))
        om1pika = (-g * (2 * self.m1 + self.m2) * math.sin(self.th1)
                         - self.m2 * g * math.sin (self.th1 - 2 * self.th2)
                         - 2 * math.sin(self.th1 - self.th2) * self.m2 * (self.om2**2 * self.l2 - self.om1**2 * self.l1 * math.cos(self.th1 - self.th2))                          
            ) / (self.l1 * imenovalec)
        om2pika = (2 * math.sin(self.th1 - self.th2) *
                        (self.om1**2 * self.l1 * (self.m1 + self.m2) +
                         g * (self.m1 + self.m2) * math.cos(self.th1) +
                         self.om2**2 * self.l2 * self.m2 * math.cos(self.th1 - self.th2))
                        ) / (self.l2 * imenovalec)
        self.th1 = self.th1 + dt * self.om1 #+ 0.5 * om1pika * dt * dt
        self.th2 = self.th2 + dt * self.om2 #+ 0.5 * om2pika * dt * dt
        self.om1 = self.om1 + dt * om1pika
        self.om2 = self.om2 + dt * om2pika
        
class Simulacija():
    def __init__(self, master):
        width = 640
        height = 640
        self.energija = DoubleVar(master)
        Label(master, textvariable=self.energija).grid(row=1, column=0)
        self.dt = 0.01
        self.nihalo = Nihalo(width, height, 50, 150, 0.1, 200)
        self.canvas = Canvas(master, width=width, height=height)
        self.canvas.grid(row=0, column=0)

        (x0, y0) = (self.nihalo.width//2, self.nihalo.height//2)
        (x1, y1) = self.nihalo.pozicija1()
        (x2, y2) = self.nihalo.pozicija2()
        self.palica1_id = self.canvas.create_line(x0,y0,x1,y1)
        self.palica2_id = self.canvas.create_line(x1,y1,x2,y2)
        self.tocke = []
        # Zaženemo animacijo
        self.animacija()

    def animacija(self):
        self.nihalo.premakni(self.dt)
        self.energija.set(self.nihalo.energija())
        (x0, y0) = (self.nihalo.width//2, self.nihalo.height//2)
        (x1, y1) = self.nihalo.pozicija1()
        (x2, y2) = self.nihalo.pozicija2()
        self.canvas.coords(self.palica1_id, x0, y0, x1, y1)
        self.canvas.coords(self.palica2_id, x1, y1, x2, y2)
        self.canvas.after(int(self.dt * 1000), self.animacija)
        tocka = self.canvas.create_oval(x2-1,y2-1,x2+1,y2+1, fill="red", outline="red")
        self.tocke.append(tocka)
        if len(self.tocke) > 500:
            self.canvas.delete(self.tocke.pop(0))

        

# Glavnemu oknu rečemo "root" (koren), ker so grafični elementi
# organizirani v drevo, glavno okno pa je koren tega drevesa

# Naredimo glavno okno
root = Tk()

root.title("Dvojno nihalo")

aplikacija = Simulacija(root)

# Kontrolo prepustimo glavnemu oknu. Funkcija mainloop neha
# delovati, ko okno zapremo.
root.mainloop()
