RKSI TMA 0.1.5

adjust traffic ratios per gateway
add missing hold fix DH989
lower altitude restriction east of KARBU on G597 to accomodate departures
lower altitude restriction west of Seoul TMA south of NOPIK to accomodate holding at ELGUK
This commit is contained in:
Calvin Ng
2021-06-24 22:08:48 -07:00
parent 8fd9c8c21f
commit 8f7d7c26fd
3 changed files with 1236 additions and 104 deletions
+1111 -53
View File
File diff suppressed because it is too large Load Diff
+95 -42
View File
@@ -74,7 +74,7 @@ beacons =
DH034, N37.14.08.2, E126.11.16.7, ! DH034, N37.14.08.2, E126.11.16.7, !
DH047, N37.02.20.0, E126.30.58.0, ! DH047, N37.02.20.0, E126.30.58.0, !
DH050, N37.01.44.4, E126.37.23.0, ! DH050, N37.01.44.4, E126.37.23.0, !
DH989, N37.18.55.0, E126.19.59.0, ! DH989, N37.18.55.0, E126.19.59.0, 47
DY019, N37.11.12.0, E126.39.48.0, ! DY019, N37.11.12.0, E126.39.48.0, !
DY037, N36.56.12.5, E126.53.08.4, ! DY037, N36.56.12.5, E126.53.08.4, !
ELGUK, N37.19.59.4, E125.45.24.7, !-67 ELGUK, N37.19.59.4, E125.45.24.7, !-67
@@ -298,8 +298,24 @@ beacons =
N4T01, N37.58.10, E127.39.52, ! N4T01, N37.58.10, E127.39.52, !
+C1T01, 5S1, N2T01, KIP, 324, ! +C1T01, 5S1, N2T01, KIP, 324, !
+C2T01, N3T01, N4T01, 4C518, 5C518, ! +C2T01, N3T01, N4T01, 4C518, 5C518, !
T02NE, N38.00.10, E127.54.52, !
T02SE, N37.10.10, E127.54.52, !
T02SW, N37.06.40, E127.39.52, !
@G597N, SEL, D5, 348.3T, !
@G597S, SEL, D5, 168.3T, !
+G02NW, N4T01, T02SW, G597N, 78.3T
+G02SW, N4T01, T02SW, G597S, 78.3T
+G02NE, T02NE, T02SE, G597N, 78.3T
+G02SE, T02NE, T02SE, G597S, 78.3T
handoff =
!BINIL, Daegu Control, Daegu Control, 132.8
!BOPTA, Incheon Control, Incheon Control, 132.15
!BULTI, Incheon Control, Incheon Control, 132.15
!OSPOT, Daegu Control, Daegu Control, 125.375
!KARBU, Daegu Control, Daegu Control, 134.175
line1 = line1 =
N37.73682, E126.52070 N37.73682, E126.52070
N37.78257, E126.49355 N37.78257, E126.49355
@@ -422,10 +438,10 @@ boundary =
#T02 #T02
!N4T01 !N4T01
#end T01 #end T01
N38.00.10, E127.54.52 !T02NE
N37.10.10, E127.54.52 !T02SE
# N37.10.10, E127.45.52 # N37.10.10, E127.45.52
# N37.06.40, E127.39.52 # !T02SW
#end T02 #end T02
#southern extension #southern extension
N37.10.10, E127.54.52 N37.10.10, E127.54.52
@@ -467,14 +483,37 @@ boundary =
[area] [area]
shape = polygon shape = polygon
name = NW name = NW
altitude = 17500 altitude = 7500
labelpos = N37.40.00, E127.47.30 labelpos = N37.35.00, E127.47.30
points = points =
N37.58.10, E127.39.52 !N4T01
N38.00.10, E127.54.52 !T02NE
N37.10.10, E127.54.52 !T02SE
N37.10.10, E127.45.52 N37.10.10, E127.45.52
N37.06.40, E127.39.52 !T02SW
[area]
shape = polygon
name = NW
altitude = 17500
labelpos = N37.20.00, E127.47.30
points =
!N4T01
!T02NE
!G02NE
!G02NW
[area]
shape = polygon
name = NW
altitude = 17500
labelpos = N37.50.00, E127.47.30
points =
!G02SW
!G02SE
!T02SE
N37.10.10, E127.45.52
!T02SW
#T03 #T03
[area] [area]
@@ -611,6 +650,19 @@ shape = polygon
name = RR name = RR
altitude = 12500 altitude = 12500
labelpos = N37.17.30, E125.22.00 labelpos = N37.17.30, E125.22.00
points =
N37.05.17, E125.48.09
N37.05.17, E125.14.00
N37.30.00, E125.14.00
N37.30.00, E125.50.00
N37.21.10, E125.32.53
!REBIT
[area]
shape = polygon
name = RR
altitude = 3000
labelpos = N37.17.30, E125.35.00
points = points =
N37.05.17, E125.48.09 N37.05.17, E125.48.09
N37.05.17, E125.14.00 N37.05.17, E125.14.00
@@ -1087,6 +1139,7 @@ climbaltitude = 6000
entrypoints = entrypoints =
# Y697/G597 # Y697/G597
80, KARBU 80, KARBU
80, KARBU
# Y685/G585 # Y685/G585
122, GUKDO 122, GUKDO
122, GUKDO 122, GUKDO
@@ -1645,19 +1698,19 @@ route = @!EGOBA1C
route = @!Y697 route = @!Y697
!KARBU !KARBU
route = route = *3
BINIL 1C, Binil 1 Charlie BINIL 1C, Binil 1 Charlie
@!BINIL1C @!BINIL1C
route = route = *10
BOPTA 1C, Bopta 1 Charlie BOPTA 1C, Bopta 1 Charlie
@!BOPTA1C @!BOPTA1C
route = route = *2
OSPOT 1C, Ospot 1 Charlie OSPOT 1C, Ospot 1 Charlie
@!OSPOT1C @!OSPOT1C
route = route = *4
EGOBA 1C, Egoba 1 Charlie EGOBA 1C, Egoba 1 Charlie
@!EGOBA1C @!EGOBA1C
@!Y697 @!Y697
@@ -1666,19 +1719,19 @@ route =
[departure] [departure]
runway = RKSIRWYE runway = RKSIRWYE
route = route = *3
BINIL 1C, Binil 1 Charlie BINIL 1C, Binil 1 Charlie
@!BINIL1C @!BINIL1C
route = route = *10
BOPTA 1C, Bopta 1 Charlie BOPTA 1C, Bopta 1 Charlie
@!BOPTA1C @!BOPTA1C
route = route = *2
OSPOT 1C, Ospot 1 Charlie OSPOT 1C, Ospot 1 Charlie
@!OSPOT1C @!OSPOT1C
route = route = *4
EGOBA 1C, Egoba 1 Charlie EGOBA 1C, Egoba 1 Charlie
@!EGOBA1C @!EGOBA1C
@!Y697 @!Y697
@@ -1722,19 +1775,19 @@ route = @!EGOBA1H
!CK099 !CK099
!EGOBA !EGOBA
route = route = *3
BINIL 1H, Binil 1 Hotel BINIL 1H, Binil 1 Hotel
@!BINIL1H @!BINIL1H
route = route = *10
BOPTA 1H, Bopta 1 Hotel BOPTA 1H, Bopta 1 Hotel
@!BOPTA1H @!BOPTA1H
route = route = *2
OSPOT 1H, Ospot 1 Hotel OSPOT 1H, Ospot 1 Hotel
@!OSPOT1H @!OSPOT1H
route = route = *4
EGOBA 1H, Egoba 1 Hotel EGOBA 1H, Egoba 1 Hotel
@!EGOBA1H @!EGOBA1H
@!Y697 @!Y697
@@ -1743,19 +1796,19 @@ route =
[departure] [departure]
runway = RKSIRWYWW runway = RKSIRWYWW
route = route = *3
BINIL 1H, Binil 1 Hotel BINIL 1H, Binil 1 Hotel
@!BINIL1H @!BINIL1H
route = route = *10
BOPTA 1H, Bopta 1 Hotel BOPTA 1H, Bopta 1 Hotel
@!BOPTA1H @!BOPTA1H
route = route = *2
OSPOT 1H, Ospot 1 Hotel OSPOT 1H, Ospot 1 Hotel
@!OSPOT1H @!OSPOT1H
route = route = *4
EGOBA 1H, Egoba 1 Hotel EGOBA 1H, Egoba 1 Hotel
@!EGOBA1H @!EGOBA1H
@!Y697 @!Y697
@@ -1819,24 +1872,24 @@ route = *2
NOPIK 1A, Nopik 1 Alpha NOPIK 1A, Nopik 1 Alpha
@!NOPIK1A @!NOPIK1A
route = *2 route = *12
BOPTA 1A, Bopta 1 Alpha BOPTA 1A, Bopta 1 Alpha
@!BOPTA1A @!BOPTA1A
route = route = *5
OSPOT 1A, Ospot 1 Alpha OSPOT 1A, Ospot 1 Alpha
@!OSPOT1A @!OSPOT1A
route = route = *3
EGOBA 1A, Egoba 1 Alpha EGOBA 1A, Egoba 1 Alpha
@!EGOBA1A @!EGOBA1A
@!Y697 @!Y697
route = route = *5
OSPOT 1E, Ospot 1 Echo OSPOT 1E, Ospot 1 Echo
@!OSPOT1E @!OSPOT1E
route = route = *3
EGOBA 1E, Egoba 1 Echo EGOBA 1E, Egoba 1 Echo
@!EGOBA1E @!EGOBA1E
@!Y697 @!Y697
@@ -1849,24 +1902,24 @@ route = *2
NOPIK 1A, Nopik 1 Alpha NOPIK 1A, Nopik 1 Alpha
@!NOPIK1A @!NOPIK1A
route = *2 route = *12
BOPTA 1A, Bopta 1 Alpha BOPTA 1A, Bopta 1 Alpha
@!BOPTA1A @!BOPTA1A
route = route = *5
OSPOT 1A, Ospot 1 Alpha OSPOT 1A, Ospot 1 Alpha
@!OSPOT1A @!OSPOT1A
route = route = *3
EGOBA 1A, Egoba 1 Alpha EGOBA 1A, Egoba 1 Alpha
@!EGOBA1A @!EGOBA1A
@!Y697 @!Y697
route = route = *5
OSPOT 1E, Ospot 1 Echo OSPOT 1E, Ospot 1 Echo
@!OSPOT1E @!OSPOT1E
route = route = *3
EGOBA 1E, Egoba 1 Echo EGOBA 1E, Egoba 1 Echo
@!EGOBA1E @!EGOBA1E
@!Y697 @!Y697
@@ -1914,15 +1967,15 @@ route =
NOPIK 1Y, Nopik 1 Yankee NOPIK 1Y, Nopik 1 Yankee
@!NOPIK1Y @!NOPIK1Y
route = route = *6
BOPTA 1Y, Bopta 1 Yankee BOPTA 1Y, Bopta 1 Yankee
@!BOPTA1Y @!BOPTA1Y
route = route = *5
OSPOT 1Y, Ospot 1 Yankee OSPOT 1Y, Ospot 1 Yankee
@!OSPOT1Y @!OSPOT1Y
route = route = *3
EGOBA 1Y, Egoba 1 Yankee EGOBA 1Y, Egoba 1 Yankee
@!EGOBA1Y @!EGOBA1Y
@!Y697 @!Y697
@@ -1935,15 +1988,15 @@ route =
NOPIK 1Y, Nopik 1 Yankee NOPIK 1Y, Nopik 1 Yankee
@!NOPIK1Y @!NOPIK1Y
route = route = *6
BOPTA 1Y, Bopta 1 Yankee BOPTA 1Y, Bopta 1 Yankee
@!BOPTA1Y @!BOPTA1Y
route = route = *5
OSPOT 1Y, Ospot 1 Yankee OSPOT 1Y, Ospot 1 Yankee
@!OSPOT1Y @!OSPOT1Y
route = route = *3
EGOBA 1Y, Egoba 1 Yankee EGOBA 1Y, Egoba 1 Yankee
@!EGOBA1Y @!EGOBA1Y
@!Y697 @!Y697
+30 -9
View File
@@ -118,6 +118,9 @@ class Fix:
except Exception as e: except Exception as e:
raise RuntimeError(f"Unable to generate a LatLon for fix {self.name}: {self}") from e raise RuntimeError(f"Unable to generate a LatLon for fix {self.name}: {self}") from e
def heading_to(self, other):
return self.latlon.initialBearingTo(Fix.fixes[other].latlon)
def meters_on_heading(self, meters, heading, true_heading=False): def meters_on_heading(self, meters, heading, true_heading=False):
if isinstance(heading, str): if isinstance(heading, str):
heading = heading.lstrip('!') heading = heading.lstrip('!')
@@ -173,22 +176,22 @@ class Fix:
`radial_true`: Whether `radial` is a true heading. Defaults to `False`. `radial_true`: Whether `radial` is a true heading. Defaults to `False`.
`other_radial_true`: Whether `other_radial` is a true heading. Defaults to `False`. `other_radial_true`: Whether `other_radial` is a true heading. Defaults to `False`.
""" """
if radial.endswith('T') and radial[:-1].isdecimal(): if radial.endswith('T') and radial[:-1].replace('.', '', 1).isdigit():
radial_true = True radial_true = True
radial = radial[:-1] radial = radial[:-1]
if other_radial.endswith('T') and radial[:-1].isdecimal(): if other_radial.endswith('T') and other_radial[:-1].replace('.', '', 1).isdigit():
other_radial_true = True other_radial_true = True
other_radial = other_radial[:-1] other_radial = other_radial[:-1]
if radial.isdecimal(): if radial.replace('.', '', 1).isdigit():
radial = float(radial) radial = float(radial)
if not radial_true: if not radial_true:
radial += Fix._var radial += Fix._var
else: else:
radial = Fix.fixes[radial].latlon radial = Fix.fixes[radial].latlon
if other_radial.isdecimal(): if other_radial.replace('.', '', 1).isdigit():
other_radial = float(other_radial) other_radial = float(other_radial)
if not other_radial_true: if not other_radial_true:
other_radial += Fix._var other_radial += Fix._var
@@ -741,6 +744,18 @@ def process_beacons(fixes):
yield fix.full_def yield fix.full_def
def process_handoffs(handoffs, center):
"""Processes fix references in [airspace] handoff=.
Returns a generator of processed [airspace] handoff= lines."""
for handoff in handoffs.strip().splitlines():
direction, separator, parameters = handoff.partition(',')
if direction.startswith('!'):
direction = str(int(center.heading_to(direction[1:])))
yield ",".join([direction, parameters])
def process_airlines_list(airline_list): def process_airlines_list(airline_list):
"""Returns generator of airline declaration strings based on the list of `Airline`s `airline_list`. """Returns generator of airline declaration strings based on the list of `Airline`s `airline_list`.
@@ -814,7 +829,9 @@ def process(args, input_file=None, preprocessed_input=None):
# remove meta section so it won't be written in output # remove meta section so it won't be written in output
del source['meta'] del source['meta']
Fix.initialize(source['airspace'].getfloat('magneticvar')) airspace = source['airspace']
Fix.initialize(airspace.getfloat('magneticvar'))
# add runways to fix database # add runways to fix database
airports = {section: source[section] for section in source if section.startswith('airport')} airports = {section: source[section] for section in source if section.startswith('airport')}
@@ -824,14 +841,18 @@ def process(args, input_file=None, preprocessed_input=None):
for runway_definition in runways: for runway_definition in runways:
RunwayFix.from_definition(runway_definition).reciprocal() RunwayFix.from_definition(runway_definition).reciprocal()
Fix('_CTR', *airspace['center'].split(","))
# build a fix database from [airspace] beacons= # build a fix database from [airspace] beacons=
for definition in source['airspace']['beacons'].strip().splitlines(): for definition in airspace['beacons'].strip().splitlines():
Fix(*definition.split(",")) Fix(*definition.split(","))
source['airspace']['beacons'] = "\n".join(process_beacons(Fix.fixes)) airspace['beacons'] = "\n".join(process_beacons(Fix.fixes))
source['airspace']['boundary'] = "\n".join( airspace['handoff'] = "\n".join(process_handoffs(airspace['handoff'], Fix.fixes['_CTR']))
process_fix_list(source['airspace']['boundary'].splitlines(), Fix.fixes))
airspace['boundary'] = "\n".join(
process_fix_list(airspace['boundary'].splitlines(), Fix.fixes))
areas = {section: source[section] for section in source if section.startswith('area')} areas = {section: source[section] for section in source if section.startswith('area')}