solution_101.py

#!/usr/bin/python3
# ===================================================================
# googly eyes - centered around the center of the window
#
# Note:
#  1. all coordinates are window coordinates with the origin
#     (0,0) in the upper left corner of the window
#  2. window x increases right and window y increases down
#  3. window pixels have integer coordinates
# ===================================================================

import math
import numpy
import graphics as gr


eye_color  = 'white'
iris_color = 'black'


# ---- window coordinates

win_width          = 800
win_height         = 800
win_x_center       = round(win_width/2)
win_y_center       = round(win_height/2)

eye_radius         = 100
eye_distance       = 2*eye_radius + 100 # distance between center of eyes

left_eye_x_center  = win_x_center - round(eye_distance/2)
left_eye_y_center  = win_y_center
right_eye_x_center = win_x_center + round(eye_distance/2)
right_eye_y_center = win_y_center

iris_radius        = eye_radius/4
iris_distance      = eye_radius/2

# Note: iris_distance is the distance from the center of the
#       eye to the center of the iris. this is a fixed distance
#       for all irises.

reset_button       = [1, 1,80, 30]
exit_button        = [81,1,161,30]
click_coords       = [1,31,161,60]


# -------------------------------------------------------------------
# create eyes and irises
# -------------------------------------------------------------------

def create_eyes(win):

    # ---- left eye

    lex = win_x_center - int(eye_distance/2)   # left eye x
    ley = win_y_center                         # left eye y

    c = gr.Circle(gr.Point(lex,ley),eye_radius)
    c.setFill(eye_color)
    c.setOutline('black')
    c.setWidth(2)
    c.draw(win)

    # ---- right eye

    rex = win_x_center + int(eye_distance/2)   # right eye x
    rey = win_y_center                         # right eye y

    c = gr.Circle(gr.Point(rex,rey),eye_radius)
    c.setFill(eye_color)
    c.setOutline('black')
    c.setWidth(2)
    c.draw(win)

    # ---- left iris

    li = gr.Circle(gr.Point(lex,ley),iris_radius)
    li.setFill(iris_color)
    li.draw(win)

    # ---- right iris
    
    ri = gr.Circle(gr.Point(rex,rey),iris_radius)
    ri.setFill(iris_color)
    ri.draw(win)
               
    return (li,ri)


# --------------------------------------------------------------------
#  reset the eye's irises
# --------------------------------------------------------------------

def reset_irises(win,irises):

    # ---- left iris reset

    p = irises[0].getCenter()
    x = p.getX()
    y = p.getY()

    dx = left_eye_x_center - x
    dy = left_eye_y_center - y

    irises[0].move(dx,dy)

    # ---- left iris reset

    p = irises[1].getCenter()
    x = p.getX()
    y = p.getY()

    dx = right_eye_x_center - x
    dy = right_eye_y_center - y

    irises[1].move(dx,dy)

    return

# -------------------------------------------------------------------
# move irises for testing
# -------------------------------------------------------------------

def test_move_irises(win,irises,dx=None,dy=None):

    if dx is None:
        dx = 40

    if dy is None:
        dy = 40

    irises[0].move(dx,dy)
    irises[1].move(-dx,-dy)

# -------------------------------------------------------------------
# move irises
# -------------------------------------------------------------------
# remember:
#  1. window x increases right and window y increases down
#  2. window pixels have integer coordinates
# -------------------------------------------------------------------

def focus_irises(irises,clickx,clicky):

    # ---- click-point to center-of-left-eye (triangle hypotenuse)

    dx = clickx - left_eye_x_center
    dy = clicky - left_eye_y_center

    h = math.sqrt(dx**2 + dy**2)

    # ---- left eye iris new coordinates using similar triangles

    newx = (dx/h * iris_distance) + left_eye_x_center
    newy = (dy/h * iris_distance) + left_eye_y_center

    # left eye iris old coordinates 

    oldx = irises[0].getCenter().getX()
    oldy = irises[0].getCenter().getY()

    # move left eye iris
    
    irises[0].move(round(newx-oldx),round(newy-oldy))

    # ---- click-point to center-of-right-eye (triangle hypotenuse)
    
    dx = clickx - right_eye_x_center
    dy = clicky - right_eye_y_center

    h = math.sqrt(dx**2 + dy**2)
    
    # ---- right iris new coordinates using similar triangles

    newx = (dx/h * iris_distance) + right_eye_x_center
    newy = (dy/h * iris_distance) + right_eye_y_center

    # right eye iris old coordinates

    oldx = irises[1].getCenter().getX()
    oldy = irises[1].getCenter().getY()

    # move right eye iris
    
    irises[1].move(round(newx-oldx),round(newy-oldy))

# -------------------------------------------------------------------
# ---- draw buttons
# -------------------------------------------------------------------

def draw_buttons(win):

    # ---- reset button

    b1 = gr.Rectangle(gr.Point(reset_button[0],reset_button[1]),
                      gr.Point(reset_button[2],reset_button[3]))
    b1.setOutline('black')
    b1.setWidth(2)
    b1.draw(win)
    
    b1txt = gr.Text(b1.getCenter(),"RESET")
    b1txt.setStyle("bold")
    b1txt.draw(win)

    # ---- exit button
    
    b2 = gr.Rectangle(gr.Point(exit_button[0],exit_button[1]),
                      gr.Point(exit_button[2],exit_button[3]))
    b2.setOutline('black')
    b2.setWidth(2)
    b2.draw(win)
    
    b1txt = gr.Text(b2.getCenter(),"Exit")
    b1txt.setStyle("bold")
    b1txt.draw(win)

    # ---- click coordinates

    ck = gr.Rectangle(gr.Point(click_coords[0],click_coords[1]),
                      gr.Point(click_coords[2],click_coords[3]))
    ck.setOutline('black')
    ck.setWidth(2)
    ck.draw(win)
    
    return ck

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

if '__main__' == __name__:

    # ---- create graphics window

    win = gr.GraphWin("Googly Eyes", win_width, win_height)

    ck = draw_buttons(win)

    # ---- draw googly eyes

    irises = create_eyes(win)

    # ---- initial click text

    cktxt = gr.Text(ck.getCenter(),f'click coords')
    cktxt.setStyle("bold")
    cktxt.draw(win)

    # ---- main graphics loop
    
    while(True):

        click = win.getMouse()

        x = click.getX()
        y = click.getY()

        # ---- in reset button?

        if (x > reset_button[0]) and (x < reset_button[2]) and \
           (y > reset_button[1]) and (y < reset_button[3]):
               ##print('Reset')
               reset_irises(win,irises)
               continue

        # ---- in exit button?

        if (x > exit_button[0]) and (x < exit_button[2]) and \
           (y > exit_button[1]) and (y < exit_button[3]):
               ##print('Exit')
               break

        # ---- report click coords

        ##print(f'x = {x}, y = {y}')
        cktxt.undraw()
        cktxt.setText(f'x = {x}, y = {y}')
        cktxt.draw(win)

        ##test_move_irises(win,irises)

        # ---- focus irises on clicked coordinates

        focus_irises(irises,x,y)

    win.close()    # Close window when done