solution_040.py

#!/usr/bin/python3
# ===================================================================
# Draw spirograph
#
# The following is left for the student complete:
#   Convert this program to draw a lines rather than points
# ===================================================================

import sys
import graphics as gr
import draw_axes as ax
import user_interface as ui
import coordinate_conversion as cc
from time import sleep
from math import radians, sin, cos

window_width  = 801
window_height = 801

color = ['red','green','blue','black','purple']

R = 160                        # default raidus of large circle
r =  20                        # default raidus of small circle
d =  60                        # default distance from drawing point
                               #   to center of small circle

# -------------------------------------------------------------------
# --- calculate x,y coordinates of the spirograph drawing point
# --- return x,y as integers
# -------------------------------------------------------------------

def xy_coords(a,R,r,d):

    rad = radians(a)

    x = ((R-r)*cos(rad)) + (d*cos(((R-r)/r)*rad))
    y = ((R-r)*sin(rad)) + (d*sin(((R-r)/r)*rad))

    return (round(x),round(y))

# -------------------------------------------------------------------
# ---- draw a line
# -------------------------------------------------------------------

def draw_line(win,x1,y1,x2,y2,color):

    wx1,wy1 = cc.center_to_win_coords(x1,y1,
              window_width,window_height)
    wx2,wy2 = cc.center_to_win_coords(x2,y2,
              window_width,window_height)

    l = gr.Line(gr.Point(wx1,wy1),gr.Point(wx2,wy2))
    l.setWidth(3)
    l.setFill(color)
    l.draw(win)

# ---------------------------------------------------------------
# ---- draw a point
# ---------------------------------------------------------------

def draw_point(win,x,y,raidus=3,color='black'):

    wx,wy = cc.center_to_win_coords(x,y,win.width,win.height)
    c = gr.Circle(gr.Point(wx,wy),raidus)
    c.setFill(color)
    c.draw(win)

# -------------------------------------------------------------------
# ---- draw spirograph design
# -------------------------------------------------------------------
 
def draw_spirograph(win,R,r,d):

    a = 0

    startx,starty = xy_coords(a,R,r,d)

    draw_point(win,startx,starty)

    while True:

        a += 1

        x,y = xy_coords(a,R,r,d)

        if startx == x and starty == y:
            break

        draw_point(win,x,y)

        sleep(0.01)

# -------------------------------------------------------------------
# ---- get it from the user
# -------------------------------------------------------------------

def get_it_from_the_user(prompt,default):

    ui.clear_screen()
    print()
    print('Enter nothing for default value')
    print('Enter q or Q to quit program')

    while(True):

        print()
        s = ui.get_user_input(prompt)

        if not s:
            return default

        if s[0] == 'q' or s[0] == 'Q':
            print()
            sys.exit()

        x,n = ui.is_integer(s)

        if not x or n < 1:
            print()
            print('Illegal input value - try again')
            continue

        return n


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

if __name__ == '__main__':

    R = get_it_from_the_user(f'Enter large circle raidus [{R}]: ',R)
    r = get_it_from_the_user(f'Enter small circle raidus [{r}]: ',r)
    d = get_it_from_the_user(f'Enter drawing point distance [{d}]: ',d)

    win = gr.GraphWin("Spirograph Design",window_width,window_height)
    win.setBackground("white")

    ax.draw_xy_axes(win,True)

    draw_spirograph(win,R,r,d)

    ui.pause()
    win.close()

    print()