Compare commits

..

12 Commits

Author SHA1 Message Date
Kilian 266606d9ab More leeway on TF overfly (MHTG)
NG skip
2025-08-17 00:01:22 +02:00
Kilian 900babf4cc workspace 2025-07-29 17:35:23 +02:00
Kilian 048d5129aa Fix CI into AF (DTMB ALTER SID into 07) 2025-07-29 14:12:25 +02:00
Kilian 73373420d3 Fix more CF 2025-07-19 15:14:46 +02:00
Kilian e9bab0306f MagDec and Loading indicator for parser 2025-07-18 23:20:24 +02:00
Kilian 4e4b921f79 Fix EDDM ILS26 OTT 2025-07-18 00:33:57 +02:00
Kilian d102ec4834 update navdata path 2025-07-17 22:51:58 +02:00
Kilian e91323c79b Update compose 2025-07-17 22:44:02 +02:00
Kilian bbda565272 update pw 2025-07-17 22:38:34 +02:00
Kilian 56ecfe38d1 compose env file 2025-07-17 22:33:20 +02:00
Kilian e0ee6d11dd Rename 2025-07-17 22:22:07 +02:00
Kilian 2bdb7e78c4 Last leg types 2025-07-17 20:57:12 +02:00
118 changed files with 793 additions and 3015 deletions
+1 -1
View File
@@ -9,7 +9,7 @@
"request": "launch", "request": "launch",
"name": "Launch Chrome against localhost", "name": "Launch Chrome against localhost",
"url": "http://localhost:3000", "url": "http://localhost:3000",
"webRoot": "${workspaceFolder}/browser", "webRoot": "${workspaceFolder}/md11-nav-data",
"sourceMaps": true "sourceMaps": true
} }
] ]
+7
View File
@@ -0,0 +1,7 @@
{
"folders": [
{
"path": "."
}
],
}
+32 -8
View File
@@ -40,7 +40,7 @@ LGAV 03L BIBE1K SID (Cycle 2507, ID 10653)
While similar to an RF, the center point is coded differently. While similar to an RF, the center point is coded differently.
Calculate distance for FMS based on ` 2 * π NavDist * abs(NavBear - Course) 360`. Calculate distance for FMS based on `2 * π * NavDist * abs(NavBear - Course) 360`.
## Course to Altitude (CA) ## Course to Altitude (CA)
@@ -346,7 +346,7 @@ LFPV 27 PB2V SID (Cycle 2507, ID 10395)
- `NavDist` is in **nmi**. `NavDist` is geodesic. - `NavDist` is in **nmi**. `NavDist` is geodesic.
## Holding mandatory (HA) ## Holding mandatory (altitude end) (HA)
### Example ### Example
@@ -420,7 +420,7 @@ My guess is that `Distance` always is a distance. This would match with the exam
The Leg terminates after the hold is exited ath the hold entry fix. The Leg terminates after the hold is exited ath the hold entry fix.
## Holding mandatory (HM) ## Holding mandatory (manual end) (HM)
### Example ### Example
@@ -493,8 +493,11 @@ FAUP VDM35 APP (Cycle 2507, ID 67790)
### Instructions ### Instructions
- From the fix identified by (`WptID`, `WptLat`, `WptLon`) *or* - From the fix identified by (`WptID`, `WptLat`, `WptLon`) *or*
(`NavID`, `NavLat`, `NavLon`, `NavDist`, `NavBear`), fly `Course` for `Distance`. (`NavID`, `NavLat`, `NavLon`, `NavDist`, `NavBear`), fly direct to succeeding leg fix.
- Turn `TurnDir` until aligned with succeeding leg course. - Turn `TurnDir` onto `Course`.
- Fly for 1 minute.
- Turn 180°.
- Fly until intercepting course of succeeding leg.
- `Alt` shall be the altitude during the procedure. - `Alt` shall be the altitude during the procedure.
### Units ### Units
@@ -505,8 +508,10 @@ FAUP VDM35 APP (Cycle 2507, ID 67790)
### Notes ### Notes
This needs to look into the succeeding leg in order to calculate the intercept point. This needs to look into the succeeding leg in order to fly the first segment and get the course
This intercept point then becomes the origin fix of the succeeding leg. to intercept after the reversal.
The database does not specify how long the outbound leg shall be.
1 minute is assumed here (googled it, seemed a common one).
## Radius to Fix (RF) ## Radius to Fix (RF)
@@ -702,4 +707,23 @@ This intercept point then becomes the origin fix of the succeeding leg.
# Other Fields # Other Fields
- `Vnav`: Angle from IAF to MAP. Useful for RNAV. - `Vnav`: Angle from IAF to MAP. Useful for RNAV.
# How to run
- `git clone https://git.hofmannnet.myhome-server.de/TFDi_MD-11_QA/NavDataExplorer.git`.
- `cd md11-nav-data`.
- `pnpm install`
For dev:
- Copy contents of `tfdidesign-aircraft-md11/Design/Primary` into ? `md11-nav-data/public/NavData`
- `cd md11-nav-data`.
- `pnpm dev`
For prod:
- `cd md11-nav-data`.
- `pnpm build`
- Verify NavData was copied into `dist`
File diff suppressed because one or more lines are too long
@@ -1,137 +0,0 @@
[
{
"ID": 84218,
"TerminalID": 10394,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 165609,
"WptLat": 48.77185278,
"WptLon": 2.09752222,
"TurnDir": "",
"NavID": 3827,
"NavLat": 48.97466667,
"NavLon": 2.45516667,
"NavBear": 228.5,
"NavDist": 18.7,
"Course": 267,
"Distance": 4,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": -1,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84219,
"TerminalID": 10394,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 247786,
"WptLat": 48.73058333,
"WptLon": 1.8205,
"TurnDir": "",
"NavID": 3827,
"NavLat": 48.97466667,
"NavLon": 2.45516667,
"NavBear": 239,
"NavDist": 29.1,
"Course": 256,
"Distance": 11,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": -1,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84220,
"TerminalID": 10394,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 253072,
"WptLat": 48.75372222,
"WptLon": 2.10236111,
"TurnDir": "R",
"NavID": 3827,
"NavLat": 48.97466667,
"NavLon": 2.45516667,
"NavBear": 225.6,
"NavDist": 19.3,
"Course": 107,
"Distance": 11,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84221,
"TerminalID": 10394,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CR",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": 3827,
"NavLat": 48.97466667,
"NavLon": 2.45516667,
"NavBear": 137,
"NavDist": null,
"Course": 73,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84222,
"TerminalID": 10394,
"Type": "2",
"Transition": "ALL",
"TrackCode": "VM",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 73,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
}
]
@@ -1,110 +0,0 @@
[
{
"ID": 84223,
"TerminalID": 10395,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 165609,
"WptLat": 48.77185278,
"WptLon": 2.09752222,
"TurnDir": "",
"NavID": 3827,
"NavLat": 48.97466667,
"NavLon": 2.45516667,
"NavBear": 228.5,
"NavDist": 18.7,
"Course": 267,
"Distance": 4,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": -1,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84224,
"TerminalID": 10395,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 165604,
"WptLat": 48.80511389,
"WptLon": 2.01279722,
"TurnDir": "",
"NavID": 3827,
"NavLat": 48.97466667,
"NavLon": 2.45516667,
"NavBear": 239,
"NavDist": 20.3,
"Course": 310,
"Distance": 3,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": -1,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84225,
"TerminalID": 10395,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CI",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 22,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84226,
"TerminalID": 10395,
"Type": "2",
"Transition": "ALL",
"TrackCode": "FM",
"WptID": 165605,
"WptLat": 48.83954444,
"WptLon": 1.95262222,
"TurnDir": "",
"NavID": 3827,
"NavLat": 48.97466667,
"NavLon": 2.45516667,
"NavBear": 247,
"NavDist": 21.5,
"Course": 67,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
}
]
@@ -1,83 +0,0 @@
[
{
"ID": 84536,
"TerminalID": 10475,
"Type": "2",
"Transition": "ALL",
"TrackCode": "VA",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 125,
"Distance": null,
"Alt": "00660A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84537,
"TerminalID": 10475,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 247774,
"WptLat": 49.11566667,
"WptLon": -0.32125,
"TurnDir": "",
"NavID": 3836,
"NavLat": 49.17319444,
"NavLon": -0.45527778,
"NavBear": 123.1,
"NavDist": 6.3,
"Course": 125,
"Distance": 6,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84538,
"TerminalID": 10475,
"Type": "2",
"Transition": "ALL",
"TrackCode": "TF",
"WptID": 252987,
"WptLat": 48.79061111,
"WptLon": 0.53027778,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
}
]
@@ -1,83 +0,0 @@
[
{
"ID": 84551,
"TerminalID": 10480,
"Type": "2",
"Transition": "ALL",
"TrackCode": "VD",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": 3851,
"NavLat": 49.17333333,
"NavLon": -0.44711111,
"NavBear": null,
"NavDist": null,
"Course": 305,
"Distance": 5,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84552,
"TerminalID": 10480,
"Type": "2",
"Transition": "ALL",
"TrackCode": "VI",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 243,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84553,
"TerminalID": 10480,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 40633,
"WptLat": 49.21472222,
"WptLon": -1.79555556,
"TurnDir": "",
"NavID": 3836,
"NavLat": 49.17319444,
"NavLon": -0.45527778,
"NavBear": 273.2,
"NavDist": 52.8,
"Course": 273,
"Distance": 44,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
}
]
@@ -1,83 +0,0 @@
[
{
"ID": 84557,
"TerminalID": 10482,
"Type": "2",
"Transition": "ALL",
"TrackCode": "VD",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": 3851,
"NavLat": 49.17333333,
"NavLon": -0.44711111,
"NavBear": null,
"NavDist": null,
"Course": 305,
"Distance": 5,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84558,
"TerminalID": 10482,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CI",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "R",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 50,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84559,
"TerminalID": 10482,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 8516,
"WptLat": 50,
"WptLon": -0.36823333,
"TurnDir": "",
"NavID": 3836,
"NavLat": 49.17319444,
"NavLon": -0.45527778,
"NavBear": 3.9,
"NavDist": 49.8,
"Course": 4,
"Distance": 42,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
}
]
@@ -1,110 +0,0 @@
[
{
"ID": 84567,
"TerminalID": 10485,
"Type": "5",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 166062,
"WptLat": 48.06525,
"WptLon": -1.67930556,
"TurnDir": "",
"NavID": 3946,
"NavLat": 48.06925,
"NavLon": -1.74166667,
"NavBear": 95.4,
"NavDist": 2.5,
"Course": 101,
"Distance": 2,
"Alt": "00530A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": 195,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84568,
"TerminalID": 10485,
"Type": "5",
"Transition": "ALL",
"TrackCode": "RF",
"WptID": 166064,
"WptLat": 48.03483333,
"WptLon": -1.63894444,
"TurnDir": "R",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 175.3,
"Distance": 2.6,
"Alt": "",
"Vnav": null,
"CenterID": 166063,
"CenterLat": 48.03252778,
"CenterLon": -1.6885,
"IsFlyOver": 0,
"SpeedLimit": 195,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84569,
"TerminalID": 10485,
"Type": "5",
"Transition": "ALL",
"TrackCode": "TF",
"WptID": 166061,
"WptLat": 47.91030556,
"WptLon": -1.62611111,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 84570,
"TerminalID": 10485,
"Type": "5",
"Transition": "ALL",
"TrackCode": "TF",
"WptID": 40368,
"WptLat": 47.64194444,
"WptLon": -1.96,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
}
]
@@ -1,110 +0,0 @@
[
{
"ID": 85228,
"TerminalID": 10653,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 166553,
"WptLat": 38.04930556,
"WptLon": 24.04694722,
"TurnDir": "",
"NavID": 3985,
"NavLat": 37.88867778,
"NavLon": 23.80449722,
"NavBear": 45,
"NavDist": 15,
"Course": 32,
"Distance": 9,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85229,
"TerminalID": 10653,
"Type": "2",
"Transition": "ALL",
"TrackCode": "AF",
"WptID": 166645,
"WptLat": 37.75945833,
"WptLon": 24.07472778,
"TurnDir": "R",
"NavID": 3985,
"NavLat": 37.88867778,
"NavLon": 23.80449722,
"NavBear": 116,
"NavDist": 15,
"Course": 45,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": -1,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85230,
"TerminalID": 10653,
"Type": "2",
"Transition": "ALL",
"TrackCode": "AF",
"WptID": 166646,
"WptLat": 37.73090833,
"WptLon": 24.04940556,
"TurnDir": "R",
"NavID": 3985,
"NavLat": 37.88867778,
"NavLon": 23.80449722,
"NavBear": 124,
"NavDist": 15,
"Course": 116,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": 220,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85231,
"TerminalID": 10653,
"Type": "2",
"Transition": "ALL",
"TrackCode": "TF",
"WptID": 166620,
"WptLat": 37.20805556,
"WptLon": 24.83444444,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
}
]
@@ -1,164 +0,0 @@
[
{
"ID": 85232,
"TerminalID": 10654,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CA",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 32,
"Distance": null,
"Alt": "00710A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85233,
"TerminalID": 10654,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 166631,
"WptLat": 38.07855556,
"WptLon": 24.06305,
"TurnDir": "",
"NavID": 4032,
"NavLat": 37.91683889,
"NavLon": 23.91443889,
"NavBear": 31,
"NavDist": 12,
"Course": 31,
"Distance": 10,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85234,
"TerminalID": 10654,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CI",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 31,
"Distance": null,
"Alt": "04000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": 210,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85235,
"TerminalID": 10654,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 166663,
"WptLat": 38.04289167,
"WptLon": 24.31536944,
"TurnDir": "",
"NavID": 4015,
"NavLat": 37.99413889,
"NavLon": 24.49490833,
"NavBear": 284,
"NavDist": 9,
"Course": 104,
"Distance": 11,
"Alt": "07000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": -1,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85236,
"TerminalID": 10654,
"Type": "2",
"Transition": "ALL",
"TrackCode": "DF",
"WptID": 253105,
"WptLat": 37.55716389,
"WptLon": 24.2987,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "24000B",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85237,
"TerminalID": 10654,
"Type": "2",
"Transition": "ALL",
"TrackCode": "TF",
"WptID": 166620,
"WptLat": 37.20805556,
"WptLon": 24.83444444,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
}
]
@@ -1,137 +0,0 @@
[
{
"ID": 85247,
"TerminalID": 10657,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 253138,
"WptLat": 37.91801944,
"WptLon": 23.93798333,
"TurnDir": "",
"NavID": 4040,
"NavLat": 37.91801944,
"NavLon": 23.93798333,
"NavBear": 0,
"NavDist": 0,
"Course": 212,
"Distance": 2,
"Alt": "00700A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85248,
"TerminalID": 10657,
"Type": "2",
"Transition": "ALL",
"TrackCode": "FA",
"WptID": 253138,
"WptLat": 37.91801944,
"WptLon": 23.93798333,
"TurnDir": "",
"NavID": 4040,
"NavLat": 37.91801944,
"NavLon": 23.93798333,
"NavBear": 0,
"NavDist": 0,
"Course": 203,
"Distance": null,
"Alt": "04000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85249,
"TerminalID": 10657,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CD",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": 4007,
"NavLat": 37.55716389,
"NavLon": 24.2987,
"NavBear": null,
"NavDist": null,
"Course": 123,
"Distance": 17,
"Alt": "06000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": 210,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85250,
"TerminalID": 10657,
"Type": "2",
"Transition": "ALL",
"TrackCode": "DF",
"WptID": 253105,
"WptLat": 37.55716389,
"WptLon": 24.2987,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "24000B",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85251,
"TerminalID": 10657,
"Type": "2",
"Transition": "ALL",
"TrackCode": "TF",
"WptID": 166620,
"WptLat": 37.20805556,
"WptLon": 24.83444444,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
}
]
@@ -1,110 +0,0 @@
[
{
"ID": 85257,
"TerminalID": 10659,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CA",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 32,
"Distance": null,
"Alt": "00710A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85258,
"TerminalID": 10659,
"Type": "2",
"Transition": "ALL",
"TrackCode": "FD",
"WptID": 253138,
"WptLat": 37.91801944,
"WptLon": 23.93798333,
"TurnDir": "",
"NavID": 4040,
"NavLat": 37.91801944,
"NavLon": 23.93798333,
"NavBear": 0,
"NavDist": 0,
"Course": 32,
"Distance": 12,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85259,
"TerminalID": 10659,
"Type": "2",
"Transition": "ALL",
"TrackCode": "DF",
"WptID": 253105,
"WptLat": 37.55716389,
"WptLon": 24.2987,
"TurnDir": "R",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "24000B06000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": 210,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85260,
"TerminalID": 10659,
"Type": "2",
"Transition": "ALL",
"TrackCode": "TF",
"WptID": 166620,
"WptLat": 37.20805556,
"WptLon": 24.83444444,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
}
]
@@ -1,110 +0,0 @@
[
{
"ID": 85331,
"TerminalID": 10679,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CA",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 32,
"Distance": null,
"Alt": "00710A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85332,
"TerminalID": 10679,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 166630,
"WptLat": 38.06507222,
"WptLon": 24.05061944,
"TurnDir": "",
"NavID": 4032,
"NavLat": 37.91683889,
"NavLon": 23.91443889,
"NavBear": 31,
"NavDist": 11,
"Course": 31,
"Distance": 10,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": -1,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85333,
"TerminalID": 10679,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CR",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "L",
"NavID": 3985,
"NavLat": 37.88867778,
"NavLon": 23.80449722,
"NavBear": 25,
"NavDist": null,
"Course": 253,
"Distance": null,
"Alt": "06000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": 240,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 85334,
"TerminalID": 10679,
"Type": "2",
"Transition": "ALL",
"TrackCode": "DF",
"WptID": 247838,
"WptLat": 37.93041111,
"WptLon": 22.9359,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
}
]
@@ -1,218 +0,0 @@
[
{
"ID": 90645,
"TerminalID": 11798,
"Type": "1",
"Transition": "RW34L",
"TrackCode": "DF",
"WptID": 169637,
"WptLat": 39.36545,
"WptLon": 8.96781667,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 90646,
"TerminalID": 11798,
"Type": "1",
"Transition": "RW34L",
"TrackCode": "FC",
"WptID": 169637,
"WptLat": 39.36545,
"WptLon": 8.96781667,
"TurnDir": "",
"NavID": 4103,
"NavLat": 39.38108333,
"NavLon": 8.96566667,
"NavBear": 170.9,
"NavDist": 0.9,
"Course": 344,
"Distance": 12,
"Alt": "05000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": -1,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 90647,
"TerminalID": 11798,
"Type": "1",
"Transition": "RW34L",
"TrackCode": "DF",
"WptID": 247859,
"WptLat": 39.36372222,
"WptLon": 8.97402778,
"TurnDir": "L",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": 270,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 90648,
"TerminalID": 11798,
"Type": "1",
"Transition": "RW34R",
"TrackCode": "DF",
"WptID": 169638,
"WptLat": 39.36699722,
"WptLon": 8.96985833,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 90649,
"TerminalID": 11798,
"Type": "1",
"Transition": "RW34R",
"TrackCode": "FC",
"WptID": 169638,
"WptLat": 39.36699722,
"WptLon": 8.96985833,
"TurnDir": "",
"NavID": 4103,
"NavLat": 39.38108333,
"NavLon": 8.96566667,
"NavBear": 164,
"NavDist": 0.9,
"Course": 344,
"Distance": 12,
"Alt": "05000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": -1,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 90650,
"TerminalID": 11798,
"Type": "1",
"Transition": "RW34R",
"TrackCode": "DF",
"WptID": 247859,
"WptLat": 39.36372222,
"WptLon": 8.97402778,
"TurnDir": "L",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": 270,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 90651,
"TerminalID": 11798,
"Type": "2",
"Transition": "ALL",
"TrackCode": "IF",
"WptID": 247859,
"WptLat": 39.36372222,
"WptLon": 8.97402778,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 90652,
"TerminalID": 11798,
"Type": "2",
"Transition": "ALL",
"TrackCode": "TF",
"WptID": 253189,
"WptLat": 39.11136111,
"WptLon": 9.50802778,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
}
]
@@ -1,623 +0,0 @@
[
{
"ID": 91603,
"TerminalID": 11909,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CA",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 346,
"Distance": null,
"Alt": "01170A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91604,
"TerminalID": 11909,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CD",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": 4169,
"NavLat": 45.64077778,
"NavLon": 8.73483333,
"NavBear": null,
"NavDist": null,
"Course": 356,
"Distance": 4.1,
"Alt": "02200A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91605,
"TerminalID": 11909,
"Type": "2",
"Transition": "ALL",
"TrackCode": "VR",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": 4169,
"NavLat": 45.64077778,
"NavLon": 8.73483333,
"NavBear": 9,
"NavDist": null,
"Course": 41,
"Distance": null,
"Alt": "03000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": 220,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91606,
"TerminalID": 11909,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 169914,
"WptLat": 45.72388889,
"WptLon": 8.86777778,
"TurnDir": "R",
"NavID": 4204,
"NavLat": 45.64597222,
"NavLon": 9.02158333,
"NavBear": 302.9,
"NavDist": 8,
"Course": 123,
"Distance": 2,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": -1,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91607,
"TerminalID": 11909,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CA",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 173,
"Distance": null,
"Alt": "04000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": 230,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91608,
"TerminalID": 11909,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 253267,
"WptLat": 45.64077778,
"WptLon": 8.73483333,
"TurnDir": "R",
"NavID": 4204,
"NavLat": 45.64597222,
"NavLon": 9.02158333,
"NavBear": 265.6,
"NavDist": 12.1,
"Course": 266,
"Distance": 5,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": 230,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91609,
"TerminalID": 11909,
"Type": "3",
"Transition": "AOS5X",
"TrackCode": "IF",
"WptID": 253267,
"WptLat": 45.64077778,
"WptLon": 8.73483333,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91610,
"TerminalID": 11909,
"Type": "3",
"Transition": "AOS5X",
"TrackCode": "TF",
"WptID": 169921,
"WptLat": 45.57482778,
"WptLon": 8.31563056,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91611,
"TerminalID": 11909,
"Type": "3",
"Transition": "AOS5X",
"TrackCode": "TF",
"WptID": 169922,
"WptLat": 45.59140556,
"WptLon": 8.24456111,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "13500A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91612,
"TerminalID": 11909,
"Type": "3",
"Transition": "AOS5X",
"TrackCode": "TF",
"WptID": 169932,
"WptLat": 45.66769722,
"WptLon": 7.91445,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "16000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91613,
"TerminalID": 11909,
"Type": "3",
"Transition": "AOS5X",
"TrackCode": "TF",
"WptID": 42141,
"WptLat": 45.79638889,
"WptLon": 7.34583333,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "19000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91614,
"TerminalID": 11909,
"Type": "3",
"Transition": "LAG9X",
"TrackCode": "IF",
"WptID": 253267,
"WptLat": 45.64077778,
"WptLon": 8.73483333,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91615,
"TerminalID": 11909,
"Type": "3",
"Transition": "LAG9X",
"TrackCode": "TF",
"WptID": 42354,
"WptLat": 45.55416667,
"WptLon": 8.44916667,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91616,
"TerminalID": 11909,
"Type": "3",
"Transition": "LAG9X",
"TrackCode": "TF",
"WptID": 42823,
"WptLat": 45.10916667,
"WptLon": 8.22972222,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91617,
"TerminalID": 11909,
"Type": "3",
"Transition": "LAG9X",
"TrackCode": "TF",
"WptID": 42487,
"WptLat": 44.39416667,
"WptLon": 8.49805556,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "11000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91618,
"TerminalID": 11909,
"Type": "3",
"Transition": "NED9X",
"TrackCode": "IF",
"WptID": 253267,
"WptLat": 45.64077778,
"WptLon": 8.73483333,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91619,
"TerminalID": 11909,
"Type": "3",
"Transition": "NED9X",
"TrackCode": "TF",
"WptID": 42354,
"WptLat": 45.55416667,
"WptLon": 8.44916667,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91620,
"TerminalID": 11909,
"Type": "3",
"Transition": "NED9X",
"TrackCode": "TF",
"WptID": 42823,
"WptLat": 45.10916667,
"WptLon": 8.22972222,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91621,
"TerminalID": 11909,
"Type": "3",
"Transition": "NED9X",
"TrackCode": "TF",
"WptID": 42584,
"WptLat": 44.69388889,
"WptLon": 8.14055556,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "20000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91622,
"TerminalID": 11909,
"Type": "3",
"Transition": "TOP9X",
"TrackCode": "IF",
"WptID": 253267,
"WptLat": 45.64077778,
"WptLon": 8.73483333,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91623,
"TerminalID": 11909,
"Type": "3",
"Transition": "TOP9X",
"TrackCode": "TF",
"WptID": 42354,
"WptLat": 45.55416667,
"WptLon": 8.44916667,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91624,
"TerminalID": 11909,
"Type": "3",
"Transition": "TOP9X",
"TrackCode": "TF",
"WptID": 42823,
"WptLat": 45.10916667,
"WptLon": 8.22972222,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 91625,
"TerminalID": 11909,
"Type": "3",
"Transition": "TOP9X",
"TrackCode": "TF",
"WptID": 253309,
"WptLat": 44.92541667,
"WptLon": 7.86166667,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
}
]
@@ -1,83 +0,0 @@
[
{
"ID": 97919,
"TerminalID": 12765,
"Type": "2",
"Transition": "ALL",
"TrackCode": "CF",
"WptID": 253373,
"WptLat": 46.95531111,
"WptLon": 15.44944444,
"TurnDir": "",
"NavID": 4275,
"NavLat": 46.95531111,
"NavLon": 15.44944444,
"NavBear": 0,
"NavDist": 0,
"Course": 164,
"Distance": 2,
"Alt": "02200A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": -1,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 97920,
"TerminalID": 12765,
"Type": "2",
"Transition": "ALL",
"TrackCode": "DF",
"WptID": 253373,
"WptLat": 46.95531111,
"WptLon": 15.44944444,
"TurnDir": "L",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "04000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 97921,
"TerminalID": 12765,
"Type": "2",
"Transition": "ALL",
"TrackCode": "HA",
"WptID": 253373,
"WptLat": 46.95531111,
"WptLon": 15.44944444,
"TurnDir": "R",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 344,
"Distance": 4,
"Alt": "04000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
}
]
@@ -1,272 +0,0 @@
[
{
"ID": 458535,
"TerminalID": 67790,
"Type": "A",
"Transition": "UPV1",
"TrackCode": "IF",
"WptID": 250431,
"WptLat": -28.40175278,
"WptLon": 21.26041111,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "05800A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458536,
"TerminalID": 67790,
"Type": "A",
"Transition": "UPV1",
"TrackCode": "PI",
"WptID": 250431,
"WptLat": -28.40175278,
"WptLon": 21.26041111,
"TurnDir": "L",
"NavID": 1333,
"NavLat": -28.40175278,
"NavLon": 21.26041111,
"NavBear": 0,
"NavDist": 0,
"Course": 213,
"Distance": 10,
"Alt": "04500A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458537,
"TerminalID": 67790,
"Type": "A",
"Transition": "UPV1",
"TrackCode": "CF",
"WptID": 113102,
"WptLat": -28.51632222,
"WptLon": 21.33836389,
"TurnDir": "",
"NavID": 1333,
"NavLat": -28.40175278,
"NavLon": 21.26041111,
"NavBear": 168,
"NavDist": 8,
"Course": 348,
"Distance": 2,
"Alt": "04500A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458538,
"TerminalID": 67790,
"Type": "A",
"Transition": "UPV2",
"TrackCode": "IF",
"WptID": 250431,
"WptLat": -28.40175278,
"WptLon": 21.26041111,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "05800A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458539,
"TerminalID": 67790,
"Type": "A",
"Transition": "UPV2",
"TrackCode": "HF",
"WptID": 250431,
"WptLat": -28.40175278,
"WptLon": 21.26041111,
"TurnDir": "L",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 348,
"Distance": 8,
"Alt": "04500A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458540,
"TerminalID": 67790,
"Type": "D",
"Transition": "",
"TrackCode": "IF",
"WptID": 113102,
"WptLat": -28.51632222,
"WptLon": 21.33836389,
"TurnDir": "",
"NavID": 1333,
"NavLat": -28.40175278,
"NavLon": 21.26041111,
"NavBear": 168,
"NavDist": 8,
"Course": null,
"Distance": null,
"Alt": "04500A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": -1,
"IsMAP": 0
},
{
"ID": 458541,
"TerminalID": 67790,
"Type": "D",
"Transition": "",
"TrackCode": "CF",
"WptID": null,
"WptLat": -28.41938889,
"WptLon": 21.27444444,
"TurnDir": "",
"NavID": 1333,
"NavLat": -28.40175278,
"NavLon": 21.26041111,
"NavBear": 163.9,
"NavDist": 1.3,
"Course": 348,
"Distance": 6.7,
"Alt": "MAP",
"Vnav": 2.45,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": -1
},
{
"ID": 458542,
"TerminalID": 67790,
"Type": "D",
"Transition": "",
"TrackCode": "CF",
"WptID": 250431,
"WptLat": -28.40175278,
"WptLon": 21.26041111,
"TurnDir": "",
"NavID": 1333,
"NavLat": -28.40175278,
"NavLon": 21.26041111,
"NavBear": 0,
"NavDist": 0,
"Course": 348,
"Distance": 1.3,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": -1,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458543,
"TerminalID": 67790,
"Type": "D",
"Transition": "",
"TrackCode": "CA",
"WptID": null,
"WptLat": null,
"WptLon": null,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 348,
"Distance": null,
"Alt": "05500A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458544,
"TerminalID": 67790,
"Type": "D",
"Transition": "",
"TrackCode": "DF",
"WptID": 250431,
"WptLat": -28.40175278,
"WptLon": 21.26041111,
"TurnDir": "L",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "05800",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
}
]
@@ -1,353 +0,0 @@
[
{
"ID": 458580,
"TerminalID": 67794,
"Type": "A",
"Transition": "FD291",
"TrackCode": "IF",
"WptID": 113125,
"WptLat": -25.65088056,
"WptLon": 28.29919167,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "08000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458581,
"TerminalID": 67794,
"Type": "A",
"Transition": "FD291",
"TrackCode": "HF",
"WptID": 113125,
"WptLat": -25.65088056,
"WptLon": 28.29919167,
"TurnDir": "R",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 284,
"Distance": 5.5,
"Alt": "07000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": 140,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458582,
"TerminalID": 67794,
"Type": "A",
"Transition": "FD292",
"TrackCode": "IF",
"WptID": 113125,
"WptLat": -25.65088056,
"WptLon": 28.29919167,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "07000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458583,
"TerminalID": 67794,
"Type": "A",
"Transition": "FD292",
"TrackCode": "TF",
"WptID": 113123,
"WptLat": -25.64774167,
"WptLon": 28.34813056,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "07000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458584,
"TerminalID": 67794,
"Type": "A",
"Transition": "FD292",
"TrackCode": "FC",
"WptID": 113123,
"WptLat": -25.64774167,
"WptLon": 28.34813056,
"TurnDir": "",
"NavID": 1283,
"NavLat": -25.65591667,
"NavLon": 28.220075,
"NavBear": 104,
"NavDist": 7,
"Course": 59,
"Distance": 2.7,
"Alt": "07000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": -1,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458585,
"TerminalID": 67794,
"Type": "A",
"Transition": "FD292",
"TrackCode": "CF",
"WptID": 113123,
"WptLat": -25.64774167,
"WptLon": 28.34813056,
"TurnDir": "R",
"NavID": 1283,
"NavLat": -25.65591667,
"NavLon": 28.220075,
"NavBear": 104,
"NavDist": 7,
"Course": 284,
"Distance": 3,
"Alt": "07000A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458586,
"TerminalID": 67794,
"Type": "A",
"Transition": "FD292",
"TrackCode": "CF",
"WptID": 113125,
"WptLat": -25.65088056,
"WptLon": 28.29919167,
"TurnDir": "",
"NavID": 1283,
"NavLat": -25.65591667,
"NavLon": 28.220075,
"NavBear": 104,
"NavDist": 4.3,
"Course": 284,
"Distance": 2.7,
"Alt": "05300A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458587,
"TerminalID": 67794,
"Type": "D",
"Transition": "",
"TrackCode": "IF",
"WptID": 113125,
"WptLat": -25.65088056,
"WptLon": 28.29919167,
"TurnDir": "",
"NavID": 1283,
"NavLat": -25.65591667,
"NavLon": 28.220075,
"NavBear": 104,
"NavDist": 4.3,
"Course": null,
"Distance": null,
"Alt": "05300A",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": -1,
"IsMAP": 0
},
{
"ID": 458588,
"TerminalID": 67794,
"Type": "D",
"Transition": "",
"TrackCode": "CF",
"WptID": 113127,
"WptLat": -25.65404722,
"WptLon": 28.24951389,
"TurnDir": "",
"NavID": 1283,
"NavLat": -25.65591667,
"NavLon": 28.220075,
"NavBear": 104,
"NavDist": 1.6,
"Course": 284,
"Distance": 2.7,
"Alt": "MAP",
"Vnav": 3,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": -1
},
{
"ID": 458589,
"TerminalID": 67794,
"Type": "D",
"Transition": "",
"TrackCode": "FD",
"WptID": 113127,
"WptLat": -25.65404722,
"WptLon": 28.24951389,
"TurnDir": "",
"NavID": 1283,
"NavLat": -25.65591667,
"NavLon": 28.220075,
"NavBear": 104,
"NavDist": 1.6,
"Course": 284,
"Distance": 2.2,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458590,
"TerminalID": 67794,
"Type": "D",
"Transition": "",
"TrackCode": "DF",
"WptID": 250381,
"WptLat": -25.65591667,
"WptLon": 28.220075,
"TurnDir": "R",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458591,
"TerminalID": 67794,
"Type": "D",
"Transition": "",
"TrackCode": "TF",
"WptID": 113125,
"WptLat": -25.65088056,
"WptLon": 28.29919167,
"TurnDir": "",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": null,
"Distance": null,
"Alt": "07000",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": null,
"IsFAF": 0,
"IsMAP": 0
},
{
"ID": 458592,
"TerminalID": 67794,
"Type": "D",
"Transition": "",
"TrackCode": "HM",
"WptID": 113125,
"WptLat": -25.65088056,
"WptLon": 28.29919167,
"TurnDir": "R",
"NavID": null,
"NavLat": null,
"NavLon": null,
"NavBear": null,
"NavDist": null,
"Course": 284,
"Distance": 4,
"Alt": "",
"Vnav": null,
"CenterID": null,
"CenterLat": null,
"CenterLon": null,
"IsFlyOver": 0,
"SpeedLimit": 140,
"IsFAF": 0,
"IsMAP": 0
}
]
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-46
View File
@@ -1,46 +0,0 @@
import { magvar } from 'magvar';
Number.prototype.toRadians = function () {
return ((this as number) * Math.PI) / 180;
};
Number.prototype.toDegrees = function () {
return ((this as number) * 180) / Math.PI;
};
Number.prototype.reciprocalCourse = function () {
let inv = (this as number) + 180;
inv = inv >= 360 ? inv - 360 : inv;
return inv;
};
Number.prototype.normaliseDegrees = function () {
return (this as number) >= 360
? (this as number) - 360
: (this as number) < 0
? (this as number) + 360
: (this as number);
};
Number.prototype.toTrue = function (fix) {
const _magvar = magvar(fix.latitude, fix.longitude); //Magvar is returned + for East
return ((this as number) + _magvar).normaliseDegrees();
};
Number.prototype.toMetre = function () {
return (this as number) * 1852.0;
};
Number.prototype.equal = function (other: number) {
return Math.abs((this as number) - other) < 0.1;
};
String.prototype.parseAltitude = function () {
switch (this.length) {
case 5:
return Number.parseInt(this as string);
case 6:
return Number.parseInt(this.substring(0, 5));
case 12: {
const upper = Number.parseInt(this.substring(0, 5));
const lower = Number.parseInt(this.substring(6, 12));
return lower + (upper - lower) / 2;
}
default:
return -1;
}
};
-19
View File
@@ -1,19 +0,0 @@
import readline from 'readline';
export const prompting = (message: string) => {
return new Promise<string | null>((resolve) => {
if (typeof prompt !== 'undefined') {
return resolve(prompt(message));
}
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question(`${message}: `, (id) => {
rl.close();
resolve(id);
});
});
};
-15
View File
@@ -1,15 +0,0 @@
@import 'tailwindcss';
@theme {
--animate-fade-in-scale: fade-in-scale 0.3s ease-out;
@keyframes fade-in-scale {
0% {
opacity: 0;
transform: scale(0.95);
}
100% {
opacity: 1;
transform: scale(1);
}
}
}
+5
View File
@@ -0,0 +1,5 @@
node_modules
.git
.gitignore
*.md
dist
+1
View File
@@ -0,0 +1 @@
v22
+19
View File
@@ -0,0 +1,19 @@
FROM node:lts-alpine AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
COPY . /app
WORKDIR /app
FROM base AS prod-deps
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile
FROM base AS build
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm run build
FROM base
COPY --from=prod-deps /app/node_modules /app/node_modules
COPY --from=build /app/dist /app/dist
EXPOSE 3003
ENTRYPOINT [ "pnpm", "serve" ]
+27
View File
@@ -0,0 +1,27 @@
networks:
traefik:
name: traefik
services:
md11-nav-data:
build: .
image: md11-nav-data
container_name: md11-nav-data-server
volumes:
- /Volumes/Data/DockerMD11NavData/NavData:/app/dist/NavData
environment:
PORT: 3003
env_file: ".env"
restart: always
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.http.routers.md11-nav-data-router.rule=Host(`md11-nav-data.hofmannnet.myhome-server.de`)"
- "traefik.http.routers.md11-nav-data-router.service=md11-nav-data-service"
- "traefik.http.services.md11-nav-data-service.loadbalancer.server.port=3003"
- "traefik.http.routers.md11-nav-data-router.entrypoints=websecure"
- "traefik.http.routers.md11-nav-data-router.tls=true"
- "traefik.http.routers.md11-nav-data-router.tls.certresolver=letsencrypt"
- "traefik.http.routers.md11-nav-data-router.middlewares=md11-nav-data-auth"
- "traefik.http.middlewares.md11-nav-data-auth.basicauth.users=tfdi:$$apr1$$gN9W1XPy$$hucbFbJGcMv/GaUgiZ/mX."
@@ -8,7 +8,7 @@
"build": "tsc -b && vite build", "build": "tsc -b && vite build",
"lint": "eslint . --ext .ts,.tsx --fix", "lint": "eslint . --ext .ts,.tsx --fix",
"preview": "vite preview", "preview": "vite preview",
"parser": "node --experimental-strip-types src/parser/node.ts" "serve": "pnpm npx http-server dist"
}, },
"dependencies": { "dependencies": {
"browser-image-manipulation": "^0.4.0", "browser-image-manipulation": "^0.4.0",
@@ -16,7 +16,6 @@
"geolib": "^3.3.4", "geolib": "^3.3.4",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"leaflet-svg-shape-markers": "^1.4.0", "leaflet-svg-shape-markers": "^1.4.0",
"magvar": "^2.0.0",
"navigraph": "^1.4.1", "navigraph": "^1.4.1",
"qrcode.react": "^4.2.0", "qrcode.react": "^4.2.0",
"react": "^19.1.0", "react": "^19.1.0",
-8
View File
@@ -23,9 +23,6 @@ importers:
leaflet-svg-shape-markers: leaflet-svg-shape-markers:
specifier: ^1.4.0 specifier: ^1.4.0
version: 1.4.0 version: 1.4.0
magvar:
specifier: ^2.0.0
version: 2.0.0
navigraph: navigraph:
specifier: ^1.4.1 specifier: ^1.4.1
version: 1.4.1 version: 1.4.1
@@ -1102,9 +1099,6 @@ packages:
magic-string@0.30.17: magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
magvar@2.0.0:
resolution: {integrity: sha512-00LpSwEJZcnyX3VsdCM2CHSCvB+M6sVQTawLCB3J9oK7eEueNltNx9GFL4YR+/HIkLM+l8rFKiY77JTKnOf0jw==}
merge2@1.4.1: merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@@ -2339,8 +2333,6 @@ snapshots:
dependencies: dependencies:
'@jridgewell/sourcemap-codec': 1.5.4 '@jridgewell/sourcemap-codec': 1.5.4
magvar@2.0.0: {}
merge2@1.4.1: {} merge2@1.4.1: {}
micromatch@4.0.8: micromatch@4.0.8:
Binary file not shown.
@@ -1,15 +1,15 @@
import type { DeviceFlowParams } from 'navigraph/auth'; import type { DeviceFlowParams } from 'navigraph/auth';
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { useState } from 'react'; import { useEffect, useState } from 'react';
import { ProcedureSelect } from './components//ProcedureSelect'; import { ProcedureSelect } from './components//ProcedureSelect';
import { Loader } from './components/Loader';
import { Map } from './components/Map'; import { Map } from './components/Map';
import { Sidebar } from './components/Sidebar'; import { Sidebar } from './components/Sidebar';
import { useNavigraphAuth } from './contexts/NavigraphAuth/NavigraphAuthContext'; import { useNavigraphAuth } from './contexts/NavigraphAuth/NavigraphAuthContext';
import Parser from './parser/parser'; import Parser from './parser/parser';
const parser = await Parser.instance();
function App() { function App() {
const [parser, setParser] = useState<Parser>();
const [selectedAirport, setSelectedAirport] = useState<Airport>(); const [selectedAirport, setSelectedAirport] = useState<Airport>();
const [selectedRunway, setSelectedRunway] = useState<Runway>(); const [selectedRunway, setSelectedRunway] = useState<Runway>();
const [selectedTerminal, setSelectedTerminal] = useState<Terminal>(); const [selectedTerminal, setSelectedTerminal] = useState<Terminal>();
@@ -17,26 +17,63 @@ function App() {
const [params, setParams] = useState<DeviceFlowParams | null>(null); const [params, setParams] = useState<DeviceFlowParams | null>(null);
const [selectedTransition, setSelectedTransition] = useState<Procedure>(); const [selectedTransition, setSelectedTransition] = useState<Procedure>();
const [selectedChart, setSelectedChart] = useState<Chart>(); const [selectedChart, setSelectedChart] = useState<Chart>();
const [skippedNG, setSkippedNG] = useState(false);
const { user, signIn, initialized } = useNavigraphAuth(); const { user, signIn, initialized } = useNavigraphAuth();
const handleSignIn = () => signIn((p) => setParams(p)); const handleSignIn = () => signIn((p) => setParams(p));
useEffect(() => {
(async () => {
setParser(await Parser.instance());
})();
}, []);
if (!parser || !initialized) {
return (
<div className="flex min-h-dvh w-full">
<div className="flex h-dvh w-dvw flex-col items-center justify-center gap-2">
<Loader size={3} />
{!parser && <span className="text-3xl">Initialising Parser...</span>}
{!initialized && <span className="text-3xl">Initialising Navigraph SDK...</span>}
</div>
</div>
);
}
return ( return (
<> <>
{!user ? ( {!user && !skippedNG ? (
<div className="flex min-h-dvh w-full"> <div className="flex min-h-dvh w-full">
{!initialized && <div>Loading...</div>} {initialized && !params && (
<div className="flex h-dvh w-dvw flex-col items-center justify-center gap-2">
<button
className="cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 font-semibold focus:outline-2 focus-visible:outline-2"
onClick={handleSignIn}
>
Sign in to NG
</button>
<button
className="cursor-pointer rounded border border-gray-600 px-2 py-1 font-semibold focus:outline-2 focus-visible:outline-2"
onClick={() => setSkippedNG(true)}
>
Skip NG
</button>
</div>
)}
{initialized && !params && !user && <button onClick={handleSignIn}>Sign in</button>} {params?.verification_uri_complete && (
<div className="flex h-dvh w-dvw flex-col items-center justify-center">
{params?.verification_uri_complete && !user && (
<>
<QRCodeSVG value={params.verification_uri_complete} size={250} /> <QRCodeSVG value={params.verification_uri_complete} size={250} />
<a href={params.verification_uri_complete} target="_blank" rel="noreferrer">
<div className="flex w-100 items-center text-center before:mr-1 before:flex-1 before:border-b-1 before:content-[''] after:ml-1 after:flex-1 after:border-b-1 after:content-['']">
or
</div>
<a className="text-3xl" href={params.verification_uri_complete} target="_blank" rel="noreferrer">
Open sign in page Open sign in page
</a> </a>
</> </div>
)} )}
</div> </div>
) : ( ) : (
@@ -49,6 +86,7 @@ function App() {
transitions={transitions} transitions={transitions}
transition={selectedTransition} transition={selectedTransition}
chart={selectedChart} chart={selectedChart}
skippedNG={skippedNG}
setTransition={setSelectedTransition} setTransition={setSelectedTransition}
setChart={setSelectedChart} setChart={setSelectedChart}
backAction={() => { backAction={() => {
@@ -60,17 +98,18 @@ function App() {
/> />
) : ( ) : (
<ProcedureSelect <ProcedureSelect
parser={parser}
selectedAirport={selectedAirport} selectedAirport={selectedAirport}
selectedRunway={selectedRunway} selectedRunway={selectedRunway}
selectedTerminal={selectedTerminal} selectedTerminal={selectedTerminal}
setSelectedAirport={setSelectedAirport} setSelectedAirport={setSelectedAirport}
setSelectedRunway={setSelectedRunway} setSelectedRunway={setSelectedRunway}
setSelectedTerminal={setSelectedTerminal} setSelectedTerminal={setSelectedTerminal}
handleSelection={(selectedTransitions) => { handleSelection={(selectedTransitions, _terminal) => {
let _transitions = selectedTransitions let _transitions = selectedTransitions
.map((transition) => ({ .map((transition) => ({
name: transition, name: transition,
data: parser.parse(selectedRunway!, transition), data: parser.parse(selectedRunway!, _terminal, transition),
})) }))
.filter( .filter(
(transition) => (transition) =>
@@ -91,6 +91,11 @@ export const Map: FC<MapProps> = ({ airport, chart, procedures }) => {
shape: 'triangle', shape: 'triangle',
radius: 6, radius: 6,
}); });
else if (properties.isInitial)
return L.shapeMarker(latlng, {
shape: 'arrowhead',
radius: 6,
});
return L.shapeMarker(latlng, { return L.shapeMarker(latlng, {
shape: 'star-4', shape: 'star-4',
@@ -2,19 +2,19 @@ import { createRef, useMemo, useState, type Dispatch, type FC, type SetStateActi
import Parser from '../parser/parser'; import Parser from '../parser/parser';
import { Loader } from './Loader'; import { Loader } from './Loader';
const parser = await Parser.instance();
interface ProcedureSelectProps { interface ProcedureSelectProps {
parser: Parser;
selectedAirport: Airport | undefined; selectedAirport: Airport | undefined;
selectedRunway: Runway | undefined; selectedRunway: Runway | undefined;
selectedTerminal: Terminal | undefined; selectedTerminal: Terminal | undefined;
setSelectedAirport: Dispatch<SetStateAction<Airport | undefined>>; setSelectedAirport: Dispatch<SetStateAction<Airport | undefined>>;
setSelectedRunway: Dispatch<SetStateAction<Runway | undefined>>; setSelectedRunway: Dispatch<SetStateAction<Runway | undefined>>;
setSelectedTerminal: Dispatch<SetStateAction<Terminal | undefined>>; setSelectedTerminal: Dispatch<SetStateAction<Terminal | undefined>>;
handleSelection: (transitions: string[]) => void; handleSelection: (transitions: string[], terminal: Terminal) => void;
} }
export const ProcedureSelect: FC<ProcedureSelectProps> = ({ export const ProcedureSelect: FC<ProcedureSelectProps> = ({
parser,
selectedAirport, selectedAirport,
selectedRunway, selectedRunway,
selectedTerminal, selectedTerminal,
@@ -125,7 +125,7 @@ export const ProcedureSelect: FC<ProcedureSelectProps> = ({
parser.loadTerminal(terminal.ID).then(() => { parser.loadTerminal(terminal.ID).then(() => {
setSelectedTerminal(terminal); setSelectedTerminal(terminal);
const transitions = new Set(parser.procedures.map((proc) => proc.Transition)); const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
handleSelection(Array.from(transitions)); handleSelection(Array.from(transitions), terminal);
setInFlight(undefined); setInFlight(undefined);
}); });
}} }}
@@ -145,10 +145,12 @@ export const ProcedureSelect: FC<ProcedureSelectProps> = ({
key={terminal.ID} key={terminal.ID}
className="cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 font-semibold focus:outline-2 focus-visible:outline-2 disabled:bg-gray-100" className="cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 font-semibold focus:outline-2 focus-visible:outline-2 disabled:bg-gray-100"
onClick={() => { onClick={() => {
setInFlight(terminal.ID);
parser.loadTerminal(terminal.ID).then(() => { parser.loadTerminal(terminal.ID).then(() => {
setSelectedTerminal(terminal); setSelectedTerminal(terminal);
const transitions = new Set(parser.procedures.map((proc) => proc.Transition)); const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
handleSelection(Array.from(transitions)); handleSelection(Array.from(transitions), terminal);
setInFlight(undefined);
}); });
}} }}
disabled={!!inFlight} disabled={!!inFlight}
@@ -167,10 +169,12 @@ export const ProcedureSelect: FC<ProcedureSelectProps> = ({
key={terminal.ID} key={terminal.ID}
className="cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 font-semibold focus:outline-2 focus-visible:outline-2 disabled:bg-gray-100" className="cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 font-semibold focus:outline-2 focus-visible:outline-2 disabled:bg-gray-100"
onClick={() => { onClick={() => {
setInFlight(terminal.ID);
parser.loadTerminal(terminal.ID).then(() => { parser.loadTerminal(terminal.ID).then(() => {
setSelectedTerminal(terminal); setSelectedTerminal(terminal);
const transitions = new Set(parser.procedures.map((proc) => proc.Transition)); const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
handleSelection(Array.from(transitions)); handleSelection(Array.from(transitions), terminal);
setInFlight(undefined);
}); });
}} }}
disabled={!!inFlight} disabled={!!inFlight}
@@ -12,6 +12,7 @@ interface SidebarProps {
transitions: Procedure[]; transitions: Procedure[];
transition: Procedure | undefined; transition: Procedure | undefined;
chart: Chart | undefined; chart: Chart | undefined;
skippedNG?: boolean;
setTransition: Dispatch<SetStateAction<SidebarProps['transition']>>; setTransition: Dispatch<SetStateAction<SidebarProps['transition']>>;
setChart: Dispatch<SetStateAction<SidebarProps['chart']>>; setChart: Dispatch<SetStateAction<SidebarProps['chart']>>;
backAction: () => void; backAction: () => void;
@@ -24,6 +25,7 @@ export const Sidebar: FC<SidebarProps> = ({
transitions, transitions,
transition, transition,
chart, chart,
skippedNG,
setTransition, setTransition,
setChart, setChart,
backAction, backAction,
@@ -36,6 +38,8 @@ export const Sidebar: FC<SidebarProps> = ({
}>({ star: [], sid: [], iap: [] }); }>({ star: [], sid: [], iap: [] });
useEffect(() => { useEffect(() => {
if (skippedNG) return;
setInFlight(true); setInFlight(true);
(async () => { (async () => {
const _chartIndex = await charts.getChartsIndex({ icao: airport.ICAO, version: 'STD' }); const _chartIndex = await charts.getChartsIndex({ icao: airport.ICAO, version: 'STD' });
@@ -134,61 +138,63 @@ export const Sidebar: FC<SidebarProps> = ({
))} ))}
</div> </div>
<div className="flex flex-col gap-2"> {!skippedNG && (
<div className="sticky top-0 z-10 -mx-2 bg-gray-500 px-2 text-lg font-semibold text-white">Charts</div>
{inFlight && <Loader size={3} />}
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<div className="sticky top-7 -mx-2 -mt-2 bg-gray-500 px-2 text-lg font-semibold text-white">Arrivals</div> <div className="sticky top-0 z-10 -mx-2 bg-gray-500 px-2 text-lg font-semibold text-white">Charts</div>
{chartIndex.star {inFlight && <Loader size={3} />}
.filter((_chart) => _chart.is_georeferenced)
.map((_chart) => (
<button
key={_chart.index_number}
className={`cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 text-left font-semibold focus:outline-2 focus:outline-black focus-visible:outline-2 focus-visible:outline-black ${chart?.index_number === _chart.index_number ? 'outline-2' : ''}`}
onClick={() => findChart(_chart)}
>
<span className="font-bold">{_chart.index_number}</span>
<br />
{_chart.name}
</button>
))}
</div>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<div className="sticky top-7 -mx-2 bg-gray-500 px-2 text-lg font-semibold text-white">Departures</div> <div className="sticky top-7 -mx-2 -mt-2 bg-gray-500 px-2 text-lg font-semibold text-white">Arrivals</div>
{chartIndex.sid {chartIndex.star
.filter((_chart) => _chart.is_georeferenced) .filter((_chart) => _chart.is_georeferenced)
.map((_chart) => ( .map((_chart) => (
<button <button
key={_chart.index_number} key={_chart.index_number}
className={`cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 text-left font-semibold focus:outline-2 focus:outline-black focus-visible:outline-2 focus-visible:outline-black ${chart?.index_number === _chart.index_number ? 'outline-2' : ''}`} className={`cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 text-left font-semibold focus:outline-2 focus:outline-black focus-visible:outline-2 focus-visible:outline-black ${chart?.index_number === _chart.index_number ? 'outline-2' : ''}`}
onClick={() => findChart(_chart)} onClick={() => findChart(_chart)}
> >
<span className="font-bold">{_chart.index_number}</span> <span className="font-bold">{_chart.index_number}</span>
<br /> <br />
{_chart.name} {_chart.name}
</button> </button>
))} ))}
</div> </div>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<div className="sticky top-7 -mx-2 bg-gray-500 px-2 text-lg font-semibold text-white">Approaches</div> <div className="sticky top-7 -mx-2 bg-gray-500 px-2 text-lg font-semibold text-white">Departures</div>
{chartIndex.iap {chartIndex.sid
.filter((_chart) => _chart.is_georeferenced) .filter((_chart) => _chart.is_georeferenced)
.map((_chart) => ( .map((_chart) => (
<button <button
key={_chart.index_number} key={_chart.index_number}
className={`cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 text-left font-semibold focus:outline-2 focus:outline-black focus-visible:outline-2 focus-visible:outline-black ${chart?.index_number === _chart.index_number ? 'outline-2' : ''}`} className={`cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 text-left font-semibold focus:outline-2 focus:outline-black focus-visible:outline-2 focus-visible:outline-black ${chart?.index_number === _chart.index_number ? 'outline-2' : ''}`}
onClick={() => findChart(_chart)} onClick={() => findChart(_chart)}
> >
<span className="font-bold">{_chart.index_number}</span> <span className="font-bold">{_chart.index_number}</span>
<br /> <br />
{_chart.name} {_chart.name}
</button> </button>
))} ))}
</div>
<div className="flex flex-col gap-2">
<div className="sticky top-7 -mx-2 bg-gray-500 px-2 text-lg font-semibold text-white">Approaches</div>
{chartIndex.iap
.filter((_chart) => _chart.is_georeferenced)
.map((_chart) => (
<button
key={_chart.index_number}
className={`cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 text-left font-semibold focus:outline-2 focus:outline-black focus-visible:outline-2 focus-visible:outline-black ${chart?.index_number === _chart.index_number ? 'outline-2' : ''}`}
onClick={() => findChart(_chart)}
>
<span className="font-bold">{_chart.index_number}</span>
<br />
{_chart.name}
</button>
))}
</div>
</div> </div>
</div> )}
</div> </div>
</div> </div>
); );
@@ -11,7 +11,11 @@ import { TerminatorsFA } from './terminators/FA';
import { TerminatorsFC } from './terminators/FC'; import { TerminatorsFC } from './terminators/FC';
import { TerminatorsFD } from './terminators/FD'; import { TerminatorsFD } from './terminators/FD';
import { TerminatorsFM } from './terminators/FM'; import { TerminatorsFM } from './terminators/FM';
import { TerminatorsHA } from './terminators/HA';
import { TerminatorsHF } from './terminators/HF';
import { TerminatorsHM } from './terminators/HM';
import { TerminatorsIF } from './terminators/IF'; import { TerminatorsIF } from './terminators/IF';
import { TerminatorsPI } from './terminators/PI';
import { TerminatorsRF } from './terminators/RF'; import { TerminatorsRF } from './terminators/RF';
import { TerminatorsTF } from './terminators/TF'; import { TerminatorsTF } from './terminators/TF';
import { TerminatorsVA } from './terminators/VA'; import { TerminatorsVA } from './terminators/VA';
@@ -21,12 +25,6 @@ import { TerminatorsVM } from './terminators/VM';
import { TerminatorsVR } from './terminators/VR'; import { TerminatorsVR } from './terminators/VR';
import './utils/extensions'; import './utils/extensions';
/*
Runway IDs for LIED
26156 - 34L
26157 - 34R
*/
class Parser { class Parser {
private static _instance: Parser; private static _instance: Parser;
@@ -37,11 +35,19 @@ class Parser {
private _procedures: TerminalEntry[] = []; private _procedures: TerminalEntry[] = [];
public static MAGVAR: Uint8Array;
public static AC_SPEED = 250; public static AC_SPEED = 250;
public static AC_BANK = 30; public static AC_BANK = 30;
public static AC_VS = 1400; public static AC_VS = 1400;
private constructor(airports: Airport[], waypoints: Waypoint[], runways: Runway[], terminals: Terminal[]) { private constructor(
magVar: Uint8Array,
airports: Airport[],
waypoints: Waypoint[],
runways: Runway[],
terminals: Terminal[]
) {
Parser.MAGVAR = magVar;
this._airports = airports; this._airports = airports;
this._waypoints = waypoints; this._waypoints = waypoints;
this._runways = runways; this._runways = runways;
@@ -50,12 +56,13 @@ class Parser {
public static instance = async () => { public static instance = async () => {
if (!Parser._instance) { if (!Parser._instance) {
const magVar = await (await fetch('NavData/magdec.bgl')).bytes();
const airports = await (await fetch('NavData/Airports.json')).json(); const airports = await (await fetch('NavData/Airports.json')).json();
const waypoints = await (await fetch('NavData/Waypoints.json')).json(); const waypoints = await (await fetch('NavData/Waypoints.json')).json();
const runways = await (await fetch('NavData/Runways.json')).json(); const runways = await (await fetch('NavData/Runways.json')).json();
const terminals = await (await fetch('NavData/Terminals.json')).json(); const terminals = await (await fetch('NavData/Terminals.json')).json();
Parser._instance = new Parser(airports, waypoints, runways, terminals); Parser._instance = new Parser(magVar, airports, waypoints, runways, terminals);
} }
return Parser._instance; return Parser._instance;
@@ -84,7 +91,7 @@ class Parser {
).json()) as TerminalEntry[]; ).json()) as TerminalEntry[];
}; };
public parse = (runway: Runway, transition: string) => { public parse = (runway: Runway, terminal: Terminal, transition: string) => {
// Private functions // Private functions
/** /**
* @param line Line segments * @param line Line segments
@@ -119,15 +126,19 @@ class Parser {
const navFixes: NavFix[] = []; const navFixes: NavFix[] = [];
const lineSegments: { line: LineSegment[]; [x: string]: unknown }[] = []; const lineSegments: { line: LineSegment[]; [x: string]: unknown }[] = [];
// Initials let lastCourse = 0;
navFixes.push({
latitude: runway.Latitude, // RWY as origin for Departures
longitude: runway.Longitude, if (terminal.Proc === 2) {
altitude: runway.Elevation, navFixes.push({
speed: 0, latitude: runway.Latitude,
name: runway.Ident, longitude: runway.Longitude,
}); altitude: runway.Elevation,
let lastCourse = runway.TrueHeading; speed: 0,
name: runway.Ident,
});
lastCourse = runway.TrueHeading;
}
const legOptions = { isMAP: false }; const legOptions = { isMAP: false };
const procedure = this._procedures.filter( const procedure = this._procedures.filter(
({ Transition }) => !Transition || Transition === transition || Transition === 'ALL' ({ Transition }) => !Transition || Transition === transition || Transition === 'ALL'
@@ -135,10 +146,32 @@ class Parser {
// Main // Main
for (let index = 0; index < procedure.length; index++) { for (let index = 0; index < procedure.length; index++) {
console.log('Processing leg with ID', procedure[index].ID);
const leg = procedure[index]; const leg = procedure[index];
leg.Alt = leg.IsMAP ? String(runway.Elevation + 200).padStart(5, '0') : leg.Alt;
const waypoint = this.waypoints.find(({ ID }) => ID === leg.WptID);
if (terminal.Proc !== 2 && navFixes.length === 0) {
if (!leg.WptLat || !leg.WptLon)
throw new Error('Non departure procedure has first leg that has no defined starting point. Cannot render.');
navFixes.push({
latitude: leg.WptLat,
longitude: leg.WptLon,
altitude: leg.Alt ? leg.Alt.parseAltitude() : runway.Elevation,
speed: leg.SpeedLimit ? leg.SpeedLimit : Parser.AC_SPEED,
name: waypoint?.Ident,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
IsFAF: leg.IsFAF,
IsMAP: leg.IsMAP,
});
}
const previousFix = navFixes.at(-1)!; const previousFix = navFixes.at(-1)!;
legOptions.isMAP ||= previousFix.IsMAP ?? false; legOptions.isMAP ||= previousFix.IsMAP ?? false;
const waypoint = this.waypoints.find(({ ID }) => ID === leg.WptID);
switch (leg.TrackCode) { switch (leg.TrackCode) {
case 'AF': { case 'AF': {
@@ -208,11 +241,21 @@ class Parser {
navFixes.at(-1)!.isFlyOver = true; navFixes.at(-1)!.isFlyOver = true;
break; break;
} }
case 'HA': case 'HA': {
case 'HF': const [fixToAdd, lineToAdd] = TerminatorsHA(leg as HATerminalEntry, previousFix);
case 'HM': update(fixToAdd, lineToAdd, { ...legOptions });
console.error('Unknown TrackCode', leg.TrackCode);
break; break;
}
case 'HF': {
const [fixToAdd, lineToAdd] = TerminatorsHF(leg as HFTerminalEntry, previousFix);
update(fixToAdd, lineToAdd, { ...legOptions });
break;
}
case 'HM': {
const [fixToAdd, lineToAdd] = TerminatorsHM(leg as HMTerminalEntry, previousFix);
update(fixToAdd, lineToAdd, { ...legOptions });
break;
}
case 'IF': { case 'IF': {
const fixToAdd = TerminatorsIF(leg as RFTerminalEntry, waypoint); const fixToAdd = TerminatorsIF(leg as RFTerminalEntry, waypoint);
// Only Runway, replace // Only Runway, replace
@@ -222,9 +265,16 @@ class Parser {
} }
break; break;
} }
case 'PI': case 'PI': {
console.error('Unknown TrackCode', leg.TrackCode); const nextLeg = procedure[index + 1] as CFTerminalEntry;
const _waypoint = this.waypoints.find(({ ID }) => ID === nextLeg.WptID);
const [fixToAdd, lineToAdd] = TerminatorsPI(leg as PITerminalEntry, nextLeg, previousFix, [
waypoint,
_waypoint,
]);
update(fixToAdd, lineToAdd, { ...legOptions });
break; break;
}
case 'RF': { case 'RF': {
const [fixToAdd, lineToAdd] = TerminatorsRF(leg as RFTerminalEntry, previousFix, lastCourse, waypoint); const [fixToAdd, lineToAdd] = TerminatorsRF(leg as RFTerminalEntry, previousFix, lastCourse, waypoint);
if (fixToAdd) { if (fixToAdd) {
@@ -1,4 +1,5 @@
import computeDestinationPoint from 'geolib/es/computeDestinationPoint'; import computeDestinationPoint from 'geolib/es/computeDestinationPoint';
import getGreatCircleBearing from 'geolib/es/getGreatCircleBearing';
import getPreciseDistance from 'geolib/es/getPreciseDistance'; import getPreciseDistance from 'geolib/es/getPreciseDistance';
/** /**
@@ -6,7 +7,8 @@ import getPreciseDistance from 'geolib/es/getPreciseDistance';
* @param crsIntoOrigin Course into arc origin point * @param crsIntoOrigin Course into arc origin point
* @param start Arc origin point * @param start Arc origin point
* @param center Arc center point * @param center Arc center point
* @param turnDir * @param end Arc end point
* @param turnDir Turn Direction
* @returns Line segments * @returns Line segments
*/ */
export const generateRFArc = ( export const generateRFArc = (
@@ -14,6 +16,7 @@ export const generateRFArc = (
crsIntoOrigin: number, crsIntoOrigin: number,
start: NavFix, start: NavFix,
center: NavFix, center: NavFix,
end: NavFix,
turnDir: TurnDirection turnDir: TurnDirection
) => { ) => {
const line: LineSegment[] = [[start.longitude, start.latitude]]; const line: LineSegment[] = [[start.longitude, start.latitude]];
@@ -26,20 +29,10 @@ export const generateRFArc = (
turnDir = prov > 0 ? 'L' : 'R'; turnDir = prov > 0 ? 'L' : 'R';
} }
let crsOrthogonalOnOrigin; let crsOrthogonalOnOrigin = getGreatCircleBearing(center, start);
let crsOrthogonalOnEndpoint; const crsOrthogonalOnEndpoint = getGreatCircleBearing(center, end);
if (turnDir === 'R') {
crsOrthogonalOnOrigin = (crsIntoOrigin + 90).normaliseDegrees();
crsOrthogonalOnEndpoint = (crsIntoEndpoint + 90).normaliseDegrees();
} else {
crsOrthogonalOnOrigin = (crsIntoOrigin - 90).normaliseDegrees();
crsOrthogonalOnEndpoint = (crsIntoEndpoint - 90).normaliseDegrees();
}
const arcRad = getPreciseDistance(center, start); const arcRad = getPreciseDistance(center, start);
crsOrthogonalOnOrigin = crsOrthogonalOnOrigin.reciprocalCourse();
crsOrthogonalOnEndpoint = crsOrthogonalOnEndpoint.reciprocalCourse();
// Start turn immediately // Start turn immediately
if (turnDir === 'R') { if (turnDir === 'R') {
crsOrthogonalOnOrigin += crsOrthogonalOnOrigin < 1 ? crsOrthogonalOnOrigin : 1; crsOrthogonalOnOrigin += crsOrthogonalOnOrigin < 1 ? crsOrthogonalOnOrigin : 1;
@@ -63,7 +63,7 @@ export const generateTangentArc = (
intcArcOnCrsIntoEndpoint, intcArcOnCrsIntoEndpoint,
crsOrthogonalOnEndpoint crsOrthogonalOnEndpoint
); );
if (Math.abs(crsOrthogonalOnEndpoint - crsOrthogonalOnOrigin) <= 0.1 && arcCenter) if (!crsOrthogonalOnEndpoint.equal(crsOrthogonalOnOrigin) && arcCenter)
arcRad = getPreciseDistance(arcCenter, start); arcRad = getPreciseDistance(arcCenter, start);
else { else {
arcRad = getPreciseDistance(start, end) / 2; arcRad = getPreciseDistance(start, end) / 2;
@@ -3,6 +3,7 @@ import getGreatCircleBearing from 'geolib/es/getGreatCircleBearing';
import getPreciseDistance from 'geolib/es/getPreciseDistance'; import getPreciseDistance from 'geolib/es/getPreciseDistance';
import Parser from '../parser'; import Parser from '../parser';
import { generateTangentArc } from '../pathGenerators/generateTangentArc'; import { generateTangentArc } from '../pathGenerators/generateTangentArc';
import { computeIntersection } from '../utils/computeIntersection';
import { computeSpeed } from '../utils/computeSpeed'; import { computeSpeed } from '../utils/computeSpeed';
import { computeTurnRate } from '../utils/computeTurnRate'; import { computeTurnRate } from '../utils/computeTurnRate';
@@ -28,7 +29,6 @@ export const TerminatorsCF = (
IsFAF: leg.IsFAF, IsFAF: leg.IsFAF,
IsMAP: leg.IsMAP, IsMAP: leg.IsMAP,
}; };
const crsToIntercept = leg.Course.toTrue(targetFix);
// Compute overfly arc // Compute overfly arc
let arc1: LineSegment[] | null = null; let arc1: LineSegment[] | null = null;
@@ -59,7 +59,13 @@ export const TerminatorsCF = (
if (endDist <= 25 || (endCrs <= crsIntoEndpoint + 1 && endCrs >= crsIntoEndpoint - 1)) arc = arc1; if (endDist <= 25 || (endCrs <= crsIntoEndpoint + 1 && endCrs >= crsIntoEndpoint - 1)) arc = arc1;
} }
if (previousFix.isFlyOver && (!lastCourse.equal(crsIntoEndpoint) || !lastCourse.equal(crsToIntercept))) { const intercept = computeIntersection(previousFix, lastCourse, targetFix, crsIntoEndpoint.reciprocalCourse());
if (
!arc &&
previousFix.isFlyOver &&
(!lastCourse.equal(crsIntoEndpoint) || !lastCourse.equal(crsIntoEndpoint)) &&
!(intercept?.latitude === targetFix.latitude && intercept.longitude === targetFix.longitude)
) {
const turnRate = computeTurnRate(speed, Parser.AC_BANK); const turnRate = computeTurnRate(speed, Parser.AC_BANK);
let updatedCrsToIntercept = getGreatCircleBearing(previousFix, targetFix); let updatedCrsToIntercept = getGreatCircleBearing(previousFix, targetFix);
@@ -72,19 +78,26 @@ export const TerminatorsCF = (
// Generate arc // Generate arc
let lastDistance = getPreciseDistance(previousFix, targetFix); let lastDistance = getPreciseDistance(previousFix, targetFix);
while (!updatedCrsToIntercept.equal(crsToIntercept)) { const reversal = Math.abs(lastCourse - crsIntoEndpoint) >= 90;
while (!updatedCrsToIntercept.equal(crsIntoEndpoint)) {
let interceptAngle = 0; let interceptAngle = 0;
if (leg.TurnDir === 'R') interceptAngle = Math.abs(lastCourse - crsToIntercept); if (leg.TurnDir === 'R') interceptAngle = Math.abs(lastCourse - crsIntoEndpoint);
else interceptAngle = Math.abs(crsToIntercept - lastCourse); else interceptAngle = Math.abs(crsIntoEndpoint - lastCourse);
let time = 0; let time = 0;
const increment = 0.1; const increment = 0.1;
if (interceptAngle < 44.9 || interceptAngle >= 45.1) { if (interceptAngle < 44.9 || interceptAngle >= 45.1) {
if (leg.TurnDir === 'R') { if (leg.TurnDir === 'R') {
lastCourse = (lastCourse + increment).normaliseDegrees(); lastCourse =
reversal || updatedCrsToIntercept >= crsIntoEndpoint
? (lastCourse + increment).normaliseDegrees()
: lastCourse;
time = increment / turnRate; time = increment / turnRate;
} else { } else {
lastCourse = (lastCourse - increment).normaliseDegrees(); lastCourse =
reversal || updatedCrsToIntercept <= crsIntoEndpoint
? (lastCourse - increment).normaliseDegrees()
: lastCourse;
time = increment / turnRate; time = increment / turnRate;
} }
} else time = increment / turnRate; } else time = increment / turnRate;
@@ -80,7 +80,7 @@ export const TerminatorsFC = (
} }
const targetFix: NavFix = { const targetFix: NavFix = {
...computeDestinationPoint(arcEnd, leg.Distance.toMetre(), lastCourse), ...computeDestinationPoint(arcEnd, leg.Distance.toMetre(), leg.Course.toTrue(refFix)),
name: leg.Distance.toString(), name: leg.Distance.toString(),
isFlyOver: true, isFlyOver: true,
altitude: leg.Alt ? leg.Alt.parseAltitude() : previousFix.altitude, altitude: leg.Alt ? leg.Alt.parseAltitude() : previousFix.altitude,
@@ -41,7 +41,7 @@ export const TerminatorsFD = (
// Compute intercept of crs from arc end and distance // Compute intercept of crs from arc end and distance
const targetFix: NavFix = { const targetFix: NavFix = {
...computeDestinationPoint(arcEnd, remainingDistance, lastCourse), ...computeDestinationPoint(arcEnd, remainingDistance, crsIntoEndpoint),
name: leg.Distance.toString(), name: leg.Distance.toString(),
isFlyOver: true, isFlyOver: true,
altitude: leg.Alt ? leg.Alt.parseAltitude() : previousFix.altitude, altitude: leg.Alt ? leg.Alt.parseAltitude() : previousFix.altitude,
@@ -0,0 +1,88 @@
import computeDestinationPoint from 'geolib/es/computeDestinationPoint';
import Parser from '../parser';
import { computeSpeed } from '../utils/computeSpeed';
import { computeTurnRate } from '../utils/computeTurnRate';
// NOTE: Distance is interpreted as distance and not time
export const TerminatorsHA = (leg: HATerminalEntry, previousFix: NavFix): [NavFix?, LineSegment[]?] => {
const refFix = {
latitude: leg.WptLat,
longitude: leg.WptLon,
};
const speed = computeSpeed(leg, previousFix);
const turnRate = computeTurnRate(speed, Parser.AC_BANK);
const inboundCrs = leg.Course.toTrue(refFix);
const outboundCrs = inboundCrs.reciprocalCourse();
const line: LineSegment[] = [[previousFix.longitude, previousFix.latitude]];
// Generate top arc
let currentCrs = inboundCrs;
while (!currentCrs.equal(outboundCrs)) {
let time = 0;
if (leg.TurnDir === 'R') {
const delta = (outboundCrs - currentCrs).normaliseDegrees();
const increment = delta < 0.1 ? delta : 0.1;
currentCrs = (currentCrs + increment).normaliseDegrees();
time = increment / turnRate;
} else {
const delta = (currentCrs - outboundCrs).normaliseDegrees();
const increment = delta < 0.1 ? delta : 0.1;
currentCrs = (currentCrs - increment).normaliseDegrees();
time = increment / turnRate;
}
const arcFix = computeDestinationPoint(
{
latitude: line.at(-1)![1],
longitude: line.at(-1)![0],
},
((speed / 3600) * time).toMetre(),
currentCrs
);
line.push([arcFix.longitude, arcFix.latitude]);
}
const outboundStart = computeDestinationPoint(
{
latitude: line.at(-1)![1],
longitude: line.at(-1)![0],
},
leg.Distance.toMetre(),
outboundCrs
);
line.push([outboundStart.longitude, outboundStart.latitude]);
// Generate bottom arc
currentCrs = outboundCrs;
while (!currentCrs.equal(inboundCrs)) {
let time = 0;
if (leg.TurnDir === 'R') {
const delta = (inboundCrs - currentCrs).normaliseDegrees();
const increment = delta < 0.1 ? delta : 0.1;
currentCrs = (currentCrs + increment).normaliseDegrees();
time = increment / turnRate;
} else {
const delta = (currentCrs - inboundCrs).normaliseDegrees();
const increment = delta < 0.1 ? delta : 0.1;
currentCrs = (currentCrs - increment).normaliseDegrees();
time = increment / turnRate;
}
const arcFix = computeDestinationPoint(
{
latitude: line.at(-1)![1],
longitude: line.at(-1)![0],
},
((speed / 3600) * time).toMetre(),
currentCrs
);
line.push([arcFix.longitude, arcFix.latitude]);
}
line.push([refFix.longitude, refFix.latitude]);
return [refFix, line];
};
@@ -0,0 +1,88 @@
import computeDestinationPoint from 'geolib/es/computeDestinationPoint';
import Parser from '../parser';
import { computeSpeed } from '../utils/computeSpeed';
import { computeTurnRate } from '../utils/computeTurnRate';
// NOTE: Distance is interpreted as distance and not time
export const TerminatorsHF = (leg: HFTerminalEntry, previousFix: NavFix): [NavFix?, LineSegment[]?] => {
const refFix = {
latitude: leg.WptLat,
longitude: leg.WptLon,
};
const speed = computeSpeed(leg, previousFix);
const turnRate = computeTurnRate(speed, Parser.AC_BANK);
const inboundCrs = leg.Course.toTrue(refFix);
const outboundCrs = inboundCrs.reciprocalCourse();
const line: LineSegment[] = [[previousFix.longitude, previousFix.latitude]];
// Generate top arc
let currentCrs = inboundCrs;
while (!currentCrs.equal(outboundCrs)) {
let time = 0;
if (leg.TurnDir === 'R') {
const delta = (outboundCrs - currentCrs).normaliseDegrees();
const increment = delta < 0.1 ? delta : 0.1;
currentCrs = (currentCrs + increment).normaliseDegrees();
time = increment / turnRate;
} else {
const delta = (currentCrs - outboundCrs).normaliseDegrees();
const increment = delta < 0.1 ? delta : 0.1;
currentCrs = (currentCrs - increment).normaliseDegrees();
time = increment / turnRate;
}
const arcFix = computeDestinationPoint(
{
latitude: line.at(-1)![1],
longitude: line.at(-1)![0],
},
((speed / 3600) * time).toMetre(),
currentCrs
);
line.push([arcFix.longitude, arcFix.latitude]);
}
const outboundStart = computeDestinationPoint(
{
latitude: line.at(-1)![1],
longitude: line.at(-1)![0],
},
leg.Distance.toMetre(),
outboundCrs
);
line.push([outboundStart.longitude, outboundStart.latitude]);
// Generate bottom arc
currentCrs = outboundCrs;
while (!currentCrs.equal(inboundCrs)) {
let time = 0;
if (leg.TurnDir === 'R') {
const delta = (inboundCrs - currentCrs).normaliseDegrees();
const increment = delta < 0.1 ? delta : 0.1;
currentCrs = (currentCrs + increment).normaliseDegrees();
time = increment / turnRate;
} else {
const delta = (currentCrs - inboundCrs).normaliseDegrees();
const increment = delta < 0.1 ? delta : 0.1;
currentCrs = (currentCrs - increment).normaliseDegrees();
time = increment / turnRate;
}
const arcFix = computeDestinationPoint(
{
latitude: line.at(-1)![1],
longitude: line.at(-1)![0],
},
((speed / 3600) * time).toMetre(),
currentCrs
);
line.push([arcFix.longitude, arcFix.latitude]);
}
line.push([refFix.longitude, refFix.latitude]);
return [refFix, line];
};
@@ -0,0 +1,88 @@
import computeDestinationPoint from 'geolib/es/computeDestinationPoint';
import Parser from '../parser';
import { computeSpeed } from '../utils/computeSpeed';
import { computeTurnRate } from '../utils/computeTurnRate';
// NOTE: Distance is interpreted as distance and not time
export const TerminatorsHM = (leg: HMTerminalEntry, previousFix: NavFix): [NavFix?, LineSegment[]?] => {
const refFix = {
latitude: leg.WptLat,
longitude: leg.WptLon,
};
const speed = computeSpeed(leg, previousFix);
const turnRate = computeTurnRate(speed, Parser.AC_BANK);
const inboundCrs = leg.Course.toTrue(refFix);
const outboundCrs = inboundCrs.reciprocalCourse();
const line: LineSegment[] = [[previousFix.longitude, previousFix.latitude]];
// Generate top arc
let currentCrs = inboundCrs;
while (!currentCrs.equal(outboundCrs)) {
let time = 0;
if (leg.TurnDir === 'R') {
const delta = (outboundCrs - currentCrs).normaliseDegrees();
const increment = delta < 0.1 ? delta : 0.1;
currentCrs = (currentCrs + increment).normaliseDegrees();
time = increment / turnRate;
} else {
const delta = (currentCrs - outboundCrs).normaliseDegrees();
const increment = delta < 0.1 ? delta : 0.1;
currentCrs = (currentCrs - increment).normaliseDegrees();
time = increment / turnRate;
}
const arcFix = computeDestinationPoint(
{
latitude: line.at(-1)![1],
longitude: line.at(-1)![0],
},
((speed / 3600) * time).toMetre(),
currentCrs
);
line.push([arcFix.longitude, arcFix.latitude]);
}
const outboundStart = computeDestinationPoint(
{
latitude: line.at(-1)![1],
longitude: line.at(-1)![0],
},
leg.Distance.toMetre(),
outboundCrs
);
line.push([outboundStart.longitude, outboundStart.latitude]);
// Generate bottom arc
currentCrs = outboundCrs;
while (!currentCrs.equal(inboundCrs)) {
let time = 0;
if (leg.TurnDir === 'R') {
const delta = (inboundCrs - currentCrs).normaliseDegrees();
const increment = delta < 0.1 ? delta : 0.1;
currentCrs = (currentCrs + increment).normaliseDegrees();
time = increment / turnRate;
} else {
const delta = (currentCrs - inboundCrs).normaliseDegrees();
const increment = delta < 0.1 ? delta : 0.1;
currentCrs = (currentCrs - increment).normaliseDegrees();
time = increment / turnRate;
}
const arcFix = computeDestinationPoint(
{
latitude: line.at(-1)![1],
longitude: line.at(-1)![0],
},
((speed / 3600) * time).toMetre(),
currentCrs
);
line.push([arcFix.longitude, arcFix.latitude]);
}
line.push([refFix.longitude, refFix.latitude]);
return [refFix, line];
};
@@ -12,6 +12,7 @@ export const TerminatorsIF = (leg: IFTerminalEntry, waypoint?: Waypoint): NavFix
altitudeConstraint: leg.Alt, altitudeConstraint: leg.Alt,
IsFAF: leg.IsFAF, IsFAF: leg.IsFAF,
IsMAP: leg.IsMAP, IsMAP: leg.IsMAP,
isInitial: true,
}; };
return targetFix; return targetFix;
@@ -0,0 +1,72 @@
import computeDestinationPoint from 'geolib/es/computeDestinationPoint';
import { generatePerformanceArc } from '../pathGenerators/generatePerformanceArc';
import { computeIntersection } from '../utils/computeIntersection';
import { computeSpeed } from '../utils/computeSpeed';
export const TerminatorsPI = (
leg: PITerminalEntry,
nextLeg: CFTerminalEntry, // As per NG docs in the TrmLegTypes.json
previousFix: NavFix,
waypoints: [Waypoint?, Waypoint?]
): [NavFix?, LineSegment[]?] => {
const speed = computeSpeed(leg, previousFix);
const originFix: NavFix = {
latitude: leg.WptLat,
longitude: leg.WptLon,
name: waypoints[0]?.Ident ?? undefined,
isFlyOver: leg.IsFlyOver,
altitude: leg.Alt ? leg.Alt.parseAltitude() : previousFix.altitude,
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
IsFAF: leg.IsFAF,
IsMAP: leg.IsMAP,
};
const endFix: NavFix = {
latitude: nextLeg.WptLat,
longitude: nextLeg.WptLon,
name: waypoints[1]?.Ident ?? undefined,
isFlyOver: leg.IsFlyOver,
altitude: leg.Alt ? leg.Alt.parseAltitude() : previousFix.altitude,
speed: speed,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
IsFAF: leg.IsFAF,
IsMAP: leg.IsMAP,
};
const outboundCrs = leg.Course.toTrue(endFix);
const interceptCrs = nextLeg.Course.toTrue(endFix);
const line: LineSegment[] = [
[originFix.longitude, originFix.latitude],
[endFix.longitude, endFix.latitude],
];
// Outbound end
const outEnd = computeDestinationPoint(
endFix,
((speed / 3600) * 60).toMetre(), // 1min leg
outboundCrs
);
line.push([outEnd.longitude, outEnd.latitude]);
// Arc
line.push(...generatePerformanceArc(outboundCrs.reciprocalCourse(), outboundCrs, outEnd, speed, leg.TurnDir));
// Intercept
const interceptFix = computeIntersection(
{
latitude: line.at(-1)![1],
longitude: line.at(-1)![0],
},
outboundCrs.reciprocalCourse(),
endFix,
interceptCrs.reciprocalCourse()
);
line.push([interceptFix!.longitude, interceptFix!.latitude]);
line.push([endFix!.longitude, endFix!.latitude]);
return [undefined, line];
};
@@ -26,6 +26,7 @@ export const TerminatorsRF = (
lastCourse, lastCourse,
previousFix, previousFix,
{ latitude: leg.CenterLat, longitude: leg.CenterLon }, { latitude: leg.CenterLat, longitude: leg.CenterLon },
targetFix,
leg.TurnDir leg.TurnDir
); );
@@ -32,7 +32,7 @@ export const TerminatorsTF = (
// Compute overfly arc // Compute overfly arc
let arc1: LineSegment[] | null = null; let arc1: LineSegment[] | null = null;
let arc2: LineSegment[] = [[previousFix.longitude, previousFix.latitude]]; let arc2: LineSegment[] = [[previousFix.longitude, previousFix.latitude]];
if (previousFix.isFlyOver) { if (previousFix.isFlyOver && !lastCourse.equal(crsIntoEndpoint, 0.5)) {
arc1 = generateTangentArc(crsIntoEndpoint, lastCourse, previousFix, targetFix, leg.TurnDir); arc1 = generateTangentArc(crsIntoEndpoint, lastCourse, previousFix, targetFix, leg.TurnDir);
} else { } else {
arc1 = [[previousFix.longitude, previousFix.latitude]]; arc1 = [[previousFix.longitude, previousFix.latitude]];
@@ -58,7 +58,7 @@ export const TerminatorsTF = (
if (endDist <= 25 || (endCrs <= crsIntoEndpoint + 1 && endCrs >= crsIntoEndpoint - 1)) arc = arc1; if (endDist <= 25 || (endCrs <= crsIntoEndpoint + 1 && endCrs >= crsIntoEndpoint - 1)) arc = arc1;
} }
if (previousFix.isFlyOver && (!lastCourse.equal(crsIntoEndpoint) || !lastCourse.equal(crsIntoEndpoint))) { if (!arc && previousFix.isFlyOver && (!lastCourse.equal(crsIntoEndpoint) || !lastCourse.equal(crsIntoEndpoint))) {
const turnRate = computeTurnRate(speed, Parser.AC_BANK); const turnRate = computeTurnRate(speed, Parser.AC_BANK);
let updatedCrsToIntercept = getGreatCircleBearing(previousFix, targetFix); let updatedCrsToIntercept = getGreatCircleBearing(previousFix, targetFix);
@@ -80,10 +80,12 @@ export const TerminatorsTF = (
const increment = 0.1; const increment = 0.1;
if (interceptAngle < 44.9 || interceptAngle >= 45.1) { if (interceptAngle < 44.9 || interceptAngle >= 45.1) {
if (leg.TurnDir === 'R') { if (leg.TurnDir === 'R') {
lastCourse = (lastCourse + increment).normaliseDegrees(); lastCourse =
updatedCrsToIntercept >= crsIntoEndpoint ? (lastCourse + increment).normaliseDegrees() : lastCourse;
time = increment / turnRate; time = increment / turnRate;
} else { } else {
lastCourse = (lastCourse - increment).normaliseDegrees(); lastCourse =
updatedCrsToIntercept >= crsIntoEndpoint ? (lastCourse - increment).normaliseDegrees() : lastCourse;
time = increment / turnRate; time = increment / turnRate;
} }
} else time = increment / turnRate; } else time = increment / turnRate;
@@ -0,0 +1,80 @@
import Parser from '../parser';
Number.prototype.toRadians = function () {
return ((this as number) * Math.PI) / 180;
};
Number.prototype.toDegrees = function () {
return ((this as number) * 180) / Math.PI;
};
Number.prototype.reciprocalCourse = function () {
let inv = (this as number) + 180;
inv = inv >= 360 ? inv - 360 : inv;
return inv;
};
Number.prototype.normaliseDegrees = function () {
return (this as number) >= 360
? (this as number) - 360
: (this as number) < 0
? (this as number) + 360
: (this as number);
};
Number.prototype.toTrue = function (fix) {
const toOffset = (lat: number, lon: number) =>
lon >= 0 ? lon * 362 + lat * 2 + 316 : (lon + 360) * 362 + lat * 2 + 316;
const magVarTable = Parser.MAGVAR;
const lowerLat = Math.floor(fix.latitude);
const upperLat = Math.ceil(fix.latitude);
const ratioLat = fix.latitude - lowerLat;
const lowerLon = Math.floor(fix.longitude);
const upperLon = Math.ceil(fix.longitude);
const ratioLon = fix.longitude - lowerLon;
const lowerLatLowerLonOffset = toOffset(lowerLat, lowerLon);
const lowerLatUpperLonOffset = toOffset(lowerLat, upperLon);
const upperLatLowerLonOffset = toOffset(upperLat, lowerLon);
const upperLatUpperLonOffset = toOffset(upperLat, upperLon);
let lowerLatLowerLonMagVar = (magVarTable[lowerLatLowerLonOffset + 1] << 8) + magVarTable[lowerLatLowerLonOffset];
lowerLatLowerLonMagVar = (lowerLatLowerLonMagVar * 0x168) / 0x10000;
lowerLatLowerLonMagVar = lowerLatLowerLonMagVar > 180 ? lowerLatLowerLonMagVar - 360 : lowerLatLowerLonMagVar;
let lowerLatUpperLonMagVar = (magVarTable[lowerLatUpperLonOffset + 1] << 8) + magVarTable[lowerLatUpperLonOffset];
lowerLatUpperLonMagVar = (lowerLatUpperLonMagVar * 0x168) / 0x10000;
lowerLatUpperLonMagVar = lowerLatUpperLonMagVar > 180 ? lowerLatUpperLonMagVar - 360 : lowerLatUpperLonMagVar;
let upperLatLowerLonMagVar = (magVarTable[upperLatLowerLonOffset + 1] << 8) + magVarTable[upperLatLowerLonOffset];
upperLatLowerLonMagVar = (upperLatLowerLonMagVar * 0x168) / 0x10000;
upperLatLowerLonMagVar = upperLatLowerLonMagVar > 180 ? upperLatLowerLonMagVar - 360 : upperLatLowerLonMagVar;
let upperLatUpperLonMagVar = (magVarTable[upperLatUpperLonOffset + 1] << 8) + magVarTable[upperLatUpperLonOffset];
upperLatUpperLonMagVar = (upperLatUpperLonMagVar * 0x168) / 0x10000;
upperLatUpperLonMagVar = upperLatUpperLonMagVar > 180 ? upperLatUpperLonMagVar - 360 : upperLatUpperLonMagVar;
const lowerLatRatioLon = lowerLatLowerLonMagVar + ratioLon * (lowerLatUpperLonMagVar - lowerLatLowerLonMagVar);
const upperLatRatioLon = upperLatLowerLonMagVar + ratioLon * (upperLatUpperLonMagVar - upperLatLowerLonMagVar);
const magVar = lowerLatRatioLon + ratioLat + (upperLatRatioLon - lowerLatRatioLon);
return ((this as number) + magVar).normaliseDegrees();
};
Number.prototype.toMetre = function () {
return (this as number) * 1852.0;
};
Number.prototype.equal = function (other: number, accuracy = 0.1) {
return Math.abs((this as number) - other) <= accuracy;
};
String.prototype.parseAltitude = function () {
switch (this.length) {
case 5:
return Number.parseInt(this as string);
case 6:
return Number.parseInt(this.substring(0, 5));
case 12: {
const upper = Number.parseInt(this.substring(0, 5));
const lower = Number.parseInt(this.substring(6, 12));
return lower + (upper - lower) / 2;
}
default:
return -1;
}
};
@@ -1,3 +1,4 @@
import computeDestinationPoint from 'geolib/es/computeDestinationPoint';
import getGreatCircleBearing from 'geolib/es/getGreatCircleBearing'; import getGreatCircleBearing from 'geolib/es/getGreatCircleBearing';
/** /**
@@ -29,8 +30,12 @@ export const getCourseAndFixForIntercepts = (leg: TerminalEntry, origin: NavFix)
} }
case 'AF': { case 'AF': {
const _leg = leg as AFTerminalEntry; const _leg = leg as AFTerminalEntry;
const fix = { latitude: _leg.WptLat, longitude: _leg.WptLon }; const navAid = { latitude: _leg.NavLat, longitude: _leg.NavLon };
return [_leg.Course.reciprocalCourse().toTrue(fix), fix]; const fix = {
...computeDestinationPoint(navAid, _leg.NavDist.toMetre(), _leg.Course.toTrue(navAid)),
isIntersection: true,
};
return [_leg.Course.toTrue(fix), fix];
} }
case 'DF': { case 'DF': {
const _leg = leg as DFTerminalEntry; const _leg = leg as DFTerminalEntry;
+1
View File
@@ -0,0 +1 @@
@import 'tailwindcss';
@@ -26,9 +26,9 @@ export declare global {
*/ */
toMetre: () => number; toMetre: () => number;
/** /**
* @returns True if delta is less than 0.1 * @returns True if delta is less than accuracy (default 0.1)
*/ */
equal: (other: number) => boolean; equal: (other: number, accuracy?: number) => boolean;
} }
interface String { interface String {
@@ -91,6 +91,7 @@ export declare global {
IsMAP?: boolean; IsMAP?: boolean;
// For map // For map
isIntersection?: boolean; isIntersection?: boolean;
isInitial?: boolean;
}; };
type LineSegment = [number, number]; type LineSegment = [number, number];

Some files were not shown because too many files have changed in this diff Show More