#!/usr/bin/python3
# ==============================================================
# draw a Theodorus spiral (a square root spiral)
# ==============================================================
import graphics as gr
import coordinate_conversion as cc
import math
import sys
DEBUG = False
ORIGIN_LINES = False
# --------------------------------------------------------------
# ---- convert polar to Cartesian coordinate systems
# --------------------------------------------------------------
def polar2cart(rho:[int|float],phi:[int|float]) -> tuple:
'''
polar to Cartesian
'''
x = rho * math.cos(phi)
y = rho * math.sin(phi)
return (x,y)
# --------------------------------------------------------------
# ---- create a graphics window
# --------------------------------------------------------------
def create_a_graphics_window(width:[int|float],
height:[int|float],
axes:bool=False,
title:str='Graph') -> gr.GraphWin:
'''
create graphics window and maybe Cartesian axes
'''
# ---- create window
win = gr.GraphWin(title,width,height)
win.setBackground("white")
# ---- draw axes?
if axes:
# ---- X,Y axes origin in window coordinates
xaxis = round(width/2.0)
yaxis = round(height/2.0)
# ---- draw X axis (line)
xl = gr.Line(gr.Point(0,yaxis),gr.Point(width-1,yaxis))
xl.setWidth(1)
xl.setFill("black")
xl.draw(win)
# ---- draw Y axis (line)
yl = gr.Line(gr.Point(xaxis,0),gr.Point(xaxis,height-1))
yl.setWidth(1)
yl.setFill("black")
yl.draw(win)
return win
# --------------------------------------------------------------
# ---- create a list of points on a square root spiral
# ---- return polar coordinates
# ----
# ---- format (tuple):
# ---- [0] radial distance
# ---- [1] triangle polar angle (degrees)
# ---- [2] triangle polar angle (radians)
# ---- [3] triangle hypotenuse using a and b
# ---- (next triangle's b value)
# --------------------------------------------------------------
# ---- angle x
# ----
# ---- + sin(x) = a/h
# ---- /| cos(x) = b/h
# ---- / |
# ---- h / | a h = math.sqrt(a**2 + b**2)
# ---- / |
# ---- / | x = atan(a/b) x = atan2(x,y)
# ---- / x | x = asin(a/h)
# ---- +------+ x = acos(b/h)
# ---- b
# ----
# --------------------------------------------------------------
def create_square_root_spiral_points(loops:int=17) -> list:
'''
create a list of points on a square root spiral
'''
pts = [] # list of spiral point
# ---- calculate each of the spiral points
for loop in range(0,loops):
# ---- loop == 0 is the initial spiral point
# ---- on the x axes
if loop == 0:
a = 0.0 # side opposite the angle
b = 1.0 # side adjacent to the angle
hyp = 1.0 # hypotenuse (triangle)
rad = 0.0 # angle in radians (triangle)
deg = 0.0 # angle in degrees (triangle)
dst = 1.0 # radial distance (polar coordinate)
else:
a = 1.0
b = math.sqrt(loop)
hyp = math.sqrt(a**2 + b**2)
rad = math.asin(a/hyp)
deg = math.degrees(rad)
dst = math.sqrt(loop + 1)
if DEBUG:
print()
print(f'loop {loop}')
print(f'a ={a:.6f} b={b:.6f} hyp={hyp:.6f}')
print(f'dst={dst:.6f} deg={deg:.6f} rad={rad:.6f}')
pts.append((dst,rad,deg,hyp))
return pts
# --------------------------------------------------------------
# ---- draw a spiral (this code is incomplete. finish it.)
# --------------------------------------------------------------
def draw_spiral(win:gr.GraphWin,pts:list) -> None:
accmulated_angle = 0.0
previous_point = None
for pt in pts:
accmulated_angle += pt[1]
x,y = polar2cart(pt[0],accmulated_angle)
x = x*75 # scale the coordinate
y = y*75 # scale the coordinate
# ---- convert point cartesian coords to window coords
wx1,wy1 = cc.center_to_win_coords(x,y,
win.width,win.height)
# ---- draw a line (from point to point)
if previous_point is not None:
l = gr.Line(gr.Point(wx1,wy1),previous_point)
l.setWidth(1)
l.setFill('black')
l.draw(win)
# ---- draw a line (from point to origin)
if ORIGIN_LINES:
wx2,wy2 = cc.center_to_win_coords(0.0,0.0,
win.width,win.height)
l = gr.Line(gr.Point(wx1,wy1),gr.Point(wx2,wy2))
l.setWidth(1)
l.setFill('black')
l.draw(win)
# ---- draw a point (circle)
c = gr.Circle(gr.Point(wx1,wy1),4)
c.setFill('red')
c.draw(win)
# ---- save the current point
previous_point = gr.Point(wx1,wy1)
return
# --------------------------------------------------------------
# ---- main
# --------------------------------------------------------------
if __name__ == '__main__':
# ---- square root spirial plot/drawing points
pts = create_square_root_spiral_points()
# ---- graphics window
win = create_a_graphics_window(801,801,axes=False,
title="Theodorus (Square Root) Spiral")
# ---- draw a Theodorus (square root) spiral
draw_spiral(win,pts)
# ---- wait for a mouse click in the window, then exit
click = win.getMouse()
win.close()
sys.exit()