Search This Blog

Sunday, December 30, 2018

Python Program to create spirals

I was reading a book on artificial intelligence and in the book it mentioned the Archimedes spiral.  There was a drawing that was fairly interesting.  So I decided to see if I could draw it on the screen using a Python script.  After some reading on Wikipedia about different kinds of spirals, and some work, the result was the program below.
But first, some pictures of the results.  The first one is a set of Lituus curves.

This next one is a set of logarithmic spirals.

And a final taste, an Archimedean spiral:

The code below allows you to vary the color of the lines, the number of spirals displayed and what type.  The types include the ones shown above plus Fermat's spiral and hyperbolic spirals.




# Draws spirals on a canvas
from Tkinter import *
from math import *
from random import randint
from time import sleep
class App:
    """This class is derived, I think, from a TK class and is designed to
    work with the TK environment.
    Requires imports from Tkinter, math, random and time"""
    def __init__(self, master):
        """This class is the whole of the application """
        # Necessary Frames
        frame = Frame(master)
        control_frame = Frame(frame)
        control_frame.grid(row = 0, column = 0, sticky = N)
        canvas_frame = Frame(frame)
        canvas_frame.grid(row =0, column = 1, rowspan=2)
        status_frame = Frame(frame)
        status_frame.grid(row = 1, column =0, sticky = S)
        #Entry box variables
        self.cmd_var = IntVar()
        self.parm1_var = DoubleVar()
        self.parm2_var = DoubleVar()
        self.parm1_var.set(12.0)
        self.color_code = 0
        # 0 = random
        # 1 = blue
        # 2 = black
        # 3 = red
        # 4 = green
        self.spiral_type = 5
        # 1 = normal,
        # 2 = logarithmic,
        # 3 = Hyperbolic
        # 4 = Fermat's spiral
        # 5 = Lituus spiral
               
        #Control FrameWidgets
        self.tmpstr = 'Number of spirals:\n'+str(self.parm1_var.get())
        self.lab = Label(control_frame, text=self.tmpstr)
        self.lab.pack(side = TOP)
       
       
        # The Canvas
        self.canvas = Canvas(canvas_frame, width = 800, height = 800)
        self.canvas.config(bg='white')
        self.canvas.pack()
        self.clear()
        frame.pack()
        #Menu's
        menubar = Menu(root)
        menu_1 = Menu(menubar, tearoff=0)
        menu_1.add_command(label='Quit',command=root.destroy)
        menubar.add_cascade(label='File', menu=menu_1)
        menu_2 = Menu(menubar, tearoff=0)
        menu_2.add_command(label='2', command=self.menu_2)
        menu_2.add_command(label='3', command=self.menu_3)
        menu_2.add_command(label='4', command=self.menu_4)
        menu_2.add_command(label='5', command=self.menu_5)
        menu_2.add_command(label='6', command=self.menu_6)
        menu_2.add_command(label='7', command=self.menu_7)
        menu_2.add_command(label='8', command=self.menu_8)
        menu_2.add_command(label='9', command=self.menu_9)
        menu_2.add_command(label='10', command=self.menu_10)
        menu_2.add_command(label='11', command=self.menu_11)
        menu_2.add_command(label='12', command=self.menu_12)
        menubar.add_cascade(label='Spirals', menu=menu_2)
        master.config(menu=menubar)
        menu_3 = Menu(menubar, tearoff=0)
        menu_3.add_command(label='Archimedean', command=self.set_normal)
        menu_3.add_command(label='Logarithmic', command=self.set_log)
        menu_3.add_command(label='Hyperbolic', command=self.set_hyp)
        menu_3.add_command(label='Fermat', command=self.set_fermat)
        menu_3.add_command(label='Lituus', command=self.set_lituus)
        menubar.add_cascade(label='Type', menu = menu_3)
        menu_4 = Menu(menubar, tearoff = 0)
        menu_4.add_command(label='Random', command=self.color_ran)
        menu_4.add_command(label='Blue', command=self.color_blue)
        menu_4.add_command(label='Black', command=self.color_black)
        menu_4.add_command(label='Red', command=self.color_red)
        menu_4.add_command(label='Green', command=self.color_grn)
        menubar.add_cascade(label='Color', menu=menu_4)
    def color_grn(self):
        """This function sets the color of th elines to green and then
        refreshes the screen."""
        self.color_code=4
        self.clear()
    def color_red(self):
        """This function sets the color of the lines to red and then
        refreshes the screen."""
        self.color_code=3
        self.clear()
       
    def color_black(self):
        """This function sets the color of the lines to black and then
        refreshes the screen."""
        self.color_code=2
        self.clear()
    def color_ran(self):
        """This function sets the color of the lines to random and then
        refreshes the screen."""
        self.color_code = 0
        self.clear()
    def color_blue(self):
        """This function sets the color of the lines to blue and then
        refreshes the screen."""
        self.color_code = 1
        self.clear()
    def set_lituus(self):
        """This function sets the spiral type to Lituus and then
        refreshes the screen."""
        self.spiral_type = 5
        self.clear()
    def set_fermat(self):
        """This function sets the spiral type to Fermat and then refreshes
        the screen."""
        self.spiral_type = 4
        self.clear()
    def set_hyp(self):
        """This function sets the spiral type to hyperbolic and then
        refreshes the screen"""
        self.spiral_type=3
        self.clear()
    def set_normal(self):
        """This function sets the spiral type to Archimedean and then
        refreshes the screen"""
        self.spiral_type=1
        self.clear()
    def set_log(self):
        """This function sets the spiral type to Logarithmic and then
        refreshes the screen"""
        self.spiral_type=2
        self.clear()
    def clear(self):
        """This function clears the screen, calls the appropriate drawing
        function, and updates the message."""
        self.canvas.delete(ALL)
        if self.spiral_type ==1:
            self.draw_spiral()
        elif self.spiral_type ==2:
            self.draw_log()
        elif self.spiral_type ==3:
            self.draw_hyp()
        elif self.spiral_type ==4:
            self.draw_fermat()
        else:
            self.draw_lituus()
        self.tmpstr = 'Number of spirals:\n'+str(self.parm1_var.get())+\
        "\nType of Spirals:\n"
        types = ['Archimedean','Logarithmic','Hyperbolic',
                 'Fermat','Lituus']
        self.tmpstr = self.tmpstr + types[self.spiral_type -1]
        self.lab.config(text=self.tmpstr)
       
    def draw_spiral(self):
        """This is the drawing function for the Archimedean spiral"""
        for k in range(0,int(self.parm1_var.get())):
            x=0
            y=0
            if self.color_code == 0:
                tk_rgb = "#%02x%02x%02x" % (randint(0,255), randint(0,255),
                                        randint(0,255))
            else:
                tk_rgb = ['null','blue','black','red','green'][self.color_code]
            for r in range(0,400): #scaled 100 = pi
                theta = r*2*pi/200.0 - 2*k*pi/self.parm1_var.get()
                new_x = r*sin(theta)
                new_y = r*cos(theta)
                self.canvas.create_line(x+400,y+400,new_x+400,new_y+400,
                                        fill=tk_rgb)
                x = new_x
                y = new_y
            sleep(0.1)
            self.canvas.update()
        for k in range(0,int(self.parm1_var.get())):
            x=0
            y=0
            if self.color_code == 0:
                tk_rgb = "#%02x%02x%02x" % (randint(0,255), randint(0,255),
                                        randint(0,255))
            else:
                tk_rgb = ['null','blue','black','red','green'][self.color_code]
            for r in range(0,400): #scaled 100 = pi
                theta = -(r*2*pi/200.0 - 2*k*pi/self.parm1_var.get())
                new_x = r*sin(theta)
                new_y = r*cos(theta)
                self.canvas.create_line(x+400,y+400,new_x+400,new_y+400,
                                        fill=tk_rgb)
                x = new_x
                y = new_y
            sleep(0.1)
            self.canvas.update()
    def draw_log(self):
        """This is the drawing function for the logarithmic spiral"""
        for k in range(0,int(self.parm1_var.get())):
            x=0
            y=0
            if self.color_code == 0:
                tk_rgb = "#%02x%02x%02x" % (randint(0,255), randint(0,255),
                                        randint(0,255))
            else:
                tk_rgb = ['null','blue','black','red','green'][self.color_code]
            for r in range(10,1000,10):
                theta=log(r) - 2*k*pi/self.parm1_var.get()
                #r = exp(theta*2*pi/100.0 + 2*k*pi/self.parm1_var.get())
                new_x = r*sin(theta)*0.4
                new_y = r*cos(theta)*0.4
                self.canvas.create_line(x+400,y+400,new_x+400,new_y+400,
                                        fill=tk_rgb)
                x = new_x
                y = new_y
            sleep(0.1)
            self.canvas.update()
        for k in range(0,int(self.parm1_var.get())):
            x=0
            y=0
            if self.color_code == 0:
                tk_rgb = "#%02x%02x%02x" % (randint(0,255), randint(0,255),
                                        randint(0,255))
            else:
                tk_rgb = ['null','blue','black','red','green'][self.color_code]
            for r in range(10,1000,10):
                theta=-(log(r) - 2*k*pi/self.parm1_var.get())
                #r = -(exp(theta*2*pi/100.0 + 2*k*pi/self.parm1_var.get()))
                new_x = r*sin(theta)*0.4
                new_y = r*cos(theta)*0.4
                self.canvas.create_line(x+400,y+400,new_x+400,new_y+400,
                                        fill=tk_rgb)
                x = new_x
                y = new_y
            sleep(0.1)
            self.canvas.update()
           
    def draw_hyp(self):
        """This is the drawing function for the hyperbolic spiral"""
        for k in range(0,int(self.parm1_var.get())):
            x=0
            y=0
            if self.color_code == 0:
                tk_rgb = "#%02x%02x%02x" % (randint(0,255), randint(0,255),
                                        randint(0,255))
            else:
                tk_rgb = ['null','blue','black','red','green'][self.color_code]
            for r in range(1,100):
                theta=30.0/r + 2*k*pi/self.parm1_var.get()
                new_x = r*sin(theta)*4
                new_y = r*cos(theta)*4
                self.canvas.create_line(x+400,y+400,new_x+400,new_y+400,
                                        fill=tk_rgb)
                x = new_x
                y = new_y
            sleep(0.1)
            self.canvas.update()
        for k in range(0,int(self.parm1_var.get())):
            x=0
            y=0
            if self.color_code == 0:
                tk_rgb = "#%02x%02x%02x" % (randint(0,255), randint(0,255),
                                        randint(0,255))
            else:
                tk_rgb = ['null','blue','black','red','green'][self.color_code]
            for r in range(1,100):
                theta=-(30.0/r + 2*k*pi/self.parm1_var.get())
                new_x = r*sin(theta)*4
                new_y = r*cos(theta)*4
                self.canvas.create_line(x+400,y+400,new_x+400,new_y+400,
                                        fill=tk_rgb)
                x = new_x
                y = new_y
            sleep(0.1)
            self.canvas.update()
    def draw_fermat(self):
        """This is the drawing function for Fermat's spiral"""
        for k in range(0,int(self.parm1_var.get())):
            x=0
            y=0
            if self.color_code == 0:
                tk_rgb = "#%02x%02x%02x" % (randint(0,255), randint(0,255),
                                        randint(0,255))
            else:
                tk_rgb = ['null','blue','black','red','green'][self.color_code]
            for r in range(0,100):
                theta=(r/40.0)**2 + 2.0*k*pi/self.parm1_var.get()
                new_x = r*sin(theta)*3
                new_y = r*cos(theta)*3
                self.canvas.create_line(x+400,y+400,new_x+400,new_y+400,
                                        fill=tk_rgb)
                x = new_x
                y = new_y
            sleep(0.1)
            self.canvas.update()
        for k in range(0,int(self.parm1_var.get())):
            x=0
            y=0
            if self.color_code == 0:
                tk_rgb = "#%02x%02x%02x" % (randint(0,255), randint(0,255),
                                        randint(0,255))
            else:
                tk_rgb = ['null','blue','black','red','green'][self.color_code]
            for r in range(0,100):
                theta=-((r/40.0)**2 + 2.0*k*pi/self.parm1_var.get())
                new_x = r*sin(theta)*3
                new_y = r*cos(theta)*3
                self.canvas.create_line(x+400,y+400,new_x+400,new_y+400,
                                        fill=tk_rgb)
                x = new_x
                y = new_y
            sleep(0.1)
            self.canvas.update()
          
    def draw_lituus(self):
        """This is the drawing function for a Lituus spiral"""
        for k in range(0,int(self.parm1_var.get())):
            x=0
            y=0
            if self.color_code == 0:
                tk_rgb = "#%02x%02x%02x" % (randint(0,255), randint(0,255),
                                        randint(0,255))
            else:
                tk_rgb = ['null','blue','black','red','green'][self.color_code]
            for r in range(1,100):
                theta=1000.0/r**2 - 2*k*pi/self.parm1_var.get()
                new_x = r*sin(theta)*4
                new_y = r*cos(theta)*4
                self.canvas.create_line(x+400,y+400,new_x+400,new_y+400,
                                        fill=tk_rgb)
                x = new_x
                y = new_y
            sleep(0.1)
            self.canvas.update()
        for k in range(0,int(self.parm1_var.get())):
            x=0
            y=0
            if self.color_code == 0:
                tk_rgb = "#%02x%02x%02x" % (randint(0,255), randint(0,255),
                                        randint(0,255))
            else:
                tk_rgb = ['null','blue','black','red','green'][self.color_code]
            for r in range(1,100):
                theta=-(1000.0/r**2 - 2*k*pi/self.parm1_var.get())
                new_x = r*sin(theta)*4
                new_y = r*cos(theta)*4
                self.canvas.create_line(x+400,y+400,new_x+400,new_y+400,
                                        fill=tk_rgb)
                x = new_x
                y = new_y
            sleep(0.1)
            self.canvas.update()
    def menu_2(self):
        self.parm1_var.set(2)
        self.clear()
    def menu_3(self):
        self.parm1_var.set(3)
        self.clear()
    def menu_4(self):
        self.parm1_var.set(4)
        self.clear()
    def menu_5(self):
        self.parm1_var.set(5)
        self.clear()
    def menu_6(self):
        self.parm1_var.set(6)
        self.clear()
    def menu_7(self):
        self.parm1_var.set(7)
        self.clear()
    def menu_8(self):
        self.parm1_var.set(8)
        self.clear()
    def menu_9(self):
        self.parm1_var.set(9)
        self.clear()
    def menu_10(self):
        self.parm1_var.set(10)
        self.clear()
    def menu_11(self):
        self.parm1_var.set(11)
        self.clear()
    def menu_12(self):
        self.parm1_var.set(12)
        self.clear()
if __name__ == '__main__':
    root = Tk()
    root.wm_title('Various kinds of Spirals')
    app = App(root)
    root.mainloop()