'''
Created on 21 déc. 2020

@author: robert
'''

import math
from trajectory.Environment.Constants import Feet2Meter
from trajectory.Environment.Earth import EarthRadiusMeters

from trajectory.Guidance.GeographicalPointFile import GeographicalPoint


class RunWay(GeographicalPoint):    
    '''
    The Charles De Gaulle airport has 2 configurations, depending on the wind directions.
    However, in both configurations Eastward and Westward of Charles de Gaulle:
    - The Run-ways 08R/26L and 09L/27R (far from the terminal) are mainly used for landings.
    - The Run-ways 08L/26R and 09R/27L (near the terminal) are mainly used for take-offs. 
    
    Id, ICAO,Number, Length Meters, Length Feet, Orientation Degrees
    The run-way true heading is defined as the angle 
      1) expressed in degrees
      2) counted from the geographic NORTH, 
      3) clock-wise 
      4) with the run-way end point as the summit of the angle

    Lat-long are the position of the end of the runway
    1) end - if takeoff runway -  is the location the aircraft starts its ground run
    2) end - if landing runway - is the location where after the touch down and deceleration, the ac reaches the taxi speed
     
    '''
    className = ''
    airportICAOcode = ''
    Name = ''
    LengthFeet = 0.0
    TrueHeadingDegrees = 0.0
    TakeOffLanding = ''

    
    def __init__(self, 
                 Name, 
                 airportICAOcode, 
                 LengthFeet, 
                 TrueHeadingDegrees, 
                 LatitudeDegrees, 
                 LongitudeDegrees):
        
        self.className = self.__class__.__name__

        assert not(Name is None) and isinstance(Name, (str)) 
        assert not(airportICAOcode is None) and isinstance(airportICAOcode, (str))
                    
        assert not (LengthFeet is None) and isinstance(LengthFeet, float) and (LengthFeet>0.0)
            
        assert not (TrueHeadingDegrees is None) and isinstance(TrueHeadingDegrees, float) 
        assert (-360.0 <= TrueHeadingDegrees) and (TrueHeadingDegrees <= 360.0)
                    
        assert not (LatitudeDegrees is None) and (isinstance(LatitudeDegrees, float)) 
        assert (-90.0 <= LatitudeDegrees) and (LatitudeDegrees <= 90.0)
            
        assert not (LongitudeDegrees is None) and (isinstance(LongitudeDegrees, float))
        assert (-180.0 <= LongitudeDegrees) and (LongitudeDegrees <= 180.0)
        
        GeographicalPoint.__init__(self, LatitudeDegrees=LatitudeDegrees, LongitudeDegrees=LongitudeDegrees, AltitudeMeanSeaLevelMeters=EarthRadiusMeters)
            
        self.airportICAOcode = airportICAOcode
        self.Name = Name
        self.LengthFeet = LengthFeet
        self.TrueHeadingDegrees = TrueHeadingDegrees
        
                                    
    def getName(self):
        return self.Name
    
    def getAirportICAOcode(self):
        return self.airportICAOcode
    
    def getLengthMeters(self):
        return self.LengthFeet * Feet2Meter
    
    def getTrueHeadingDegrees(self):
        return self.TrueHeadingDegrees
    
    def getLatitudeDegrees(self):
        return self.LatitudeDegrees
    
    def getLongitudeDegrees(self):
        return self.LongitudeDegrees
    
    def __str__(self):
        strRunWay = self.className
        strRunWay += ': runway= ' + self.Name
        strRunWay += ' airport ICAO code= '     + self.airportICAOcode 
        strRunWay += ' length= {0:.2f} feet'.format(self.LengthFeet) 
        strRunWay += ' true heading= {0:.2f} degrees'.format(self.TrueHeadingDegrees)
        strRunWay += ' latitude= {0:.2f} degrees'.format(self.LatitudeDegrees)
        strRunWay += ' longitude= {0:.2f} degrees'.format(self.LongitudeDegrees)
        return strRunWay
    
    def getEndOfRunWay(self):
        latitudeDegrees , longitudeDegrees = self.getGeoPointAtDistanceHeading(self.getLengthMeters(), self.getTrueHeadingDegrees())
        return GeographicalPoint(latitudeDegrees , longitudeDegrees, EarthRadiusMeters)
    
    def computeShortestDistanceToRunway(self, geographicalPoint):
        ''' https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line '''
        assert not(geographicalPoint is None) and isinstance(geographicalPoint, (GeographicalPoint)) 
        
        #x0, y0, z0 = geographicalPoint.convert2Cartesian()
        #x0 , y0 = geographicalPoint.projectionMillerCylindrical()
        x0 = geographicalPoint.new_x_coord()
        y0 = geographicalPoint.new_y_coord()
        
        ''' these are cartesian coordinates from runway starting point '''
        #x1, y1, z1 = self.convert2Cartesian()
        #x1, y1 = self.projectionMillerCylindrical()
        x1 = self.new_x_coord()
        y1 = self.new_y_coord()
        
        endOfRunway = self.getEndOfRunWay()
        #x2, y2, z2 = endOfRunway.convert2Cartesian()
        #x2 , y2 = endOfRunway.projectionMillerCylindrical()
        x2 = endOfRunway.new_x_coord()
        y2 = endOfRunway.new_y_coord()
        
        ''' Assuming that all three points are in the same Z plane '''
        
        ''' The numerator is twice the area of the triangle with its vertices at the three points, (x0, y0), P1 and P2 '''
        numerator = math.fabs ( ( (x2 - x1) * (y1 - y0)) - ( (x1 - x0) * (y2 - y1) ) )
        ''' The denominator of this expression is the distance between P1 and P2 '''
        denominator = math.sqrt( (x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1) )
        return numerator / denominator
        
        

