# L-9 MCS 275 Mon 30 Jan 2017 : flake.py

"""
A Koch flake is a combination of the regular n-gon
and the Koch curve.
"""

from tkinter import Tk, IntVar, Scale, Canvas, ALL
from math import cos, sin, pi, sqrt

class KochFlake(object):
    """
    GUI to draw a Koch flake canvas.
    """
    def __init__(self, wdw):
        """
        Determines the layout of the GUI.
        """
        wdw.title('a regular n-Koch flake')
        self.dim = 400
        self.nbr = IntVar()
        self.k = IntVar()
        self.scn = Scale(wdw, orient='horizontal', \
            from_=3, to=20, tickinterval=1, \
            length=self.dim, variable=self.nbr, \
            command=self.draw_flake)
        self.scn.set(10)
        self.scn.grid(row=0, column=1)
        self.cnv = Canvas(wdw, width=self.dim, \
            height=self.dim, bg='white')
        self.cnv.grid(row=1, column=1)
        self.sck = Scale(wdw, orient='vertical', \
            from_=0, to=6, tickinterval=1,\
            length=self.dim, variable=self.k,\
            command=self.draw_flake)
        self.sck.set(0)
        self.sck.grid(row=1, column=0)

    def koch(self, left, right, k):
        """
        A Koch flake from left to right with k levels.
        """
        if k == 0:
            self.cnv.create_line(left[0], left[1], \
                right[0], right[1], width=2)
        else:
            nlf = ((2*left[0]+right[0])/3.0, (2*left[1]+right[1])/3.0)
            nrg = ((left[0]+2*right[0])/3.0, (left[1]+2*right[1])/3.0)
            mid = ((left[0]+right[0])/2.0, (left[1]+right[1])/2.0)
            ratio = sqrt(3)/6
            top = (ratio*(left[1]-right[1]), ratio*(right[0]-left[0]))
            peak = (mid[0]-top[0], mid[1]-top[1])
            self.koch(left, nlf, k-1)
            self.koch(nlf, peak, k-1)
            self.koch(peak, nrg, k-1)
            self.koch(nrg, right, k-1)

    def draw_flake(self, val):
        """
        Draws a regular Koch flake.
        """
        (xctr, yctr) = (self.dim/2, self.dim/2)
        radius = 0.4*self.dim
        self.cnv.delete(ALL)
        nbr = self.nbr.get()
        k = self.k.get()
        txt = '(' + str(nbr) + ',' + str(k) + ')'
        self.cnv.create_text(xctr, yctr, text=txt, tags="text")
        pts = []
        for i in range(0, nbr):
            xpt = xctr + radius*cos(2*i*pi/nbr)
            ypt = yctr + radius*sin(2*i*pi/nbr)
            pts.append((xpt, ypt))
        for i in range(0, nbr-1):
            self.koch(pts[i], pts[i+1], k)
        self.koch(pts[nbr-1], pts[0], k)

def main():
    """
    Instantiates the GUI object and
    launches the main event loop.
    """
    top = Tk()
    KochFlake(top)
    top.mainloop()

if __name__ == "__main__":
    main()
