#!/usr/bin/python3 # ==================================================================== # given three (2D) points, calculate the 2D angle formed by them # ===================================================================== import sys import numpy as np import user_interface as ui interactive_description = r''' ------------------------------------------------------------ In interactive mode, the origin (0,0,0) is asummed to be the middle point used in the calculation (point B). A / / B \ \ C Points A are C entered by the user and the angle calculated. The smaller angle is returned - no angles over 180 degrees is returned if an error occurs 0.0 is returned ------------------------------------------------------------ ''' # -------------------------------------------------------------------- # ---- get 2D angle in degrees from three points a,b,c # -------------------------------------------------------------------- def get_2d_angle(a, b, c): try: v0 = np.array(a) - np.array(b) v1 = np.array(c) - np.array(b) ang = np.math.atan2(np.linalg.det([v0,v1]),np.dot(v0,v1)) ang = np.degrees(ang) except: ang = 0.0 return abs(ang) # -------------------------------------------------------------------- # ---- pre-defined angle tests # -------------------------------------------------------------------- def predefined_angle_tests(): tests_2d = [ [ 'counter clockwise (positive angles)'], [ (5,0), (0,0),(5,0), 'g. Test 0 degrees' ], [ (5,-5), (0,0),(5,0), 'a. Test 45 degrees' ], [ (0,-5), (0,0),(5,0), 'b. Test 90 degrees' ], [ (-5,-5),(0,0),(5,0), 'c. Test 135 degrees' ], [ (-5,0), (0,0),(5,0), 'd. Test 180 degrees' ], [ (-5,5), (0,0),(5,0), 'e. Test 225 degrees' ], [ (0,5), (0,0),(5,0), 'f. Test 270 degrees' ], [ (5,5), (0,0),(5,0), 'g. Test 315 degrees' ], [ (5,0), (0,0),(5,0), 'g. Test 360 degrees' ], [ 'special case tests - illegal points/angles' ], [ (0,0),(0,0),(0,0), 'b. Test (0,0,0) point' ], [ (5,5),(5,5),(5,5), 'c. Test (5,5,0) point' ], [ 'clockwise (negtave angles)'], [ (5,0),(0,0),(5,-5), 'a. Test -45 degrees' ], [ (5,0),(0,0),(0,-5), 'b. Test -90 degrees' ], [ (5,0),(0,0),(-5,-5), 'c. Test -135 degrees' ], [ (5,0),(0,0),(-5,0), 'd. Test -180 degrees' ], [ (5,0),(0,0),(-5,5), 'e. Test -225 degrees' ], [ (5,0),(0,0),(0,5), 'f. Test -270 degrees' ], [ (5,0),(0,0),(5,5), 'g. Test -315 degrees' ], ] print('----------------------------------------------------') print('test various angles and rotations') print(' (vector a to vector b) and (vector b to vector a)') print('----------------------------------------------------') for t in tests_2d: if len(t) < 4: print() for tt in t: print(f'---- {tt}') continue print() print(f'---- {t[3]}') ang,aang = get_2d_angle(t[0],t[1],t[2]) print(f'returned ang = {ang:<7.2f} ' + f'aang = {aang:<7.2f} degrees') # -------------------------------------------------------------------- # ---- ask the user for a point's coordinates # -------------------------------------------------------------------- def get_point_coordinates(title): print() print(title) while True: print() s = ui.get_user_input('Enter x,y coordinates: ') if not s: sys.exit() s = s.replace(',', ' ') s = s.replace(r'/', ' ') s = s.replace(':', ' ') sx,sy = s.split() tf,x = ui.is_float(sx) if not tf: print('bad X coord entered') continue tf,y = ui.is_float(sy) if not tf: print('bad y coord entered') continue return (x,y) # -------------------------------------------------------------------- # ---- interactive angle calculation tests # -------------------------------------------------------------------- def interactive_angle_tests(center_point): print(interactive_description) while True: a = get_point_coordinates( 'Enter x,y coordinates for point A') c = get_point_coordinates( 'Enter x,y coordinates for point C') ang = get_2d_angle(a,center_point,c) print() print(f'Angle is {ang:.4} degrees') ##ui.pause() # -------------------------------------------------------------------- # ---- main # -------------------------------------------------------------------- if __name__ == '__main__': # ---- pre defined lat/lon test ##predefined_angle_tests() # ---- interactive lat/lon test interactive_angle_tests((0,0))