'''
Created on 21 déc. 2020

@author: robert
'''

import math
from trajectory.Environment.Constants import Feet2Meter
from trajectory.Environment.Earth import EarthRadiusMeters

from trajectory.Guidance.GeographicalPointFile import GeographicalPoint


class RunWay(GeographicalPoint):    
    '''
    The Charles De Gaulle airport has 2 configurations, depending on the wind directions.
    However, in both configurations Eastward and Westward of Charles de Gaulle:
    - The Run-ways 08R/26L and 09L/27R (far from the terminal) are mainly used for landings.
    - The Run-ways 08L/26R and 09R/27L (near the terminal) are mainly used for take-offs. 
    
    Id, ICAO,Number, Length Meters, Length Feet, Orientation Degrees
    The run-way true heading is defined as the angle 
      1) expressed in degrees
      2) counted from the geographic NORTH, 
      3) clock-wise 
      4) with the run-way end point as the summit of the angle

    Lat-long are the position of the end of the runway
    1) end - if takeoff runway -  is the location the aircraft starts its ground run
    2) end - if landing runway - is the location where after the touch down and deceleration, the ac reaches the taxi speed
     
    '''
    className = ''
    airportICAOcode = ''
    Name = ''
    LengthFeet = 0.0
    TrueHeadingDegrees = 0.0
    TakeOffLanding = ''

    
    def __init__(self, 
                 Name, 
                 airportICAOcode, 
                 LengthFeet, 
                 TrueHeadingDegrees, 
                 LatitudeDegrees, 
                 LongitudeDegrees):
        
        self.className = self.__class__.__name__

        assert not(Name is None) and isinstance(Name, (str)) 
        assert not(airportICAOcode is None) and isinstance(airportICAOcode, (str))
                    
        assert not (LengthFeet is None) and isinstance(LengthFeet, float) and (LengthFeet>0.0)
            
        assert not (TrueHeadingDegrees is None) and isinstance(TrueHeadingDegrees, float) 
        assert (-360.0 <= TrueHeadingDegrees) and (TrueHeadingDegrees <= 360.0)
                    
        assert not (LatitudeDegrees is None) and (isinstance(LatitudeDegrees, float)) 
        assert (-90.0 <= LatitudeDegrees) and (LatitudeDegrees <= 90.0)
            
        assert not (LongitudeDegrees is None) and (isinstance(LongitudeDegrees, float))
        assert (-180.0 <= LongitudeDegrees) and (LongitudeDegrees <= 180.0)
        
        GeographicalPoint.__init__(self, LatitudeDegrees=LatitudeDegrees, LongitudeDegrees=LongitudeDegrees, AltitudeMeanSeaLevelMeters=EarthRadiusMeters)
            
        self.airportICAOcode = airportICAOcode
        self.Name = Name
        self.LengthFeet = LengthFeet
        self.TrueHeadingDegrees = TrueHeadingDegrees
        
                                    
    def getName(self):
        return self.Name
    
    def getAirportICAOcode(self):
        return self.airportICAOcode
    
    def getLengthMeters(self):
        return self.LengthFeet * Feet2Meter
    
    def getTrueHeadingDegrees(self):
        return self.TrueHeadingDegrees
    
    def getLatitudeDegrees(self):
        return self.LatitudeDegrees
    
    def getLongitudeDegrees(self):
        return self.LongitudeDegrees
    
    def __str__(self):
        strRunWay = self.className
        strRunWay += ': runway= ' + self.Name
        strRunWay += ' airport ICAO code= '     + self.airportICAOcode 
        strRunWay += ' length= {0:.2f} feet'.format(self.LengthFeet) 
        strRunWay += ' true heading= {0:.2f} degrees'.format(self.TrueHeadingDegrees)
        strRunWay += ' latitude= {0:.2f} degrees'.format(self.LatitudeDegrees)
        strRunWay += ' longitude= {0:.2f} degrees'.format(self.LongitudeDegrees)
        return strRunWay
    
    def getEndOfRunWay(self):
        latitudeDegrees , longitudeDegrees = self.getGeoPointAtDistanceHeading(self.getLengthMeters(), self.getTrueHeadingDegrees())
        return GeographicalPoint(latitudeDegrees , longitudeDegrees, EarthRadiusMeters)
    
    def computeShortestDistanceToRunway(self, geographicalPoint):
        ''' https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line '''
        assert not(geographicalPoint is None) and isinstance(geographicalPoint, (GeographicalPoint)) 
        
        #x0, y0, z0 = geographicalPoint.convert2Cartesian()
        #x0 , y0 = geographicalPoint.projectionMillerCylindrical()
        x0 = geographicalPoint.new_x_coord()
        y0 = geographicalPoint.new_y_coord()
        
        ''' these are cartesian coordinates from runway starting point '''
        #x1, y1, z1 = self.convert2Cartesian()
        #x1, y1 = self.projectionMillerCylindrical()
        x1 = self.new_x_coord()
        y1 = self.new_y_coord()
        
        endOfRunway = self.getEndOfRunWay()
        #x2, y2, z2 = endOfRunway.convert2Cartesian()
        #x2 , y2 = endOfRunway.projectionMillerCylindrical()
        x2 = endOfRunway.new_x_coord()
        y2 = endOfRunway.new_y_coord()
        
        ''' Assuming that all three points are in the same Z plane '''
        
        ''' The numerator is twice the area of the triangle with its vertices at the three points, (x0, y0), P1 and P2 '''
        numerator = math.fabs ( ( (x2 - x1) * (y1 - y0)) - ( (x1 - x0) * (y2 - y1) ) )
        ''' The denominator of this expression is the distance between P1 and P2 '''
        denominator = math.sqrt( (x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1) )
        return numerator / denominator
        
        

