Last active
March 1, 2022 06:27
-
-
Save GISConsortium/c15e2afc1ec3eba04614cc375575defc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
# File: i_space_assignment.py | |
# Description: This program provides the elevation angle and distance of horizon from an observer | |
# Developer Name: Nitin Kandpal | |
# Date Created: 28/02/2022 | |
import pandas as pd | |
import logging | |
import math | |
import os | |
import sys | |
class Log: | |
""" | |
This class logs the error, warning and info produced during execution of i_space_assignment code. | |
The write_log function is static function of this class, and returns the logger, | |
log is created inside the current working directory. | |
""" | |
@staticmethod | |
def write_log(): | |
logger = logging.getLogger('assignment') | |
log_dir = os.path.join(os.getcwd(), 'log') | |
if not os.path.exists(log_dir): | |
os.makedirs(log_dir) | |
log_file_path = os.path.join(log_dir, 'assignment.log') | |
# Create handlers | |
error_handler = logging.FileHandler(log_file_path) | |
error_handler.setLevel(logging.DEBUG) | |
# Define format for logging and add it to handlers | |
error_string_format = logging.Formatter('%(asctime)s - %(lineno)s - %(levelname)s - %(message)s') | |
error_handler.setFormatter(error_string_format) | |
logger.addHandler(error_handler) | |
return logger | |
class PlanetUtility: | |
""" | |
This class is for calculating elevation angle and distance to horizon from a point of observation. | |
The compute_horizon_distance_from_observer function is the public interface for this class. | |
The instance variable planet_radius_meters stores the radius of planetary feature in meters. | |
""" | |
def __init__(self, radius): | |
""" | |
This is a constructor that assigns the object variable with the radius | |
of the planetary feature. | |
Parameters | |
---------- | |
radius : float/int | |
radius of the planetary feature in meters. | |
Returns | |
------- | |
None. | |
""" | |
self.planet_radius_meters = radius | |
@staticmethod | |
def _calculate_elevation_angle(series): | |
""" | |
Parameters | |
---------- | |
series : pandas series | |
dataframe containing perpendicular distance and base w.r.t. observer | |
Returns | |
------- | |
elevation_angle : float/int | |
Elevation angle in degrees. | |
""" | |
perpendicular = series[2] | |
base = series[1] | |
radian = math.atan(perpendicular / base) | |
elevation_angle = PlanetUtility._convert_radian_2_degree(radian) | |
return elevation_angle | |
@staticmethod | |
def _convert_degree_2_radians(angle): | |
""" | |
Parameters | |
---------- | |
angle : float/int | |
angle in degrees. | |
Returns | |
------- | |
angle_radian : float/int | |
angle in radian. | |
""" | |
angle_radian = math.radians(angle) | |
return angle_radian | |
@staticmethod | |
def _convert_radian_2_degree(radian): | |
""" | |
Parameters | |
---------- | |
radian : float/int | |
Angle in radian. | |
Returns | |
------- | |
float/int | |
Angle in degree. | |
""" | |
angle_degree = radian * (180 / math.pi) | |
return angle_degree | |
@staticmethod | |
def _calculate_hypotenuse(perpendicular, base): | |
""" | |
Parameters | |
---------- | |
perpendicular : float/int | |
Length of the perpendicular edge of the triangle. | |
base : float/int | |
Length of the base of the triangle. | |
Returns | |
------- | |
hypotenuse : float/int | |
Length of the hypotenuse of the triangle. | |
""" | |
hypotenuse = math.sqrt(perpendicular ** 2 + base ** 2) | |
return hypotenuse | |
def __calculate_distance_of_visible_horizon(self): | |
""" | |
This function provides the distance of horizon | |
from object standing 1 meter above the ground | |
using pythagoras theorem. It will provide the | |
distance within which the elevation need to | |
be checked. | |
Returns | |
------- | |
horizon_distance : float | |
Distance to the horizon from an object standing 1 m above the | |
ground. | |
""" | |
horizon_distance = math.sqrt((self.planet_radius_meters + 1) ** 2 - self.planet_radius_meters ** 2) | |
return math.ceil(horizon_distance) | |
def compute_horizon_distance_from_observer(self, elevation_file_path, index_of_observer=0, | |
sampling_distance=350, height_observer=3): | |
""" | |
This function calculates the minimum elevation angle needed to view space, | |
it also calculates the distance of horizon from the observer. | |
Parameters | |
---------- | |
elevation_file_path : string | |
Input path for the elevation file, it has a single column that | |
contains series of lunar elevations taken along a straight line in | |
Mare Frigoris. | |
index_of_observer : integer, optional | |
It is the row number at which the height of observer is present in | |
the provided elevation file. The default is 0. | |
sampling_distance : int/float, optional | |
It is the distance interval in which the elevations are measured. Its | |
unit is in meters. The default is 350. | |
height_observer : int/float, optional | |
Height of the observer above the ground. The default is 3. | |
Returns | |
------- | |
distance_to_horizon : float/int | |
calculate the distance of horizon from the observer | |
""" | |
elev_profile = pd.read_csv(elevation_file_path, header=None, | |
skiprows=index_of_observer, names=["elevation"]) | |
'''processing the elevation points that are at a distance of visible | |
horizon from the observer, and to ensure accuracy we will | |
take distance buffer of +1000m''' | |
distance_visible_horizon = self.__calculate_distance_of_visible_horizon() + 1000 | |
# assigning distance from observer to each elevation profile | |
lst_distance_from_observer = [] | |
for i in range(0, len(elev_profile)): | |
lst_distance_from_observer.append(i * sampling_distance) | |
elev_profile["distance_from_observer"] = lst_distance_from_observer | |
# getting the elevation profile of the observer | |
elev_of_ground = elev_profile.loc[elev_profile["distance_from_observer"] == 0, 'elevation'][0] | |
# updating the elevation profile of the observer | |
elev_of_observer = elev_of_ground + height_observer | |
elev_profile.loc[(elev_profile["distance_from_observer"] == 0), 'elevation'] = elev_of_observer | |
# identifying the difference in the elevation w.r.t observer | |
elev_profile['elev_diff_observer'] = elev_profile['elevation'].to_list() - elev_of_observer | |
'''filtering out the features that are within the distance of the visible horizon | |
and their height is more than the observer height''' | |
elev_profile = elev_profile.loc[(elev_profile["distance_from_observer"] <= distance_visible_horizon) & ( | |
elev_profile['elev_diff_observer'] > 0)] | |
# calculating the elevation angle | |
elev_profile["elev_angle"] = elev_profile.apply(PlanetUtility._calculate_elevation_angle, axis=1) | |
# Identifying the feature within the visible horizon and has the highest elevation angle | |
target_elev_angle = \ | |
elev_profile.loc[elev_profile["elev_angle"] == max(elev_profile["elev_angle"]), "elev_angle"].to_list()[0] | |
target_perpendicular_dist = \ | |
elev_profile.loc[ | |
elev_profile["elev_angle"] == max(elev_profile["elev_angle"]), "elev_diff_observer"].to_list()[ | |
0] | |
target_dist_from_observer = elev_profile.loc[ | |
elev_profile["elev_angle"] == max(elev_profile["elev_angle"]), "distance_from_observer"].to_list()[0] | |
distance_to_horizon = PlanetUtility._calculate_hypotenuse(target_perpendicular_dist, target_dist_from_observer) | |
print("Elevation angle of horizon :{elev_angle} degree;Distance to horizon :{distance_horizon} meters".format( | |
distance_horizon=round(distance_to_horizon, 2), elev_angle=round(target_elev_angle, 2))) | |
return target_elev_angle, distance_to_horizon | |
if __name__ == "__main__": | |
logger = Log.write_log() | |
try: | |
moon = PlanetUtility(radius=1737400) | |
print(moon.compute_horizon_distance_from_observer(elevation_file_path = r"C:\Users\nitin\Downloads\I-SPACE\elevationProfile.txt")) | |
#Elevation angle of horizon :0.24 degree;Distance to horizon :2800.02 meters | |
except Exception as ex: | |
print(ex) | |
logger.error(ex) | |
sys.exit(ex) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment