solution_031f.py

#!/usr/bin/python3
# ===================================================================
# Finding out if a particular star is in the area-of-interest
# (AOI) is a problem. The coordinates (lat/lon) are not consistent
# (lon is 0 to 360 and lat is -90 to +90) and must be "fiddled"
# with in code to overcome this inconsistency.
# -------------------------------------------------------------------
# This code test if a star's lat/lon is in the area-of-interest (AOI)
# a. Pretend the point-of-interest (POI) has been rotated
#    until it is on the +Z axes. (-poilat,-poilon)
# b. The AIO is now centered on the new POI (lat=0,lon=0).
# c. The other stars are rotated relative to the new POI
#    for testing. (Rotated the same amount as the POI.)
# d. To see if a star is in the AOI, pretend rotate it's lat/lon
#    relative to the new POI (and AOI) and test. Is it in or out.
# e. Because of the lat/lon coordinate system are not consistent,
#    the calculations will give you "funny" numbers. However,
#    you can still test.
# -------------------------------------------------------------------
# The lat/lon coordinate system is inconsistent, but it is
# good for astronomy. (lon is 0 to 360 and lat is -90 to +90)
# ===================================================================

import user_interface as ui
import sys, os, platform
from math import radians, sin, cos

win_width         = 801        # graphics window width  (pixels)
win_height        = 801        # graphics window height (pixels)

min_poi_latitude  = -90.0      # degrees
max_poi_latitude  = +90.0      # degrees
min_poi_longitude = +0.0       # degrees
max_poi_longitude = +360.0     # degrees
min_poi_size      = +2.0       # degrees
max_poi_size      = +20.0      # degrees

# -------------------------------------------------------------------
# ---- get user's Point of Interest (POI)
# -------------------------------------------------------------------

def get_user_poi():

    ui.clear_screen()

    # --- galactic longitude

    print()
    print('Enter POI galactic longitude in degrees (0.0 to 360.0)')
    print('Enter nothing to exit program')

    while(True):

        print()
        s = ui.get_user_input('Enter POI longitude: ')

        if not s:
            sys.exit()

        tf,poilon = ui.is_float(s)

        if tf != True                  or \
           poilon < min_poi_longitude  or \
           poilon > max_poi_longitude:
           print('illegal longitude - try again')
           continue

        break

    # ---- poi latitude

    print()
    print('Enter POI galactic latitude in degrees (-90.0 to +90.0)')
    print('Enter nothing to exit program')

    while(True):

        print()
        s = ui.get_user_input('Enter POI Latitude: ')

        if not s:
            sys.exit()

        tf,poilat = ui.is_float(s)

        if tf != True                 or \
            poilat < min_poi_latitude or \
            poilat > max_poi_latitude:
            print()
            print('illegal latitude - try again')
            continue

        break

    # ---- poi size

    print()
    print('Enter POI size in degrees (2.0 > size <= 20.0)')
    print('Enter nothing to exit program')

    while(True):

        print()
        s = ui.get_user_input('Enter POI size: ')

        if not s:
            sys.exit()

        tf,poisize = ui.is_float(s)

        if tf != True              or \
            poisize < min_poi_size or \
            poisize > max_poi_size:
            print()
            print('illegal latitude - try again')
            continue

        break

    return (poilat,poilon,poisize)

# -------------------------------------------------------------------
# ---- convert galactic lat/lon to x,y,z coordinates
# ---- (unit vector is radius of sphere)
# -------------------------------------------------------------------

def lat_lon_to_xyz(glat,glon,scale=1.0):

    rlat = radians(glat)       # convert to radians
    rlon = radians(glon)       # convert to radians

    x = sin(rlat) * cos(rlon)
    y = sin(rlat)
    z = cos(rlat) * cos(rlon)

    return (x*scale, y*scale, z*scale)

# -------------------------------------------------------------------
# ---- rotate a star's lat/lon so it is relative to the POI
# ---- as if the POI were on the +Z axis
# -------------------------------------------------------------------

def rotate_lat_lon_to_z_axis(lat,lon,poilat,poilon):

   newlat = lat - poilat
   newlon = lon - poilon
    
   print()
   print(f'new lat = {newlat}')
   print(f'new lon = {newlon}')

   return (newlat,newlon)

# -------------------------------------------------------------------
# ---- get lat/lon to test POI rotation
# -------------------------------------------------------------------

def get_test_lat_lon():

    while(True):
        print()
        s = ui.get_user_input('Enter test lon (0 to 360): ')
        if not s:
            sys.exit()
        tf,lon = ui.is_float(s)
        if not tf:
            print('bad input')
            continue
        break

    while(True):
        print()
        s = ui.get_user_input('Enter test lat (-90 to +90): ')
        if not s:
            sys.exit()
        tf,lat = ui.is_float(s)
        if not tf:
            print('bad input')
            continue
        break

    return (lat,lon)

# -------------------------------------------------------------------
# ---- is test lat/lon (star) in area-if-interest AIO
# -------------------------------------------------------------------

def in_area_of_interest(tlat,tlon,poilat,poilon,poisiz):

   halfsiz = poisiz / 2.0

   aio_min_lat = poilat - halfsiz 
   aio_max_lat = poilat + halfsiz
   aio_min_lon = poilon - halfsiz
   aio_max_lon = poilon + hanfsiz

   newlat = tlat - poilat
   newlon = tlon - poilon

   print()
   print(f'new lat = {newlat}')
   print(f'new lon = {newlon}')

   return (newlat,newlon)

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

if __name__ == '__main__':

    # ---- get the user's point of interest (POI)

    poilat,poilon,poisiz = get_user_poi()

    # ---- calculate the area-of-interest after rotating
    # ---- the POI until it is on the +Z axes

    aio_min_lat = -poisiz/2.0  # 1/2 poi size 
    aio_max_lat = +poisiz/2.0  # 1/2 poi size
    aio_min_lon = -poisiz/2.0  # 1/2 poi size
    aio_max_lon = +poisiz/2.0  # 1/2 poi size

    while(True):

        ui.clear_screen()

        print()
        print(f'POI lon  = {poilon}')
        print(f'POI lat  = {poilat}')
        print(f'POI siz  = {poisiz}')
        print(f'AIO lon  = {aio_min_lon:<6} (min)')
        print(f'AIO lon  = {aio_max_lon:<6} (max)')
        print(f'AIO lat  = {aio_min_lat:<6} (min)')
        print(f'AIP lat  = {aio_max_lat:<6} (max)')

        tlat,tlon = get_test_lat_lon()

        print()
        print(f'test lon = {tlon}')
        print(f'test lat = {tlat}')

        nlat = tlat - poilat   # rotate test lat
        nlon = tlon - poilon   # rotate test lon

        print()
        print(f'new lon  = {nlon}')
        print(f'new lat  = {nlat}')

        x,y,z = lat_lon_to_xyz(nlat,nlon)

        xx = x * 100.0         # scale X coordinate
        yy = y * 100.0         # scale Y coordinate
        zz = z * 100.0         # scale Z coordinate

        print()
        print(f'new x    = {round(xx,2)}')
        print(f'new y    = {round(yy,2)}')
        print(f'new z    = {round(zz,2)}')

        # ---- test if the rotated test lat/lon (newlat,newlon)
        # ---- in the area-of-interest?

        print()
        if nlon < aio_min_lon or nlon > aio_max_lon or \
           nlat < aio_min_lat or nlon > aio_max_lat:
            print('NOT in area of interest')
        else:
            print('in area of interest')

        ui.pause()