solution_139.py

#!/usr/bin/python3
# ====================================================================
# draw the golden ratio spiral
#
# use Catesian coordinates
#
#           |
#      Q2   |   Q1
#   --------+--------
#      Q3   |   Q4
#           |
#
# Note: A golden spiral gets wider (or further from its origin)
# by a factor of φ for every quarter turn it makes. 
# ====================================================================

import math
from graphics import *
import coordinate_conversion as cc

GOLDENRATIO = (1 + math.sqrt(5))/2


# -------------------------------------------------------------------
# ---- draw X,Y axes (center/Cartesian coordinates)
# -------------------------------------------------------------------

def draw_xy_axes(win,linewidth=1,linecolor="black"):

    wx  = win.width            # window width
    wy  = win.height           # window height
    wcx = round(wx/2.0)        # window center X
    wcy = round(wy/2.0)        # window center Y

    # ---- X axis

    xl = Line(Point(0,wcy),Point(wx-1,wcy))
    xl.setWidth(linewidth)
    xl.setFill(linecolor)
    xl.draw(win)

    # ---- Y axis

    yl = Line(Point(wcx,0),Point(wcx,wy-1))
    yl.setWidth(linewidth)
    yl.setFill(linecolor)
    yl.draw(win)

# -------------------------------------------------------------------
# ---- draw a circle
# -------------------------------------------------------------------
# ---- win   graphics window
# ---- pt    graphics point
# ---- dia   circle diameter
# ---- color circle color
#--------------------------------------------------------------------

def draw_circle(win,x,y,dia=3,color='black'):

    x = round(x)
    y = round(y)

    wx,wy = cc.center_to_win_coords(x,y,win.width,win.height)

    if wx < 0 or wx > win.width or wy < 0 or wy > win.height:
        return None
    
    c = Circle(Point(wx,wy),dia)
    c.setFill(color)
    c.setOutline(color)
    c.setWidth(1)
    c.draw(win)
    return c

# ------------------------------------------------------------------
# ---- draw a line
# ------------------------------------------------------------------
# ---- win       graphics window
# ---- cx1       start of line X coordinate
# ---- cy1       start of line Y coordinate
# ---- cx2       end   of line X coordinate
# ---- cy2       end   of line Y coordinate
# ---- ll        leg length (for documentation only)
# ---- linewidth line width (pixels)
# ---- linecolor line color
#--------------------------------------------------------------------

def draw_line(win,cx1,cy1,cx2,cy2,ll=None,
             linewidth = 2, linecolor="black"):
    
    wx1,wy1 = cc.center_to_win_coords(cx1,cy1,win.width,win.height)
    wx2,wy2 = cc.center_to_win_coords(cx2,cy2,win.width,win.height)
    
    l = Line(Point(wx1,wy1),Point(wx2,wy2))
    l.setWidth(linewidth)
    l.setFill(linecolor)
    l.draw(win)
    return l

# ------------------------------------------------------------------
# ---- draw quarter of circle (90 degrees)
# ------------------------------------------------------------------

def draw_quarter(win,start_ang,start_len,steps=10):

    start_ang = start_ang % 360.0

    delta_a = 90.0/steps

    end_len = start_len * GOLDENRATIO
    
    delta_l = (end_len - start_len)/steps
   
    i = 0
    while i < steps:

        a = start_ang + (delta_a * i)
        l = start_len + (delta_l * i)

        x = l * math.cos(math.radians(a)) 
        y = l * math.sin(math.radians(a))

        if draw_circle(win,x,y) is None:
            return -1

        i += 1

    return end_len      # ending length; new starting length


# ------------------------------------------------------------------
# ---- main
# -------------------------------------------------------------------

if __name__ == '__main__':

    # ---- create graphics window

    win = GraphWin("Golden Ratio", 801, 801)
    win.setBackground("white")

    draw_xy_axes(win)

    # ---- draw spirial

    a = 0
    l = 30
    s = 5

    while True:
    
       l = draw_quarter(win,a,l,s)

       if l < 0:
           break

       a = a + 90
       s = s + 5

    # ---- pause for click in window
    
    win.getMouse()
    win.close()