#!/usr/bin/python3
# ===================================================================
# How High is the Mountain - Draw Diagram From User Input
# ===================================================================
import sys
import draw_axes as ax
import coordinate_conversion as cc
import user_interface as ui
import graphics as gr
from math import radians, sin, cos
# ---- input ranges
flight_altitude_min = 10000
flight_altitude_max = 80000
measure_distance_min = 1000
measure_distance_max = 20000
angle_alpha_min = 10
angle_alpha_max = 80
angle_beta_min = 10
angle_beta_max = 80
# ---- graphics window
wwidth = 801 # (pixels) window width
wheight = 801 # (pixels) window height
maxxy = 300 # (pixels) diagram max x,y pixels
# max distance from the origin 0,0
# ---- explanation
explanation = f'''
This program will calculate and then draw a diagram that show the
height of a mountain based on the user's input. Ridiculous input
data will result in ridiculous output.
{flight_altitude_min:>6} < flight altitude < {flight_altitude_max:<6}
{measure_distance_min:>6} < measure distance < {measure_distance_max:<6}
{angle_alpha_min:>6} < angle alpha < {angle_alpha_max:<6}
{angle_beta_min:>6} < angle beta < {angle_beta_max:<6}
'''
# -------------------------------------------------------------------
# ---- prompt for user input
# -------------------------------------------------------------------
def user_input(min,max,prompt):
while(True):
print()
s = ui.get_user_input(prompt)
if not s:
return(False,0)
x,n = ui.is_float(s)
if not x:
print()
print('unknown value enter - try again')
continue
if n < min:
print()
print(f'value must be > {min} - try again')
continue
if n > max:
print()
print('value must < {max} - try again')
continue
return(True,n)
# -------------------------------------------------------------------
# ---- get all user input
# -------------------------------------------------------------------
def get_all_user_input(explanation = None):
ui.clear_screen()
if explanation:
print(explanation)
# ---- flight altitude
x,n = user_input(flight_altitude_min,
flight_altitude_max,
'Enter flight altitude (ft): ')
if not x:
return(False,0,0,0,0)
flight_altitude = n
# ---- measure distance
flight_altitude = n
# ---- measure distance
x,n = user_input(measure_distance_min,
measure_distance_max,
'Enter measure distance (ft): ')
if not x:
return(False,0,0,0,0)
measure_distance = n
# ---- angle alpha
x,n = user_input(angle_alpha_min,
angle_alpha_max,
'Enter angle alpha (deg): ')
if not x:
return(False,0,0,0,0)
angle_alpha = n
# ---- angle beta
x,n = user_input(angle_beta_min,
angle_beta_max,
'Enter angle beta (deg): ')
if not x:
return(False,0,0,0,0)
angle_beta = n
# ---- return user input
return(True,flight_altitude,measure_distance,
angle_alpha,angle_beta)
# -------------------------------------------------------------------
# ---- calculation beta angle x and y
# -------------------------------------------------------------------
def calculation(flight_altitude,
measure_distance,
angle_alpha,
angle_beta):
angle_gamma = 180 - angle_alpha - angle_beta
alpha_rad = radians(angle_alpha)
beta_rad = radians(angle_beta)
gamma_rad = radians(angle_gamma)
gamma_hypotenuse = (sin(alpha_rad) * measure_distance) / sin(gamma_rad)
beta_x = sin(beta_rad) * gamma_hypotenuse
beta_y = cos(beta_rad) * gamma_hypotenuse
return(beta_x, beta_y)
# -------------------------------------------------------------------
# ---- draw diagram
# -------------------------------------------------------------------
def draw_diagram(flight_altitude, measure_distance, beta_x, beta_y):
# ---------------------------------------------------------------
# ---- draw a point
# ---------------------------------------------------------------
def draw_point(win,x,y,raidus=5,color='black'):
wx,wy = cc.center_to_win_coords(x,y,wwidth,wheight)
c = gr.Circle(gr.Point(wx,wy),raidus)
c.setFill(color)
c.draw(win)
# ---------------------------------------------------------------
# ---- draw a line
# ---------------------------------------------------------------
def draw_line(win,x0,y0,x1,y1,width=3,color='black'):
wx0,wy0 = cc.center_to_win_coords(x0,y0,wwidth,wheight)
wx1,wy1 = cc.center_to_win_coords(x1,y1,wwidth,wheight)
c = gr.Line(gr.Point(wx0,wy0),gr.Point(wx1,wy1))
c.setWidth(width)
c.setFill(color)
c.draw(win)
# ---------------------------------------------------------------
# ---- add text to window
# ---------------------------------------------------------------
def add_text(win,x,y,txt):
wx,wy = cc.center_to_win_coords(x,y,wwidth,wheight)
t = gr.Text(gr.Point(wx,wy),txt)
t.setSize(20)
t.draw(win)
# ---------------------------------------------------------------
# ---- scale coordinates to fit the diagram in the window
# ---- center the diagram so that the beta angle
# ---- x coordinate is 0 and the y coordinate is 1/2 of beta_y
# ---------------------------------------------------------------
def scale_point_coords(maxxy,measure_distance,beta_x,beta_y):
# ---- calculate coordinates
x0 = -(measure_distance - beta_x)
y0 = beta_y / 2.0
x1 = beta_x
y1 = beta_y / 2.0
x2 = 0.0
y2 = -beta_y / 2.0
# ---- calculate the scale factor to fit diagram
# ---- in the graphics window
max_coord = 0.0
if abs(x0) > max_coord:
max_coord = abs(x0)
if abs(y0) > max_coord:
max_coord = abs(y0)
if abs(x1) > max_coord:
msx_coord = abs(x1)
if abs(y1) > max_coord:
max_coord = abs(y1)
if abs(x2) > max_coord:
max_coord = abs(x2)
if abs(y2) > max_coord:
max_coord = abs(y2)
scale = maxxy / max_coord
print(f'scale factor : {round(scale,6)}')
# ---- round and scale coordinates
x0 = round(x0 * scale)
y0 = round(y0 * scale)
x1 = round(x1 * scale)
y1 = round(y1 * scale)
x2 = round(x2 * scale)
y2 = round(y2 * scale)
return (x0,y0,x1,y1,x2,y2)
# ---- create graphics window
win = gr.GraphWin("How high is the mountain?",wwidth,wheight)
win.setBackground("white")
# ---- draw x,y axes
ax.draw_xy_axes(win,True)
# ---- calculate the triangle point coordinates
# ---- round coordinates and scale to fit in the window
x0,y0,x1,y1,x2,y2 = scale_point_coords(maxxy,
measure_distance,
beta_x,
beta_y)
print(f'point x0 : {x0:<8} (pix)')
print(f'point y0 : {y0:<8} (pix)')
print(f'point x1 : {x1:<8} (pix)')
print(f'point y1 : {y1:<8} (pix)')
print(f'point x2 : {x2:<8} (pix)')
print(f'point y2 : {y2:<8} (pix)')
draw_point(win,x0,y0)
draw_point(win,x1,y1)
draw_point(win,x2,y2)
draw_line(win,x0,y0,x1,y1)
draw_line(win,x1,y1,x2,y2)
draw_line(win,x2,y2,x0,y0)
# ---- add text to window
add_text(win,0,y0+20,str(flight_altitude)+' ft')
add_text(win,x0,y0+20,'alpha')
add_text(win,x1,y1+20,'beta')
add_text(win,x2,y2-40,'mountain top\n' +
str(flight_altitude - beta_y) + ' ft')
# ---- pause then proceed
ui.pause()
win.close()
# -------------------------------------------------------------------
# ---- main
# -------------------------------------------------------------------
if __name__ == '__main__':
(x,flight_altitude,measure_distance,
angle_alpha,angle_beta) = get_all_user_input(explanation)
if not x:
print()
sys.exit()
print()
print(f'flight altitude : {flight_altitude:<8} (ft)')
print(f'measure distance: {measure_distance:<8} (ft)')
print(f'angle alpha : {angle_alpha:<8} (deg)')
print(f'angle beta : {angle_beta:<8} (deg)')
beta_x,beta_y = calculation(flight_altitude,
measure_distance,
angle_alpha,
angle_beta)
beta_x = round(beta_x,1)
beta_y = round(beta_y,1)
print(f'angle beta x : {beta_x:<8} (ft)')
print(f'angle beta y : {beta_y:<8} (ft)')
draw_diagram(flight_altitude,measure_distance,beta_x,beta_y)
print()