Created on 21 déc. 2020  @author: robert The Charles De Gaulle airport has 2 configurations, depending on the wind directions.     However, in both configurations Eastward and Westward of Charles de Gaulle:     - The Run-ways 08R/26L and 09L/27R (far from the terminal) are mainly used for landings.     - The Run-ways 08L/26R and 09R/27L (near the terminal) are mainly used for take-offs.           Id, ICAO,Number, Length Meters, Length Feet, Orientation Degrees     The run-way true heading is defined as the angle        1) expressed in degrees       2) counted from the geographic NORTH,        3) clock-wise        4) with the run-way end point as the summit of the angle      Lat-long are the position of the end of the runway     1) end - if takeoff runway -  is the location the aircraft starts its ground run     2) end - if landing runway - is the location where after the touch down and deceleration, the ac reaches the taxi speed https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line #x0, y0, z0 = geographicalPoint.convert2Cartesian() #x0 , y0 = geographicalPoint.projectionMillerCylindrical() these are cartesian coordinates from runway starting point #x1, y1, z1 = self.convert2Cartesian() #x1, y1 = self.projectionMillerCylindrical() #x2, y2, z2 = endOfRunway.convert2Cartesian() #x2 , y2 = endOfRunway.projectionMillerCylindrical() Assuming that all three points are in the same Z plane The numerator is twice the area of the triangle with its vertices at the three points, (x0, y0), P1 and P2 The denominator of this expression is the distance between P1 and P2