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",
"name": "Launch Chrome against localhost",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}/browser",
"webRoot": "${workspaceFolder}/md11-nav-data",
"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.
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)
@@ -346,7 +346,7 @@ LFPV 27 PB2V SID (Cycle 2507, ID 10395)
- `NavDist` is in **nmi**. `NavDist` is geodesic.
## Holding mandatory (HA)
## Holding mandatory (altitude end) (HA)
### 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.
## Holding mandatory (HM)
## Holding mandatory (manual end) (HM)
### Example
@@ -493,8 +493,11 @@ FAUP VDM35 APP (Cycle 2507, ID 67790)
### Instructions
- From the fix identified by (`WptID`, `WptLat`, `WptLon`) *or*
(`NavID`, `NavLat`, `NavLon`, `NavDist`, `NavBear`), fly `Course` for `Distance`.
- Turn `TurnDir` until aligned with succeeding leg course.
(`NavID`, `NavLat`, `NavLon`, `NavDist`, `NavBear`), fly direct to succeeding leg fix.
- 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.
### Units
@@ -505,8 +508,10 @@ FAUP VDM35 APP (Cycle 2507, ID 67790)
### Notes
This needs to look into the succeeding leg in order to calculate the intercept point.
This intercept point then becomes the origin fix of the succeeding leg.
This needs to look into the succeeding leg in order to fly the first segment and get the course
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)
@@ -702,4 +707,23 @@ This intercept point then becomes the origin fix of the succeeding leg.
# 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",
"lint": "eslint . --ext .ts,.tsx --fix",
"preview": "vite preview",
"parser": "node --experimental-strip-types src/parser/node.ts"
"serve": "pnpm npx http-server dist"
},
"dependencies": {
"browser-image-manipulation": "^0.4.0",
@@ -16,7 +16,6 @@
"geolib": "^3.3.4",
"leaflet": "^1.9.4",
"leaflet-svg-shape-markers": "^1.4.0",
"magvar": "^2.0.0",
"navigraph": "^1.4.1",
"qrcode.react": "^4.2.0",
"react": "^19.1.0",
-8
View File
@@ -23,9 +23,6 @@ importers:
leaflet-svg-shape-markers:
specifier: ^1.4.0
version: 1.4.0
magvar:
specifier: ^2.0.0
version: 2.0.0
navigraph:
specifier: ^1.4.1
version: 1.4.1
@@ -1102,9 +1099,6 @@ packages:
magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
magvar@2.0.0:
resolution: {integrity: sha512-00LpSwEJZcnyX3VsdCM2CHSCvB+M6sVQTawLCB3J9oK7eEueNltNx9GFL4YR+/HIkLM+l8rFKiY77JTKnOf0jw==}
merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@@ -2339,8 +2333,6 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.4
magvar@2.0.0: {}
merge2@1.4.1: {}
micromatch@4.0.8:
Binary file not shown.
@@ -1,15 +1,15 @@
import type { DeviceFlowParams } from 'navigraph/auth';
import { QRCodeSVG } from 'qrcode.react';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { ProcedureSelect } from './components//ProcedureSelect';
import { Loader } from './components/Loader';
import { Map } from './components/Map';
import { Sidebar } from './components/Sidebar';
import { useNavigraphAuth } from './contexts/NavigraphAuth/NavigraphAuthContext';
import Parser from './parser/parser';
const parser = await Parser.instance();
function App() {
const [parser, setParser] = useState<Parser>();
const [selectedAirport, setSelectedAirport] = useState<Airport>();
const [selectedRunway, setSelectedRunway] = useState<Runway>();
const [selectedTerminal, setSelectedTerminal] = useState<Terminal>();
@@ -17,26 +17,63 @@ function App() {
const [params, setParams] = useState<DeviceFlowParams | null>(null);
const [selectedTransition, setSelectedTransition] = useState<Procedure>();
const [selectedChart, setSelectedChart] = useState<Chart>();
const [skippedNG, setSkippedNG] = useState(false);
const { user, signIn, initialized } = useNavigraphAuth();
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 (
<>
{!user ? (
{!user && !skippedNG ? (
<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 && !user && (
<>
{params?.verification_uri_complete && (
<div className="flex h-dvh w-dvw flex-col items-center justify-center">
<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
</a>
</>
</div>
)}
</div>
) : (
@@ -49,6 +86,7 @@ function App() {
transitions={transitions}
transition={selectedTransition}
chart={selectedChart}
skippedNG={skippedNG}
setTransition={setSelectedTransition}
setChart={setSelectedChart}
backAction={() => {
@@ -60,17 +98,18 @@ function App() {
/>
) : (
<ProcedureSelect
parser={parser}
selectedAirport={selectedAirport}
selectedRunway={selectedRunway}
selectedTerminal={selectedTerminal}
setSelectedAirport={setSelectedAirport}
setSelectedRunway={setSelectedRunway}
setSelectedTerminal={setSelectedTerminal}
handleSelection={(selectedTransitions) => {
handleSelection={(selectedTransitions, _terminal) => {
let _transitions = selectedTransitions
.map((transition) => ({
name: transition,
data: parser.parse(selectedRunway!, transition),
data: parser.parse(selectedRunway!, _terminal, transition),
}))
.filter(
(transition) =>
@@ -91,6 +91,11 @@ export const Map: FC<MapProps> = ({ airport, chart, procedures }) => {
shape: 'triangle',
radius: 6,
});
else if (properties.isInitial)
return L.shapeMarker(latlng, {
shape: 'arrowhead',
radius: 6,
});
return L.shapeMarker(latlng, {
shape: 'star-4',
@@ -2,19 +2,19 @@ import { createRef, useMemo, useState, type Dispatch, type FC, type SetStateActi
import Parser from '../parser/parser';
import { Loader } from './Loader';
const parser = await Parser.instance();
interface ProcedureSelectProps {
parser: Parser;
selectedAirport: Airport | undefined;
selectedRunway: Runway | undefined;
selectedTerminal: Terminal | undefined;
setSelectedAirport: Dispatch<SetStateAction<Airport | undefined>>;
setSelectedRunway: Dispatch<SetStateAction<Runway | undefined>>;
setSelectedTerminal: Dispatch<SetStateAction<Terminal | undefined>>;
handleSelection: (transitions: string[]) => void;
handleSelection: (transitions: string[], terminal: Terminal) => void;
}
export const ProcedureSelect: FC<ProcedureSelectProps> = ({
parser,
selectedAirport,
selectedRunway,
selectedTerminal,
@@ -125,7 +125,7 @@ export const ProcedureSelect: FC<ProcedureSelectProps> = ({
parser.loadTerminal(terminal.ID).then(() => {
setSelectedTerminal(terminal);
const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
handleSelection(Array.from(transitions));
handleSelection(Array.from(transitions), terminal);
setInFlight(undefined);
});
}}
@@ -145,10 +145,12 @@ export const ProcedureSelect: FC<ProcedureSelectProps> = ({
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"
onClick={() => {
setInFlight(terminal.ID);
parser.loadTerminal(terminal.ID).then(() => {
setSelectedTerminal(terminal);
const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
handleSelection(Array.from(transitions));
handleSelection(Array.from(transitions), terminal);
setInFlight(undefined);
});
}}
disabled={!!inFlight}
@@ -167,10 +169,12 @@ export const ProcedureSelect: FC<ProcedureSelectProps> = ({
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"
onClick={() => {
setInFlight(terminal.ID);
parser.loadTerminal(terminal.ID).then(() => {
setSelectedTerminal(terminal);
const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
handleSelection(Array.from(transitions));
handleSelection(Array.from(transitions), terminal);
setInFlight(undefined);
});
}}
disabled={!!inFlight}
@@ -12,6 +12,7 @@ interface SidebarProps {
transitions: Procedure[];
transition: Procedure | undefined;
chart: Chart | undefined;
skippedNG?: boolean;
setTransition: Dispatch<SetStateAction<SidebarProps['transition']>>;
setChart: Dispatch<SetStateAction<SidebarProps['chart']>>;
backAction: () => void;
@@ -24,6 +25,7 @@ export const Sidebar: FC<SidebarProps> = ({
transitions,
transition,
chart,
skippedNG,
setTransition,
setChart,
backAction,
@@ -36,6 +38,8 @@ export const Sidebar: FC<SidebarProps> = ({
}>({ star: [], sid: [], iap: [] });
useEffect(() => {
if (skippedNG) return;
setInFlight(true);
(async () => {
const _chartIndex = await charts.getChartsIndex({ icao: airport.ICAO, version: 'STD' });
@@ -134,61 +138,63 @@ export const Sidebar: FC<SidebarProps> = ({
))}
</div>
<div className="flex flex-col gap-2">
<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} />}
{!skippedNG && (
<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>
{chartIndex.star
.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="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="sticky top-7 -mx-2 bg-gray-500 px-2 text-lg font-semibold text-white">Departures</div>
{chartIndex.sid
.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="sticky top-7 -mx-2 -mt-2 bg-gray-500 px-2 text-lg font-semibold text-white">Arrivals</div>
{chartIndex.star
.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="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 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>
{chartIndex.sid
.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="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>
);
@@ -11,7 +11,11 @@ import { TerminatorsFA } from './terminators/FA';
import { TerminatorsFC } from './terminators/FC';
import { TerminatorsFD } from './terminators/FD';
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 { TerminatorsPI } from './terminators/PI';
import { TerminatorsRF } from './terminators/RF';
import { TerminatorsTF } from './terminators/TF';
import { TerminatorsVA } from './terminators/VA';
@@ -21,12 +25,6 @@ import { TerminatorsVM } from './terminators/VM';
import { TerminatorsVR } from './terminators/VR';
import './utils/extensions';
/*
Runway IDs for LIED
26156 - 34L
26157 - 34R
*/
class Parser {
private static _instance: Parser;
@@ -37,11 +35,19 @@ class Parser {
private _procedures: TerminalEntry[] = [];
public static MAGVAR: Uint8Array;
public static AC_SPEED = 250;
public static AC_BANK = 30;
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._waypoints = waypoints;
this._runways = runways;
@@ -50,12 +56,13 @@ class Parser {
public static instance = async () => {
if (!Parser._instance) {
const magVar = await (await fetch('NavData/magdec.bgl')).bytes();
const airports = await (await fetch('NavData/Airports.json')).json();
const waypoints = await (await fetch('NavData/Waypoints.json')).json();
const runways = await (await fetch('NavData/Runways.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;
@@ -84,7 +91,7 @@ class Parser {
).json()) as TerminalEntry[];
};
public parse = (runway: Runway, transition: string) => {
public parse = (runway: Runway, terminal: Terminal, transition: string) => {
// Private functions
/**
* @param line Line segments
@@ -119,15 +126,19 @@ class Parser {
const navFixes: NavFix[] = [];
const lineSegments: { line: LineSegment[]; [x: string]: unknown }[] = [];
// Initials
navFixes.push({
latitude: runway.Latitude,
longitude: runway.Longitude,
altitude: runway.Elevation,
speed: 0,
name: runway.Ident,
});
let lastCourse = runway.TrueHeading;
let lastCourse = 0;
// RWY as origin for Departures
if (terminal.Proc === 2) {
navFixes.push({
latitude: runway.Latitude,
longitude: runway.Longitude,
altitude: runway.Elevation,
speed: 0,
name: runway.Ident,
});
lastCourse = runway.TrueHeading;
}
const legOptions = { isMAP: false };
const procedure = this._procedures.filter(
({ Transition }) => !Transition || Transition === transition || Transition === 'ALL'
@@ -135,10 +146,32 @@ class Parser {
// Main
for (let index = 0; index < procedure.length; index++) {
console.log('Processing leg with ID', procedure[index].ID);
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)!;
legOptions.isMAP ||= previousFix.IsMAP ?? false;
const waypoint = this.waypoints.find(({ ID }) => ID === leg.WptID);
switch (leg.TrackCode) {
case 'AF': {
@@ -208,11 +241,21 @@ class Parser {
navFixes.at(-1)!.isFlyOver = true;
break;
}
case 'HA':
case 'HF':
case 'HM':
console.error('Unknown TrackCode', leg.TrackCode);
case 'HA': {
const [fixToAdd, lineToAdd] = TerminatorsHA(leg as HATerminalEntry, previousFix);
update(fixToAdd, lineToAdd, { ...legOptions });
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': {
const fixToAdd = TerminatorsIF(leg as RFTerminalEntry, waypoint);
// Only Runway, replace
@@ -222,9 +265,16 @@ class Parser {
}
break;
}
case 'PI':
console.error('Unknown TrackCode', leg.TrackCode);
case 'PI': {
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;
}
case 'RF': {
const [fixToAdd, lineToAdd] = TerminatorsRF(leg as RFTerminalEntry, previousFix, lastCourse, waypoint);
if (fixToAdd) {
@@ -1,4 +1,5 @@
import computeDestinationPoint from 'geolib/es/computeDestinationPoint';
import getGreatCircleBearing from 'geolib/es/getGreatCircleBearing';
import getPreciseDistance from 'geolib/es/getPreciseDistance';
/**
@@ -6,7 +7,8 @@ import getPreciseDistance from 'geolib/es/getPreciseDistance';
* @param crsIntoOrigin Course into arc origin point
* @param start Arc origin point
* @param center Arc center point
* @param turnDir
* @param end Arc end point
* @param turnDir Turn Direction
* @returns Line segments
*/
export const generateRFArc = (
@@ -14,6 +16,7 @@ export const generateRFArc = (
crsIntoOrigin: number,
start: NavFix,
center: NavFix,
end: NavFix,
turnDir: TurnDirection
) => {
const line: LineSegment[] = [[start.longitude, start.latitude]];
@@ -26,20 +29,10 @@ export const generateRFArc = (
turnDir = prov > 0 ? 'L' : 'R';
}
let crsOrthogonalOnOrigin;
let crsOrthogonalOnEndpoint;
if (turnDir === 'R') {
crsOrthogonalOnOrigin = (crsIntoOrigin + 90).normaliseDegrees();
crsOrthogonalOnEndpoint = (crsIntoEndpoint + 90).normaliseDegrees();
} else {
crsOrthogonalOnOrigin = (crsIntoOrigin - 90).normaliseDegrees();
crsOrthogonalOnEndpoint = (crsIntoEndpoint - 90).normaliseDegrees();
}
let crsOrthogonalOnOrigin = getGreatCircleBearing(center, start);
const crsOrthogonalOnEndpoint = getGreatCircleBearing(center, end);
const arcRad = getPreciseDistance(center, start);
crsOrthogonalOnOrigin = crsOrthogonalOnOrigin.reciprocalCourse();
crsOrthogonalOnEndpoint = crsOrthogonalOnEndpoint.reciprocalCourse();
// Start turn immediately
if (turnDir === 'R') {
crsOrthogonalOnOrigin += crsOrthogonalOnOrigin < 1 ? crsOrthogonalOnOrigin : 1;
@@ -63,7 +63,7 @@ export const generateTangentArc = (
intcArcOnCrsIntoEndpoint,
crsOrthogonalOnEndpoint
);
if (Math.abs(crsOrthogonalOnEndpoint - crsOrthogonalOnOrigin) <= 0.1 && arcCenter)
if (!crsOrthogonalOnEndpoint.equal(crsOrthogonalOnOrigin) && arcCenter)
arcRad = getPreciseDistance(arcCenter, start);
else {
arcRad = getPreciseDistance(start, end) / 2;
@@ -3,6 +3,7 @@ import getGreatCircleBearing from 'geolib/es/getGreatCircleBearing';
import getPreciseDistance from 'geolib/es/getPreciseDistance';
import Parser from '../parser';
import { generateTangentArc } from '../pathGenerators/generateTangentArc';
import { computeIntersection } from '../utils/computeIntersection';
import { computeSpeed } from '../utils/computeSpeed';
import { computeTurnRate } from '../utils/computeTurnRate';
@@ -28,7 +29,6 @@ export const TerminatorsCF = (
IsFAF: leg.IsFAF,
IsMAP: leg.IsMAP,
};
const crsToIntercept = leg.Course.toTrue(targetFix);
// Compute overfly arc
let arc1: LineSegment[] | null = null;
@@ -59,7 +59,13 @@ export const TerminatorsCF = (
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);
let updatedCrsToIntercept = getGreatCircleBearing(previousFix, targetFix);
@@ -72,19 +78,26 @@ export const TerminatorsCF = (
// Generate arc
let lastDistance = getPreciseDistance(previousFix, targetFix);
while (!updatedCrsToIntercept.equal(crsToIntercept)) {
const reversal = Math.abs(lastCourse - crsIntoEndpoint) >= 90;
while (!updatedCrsToIntercept.equal(crsIntoEndpoint)) {
let interceptAngle = 0;
if (leg.TurnDir === 'R') interceptAngle = Math.abs(lastCourse - crsToIntercept);
else interceptAngle = Math.abs(crsToIntercept - lastCourse);
if (leg.TurnDir === 'R') interceptAngle = Math.abs(lastCourse - crsIntoEndpoint);
else interceptAngle = Math.abs(crsIntoEndpoint - lastCourse);
let time = 0;
const increment = 0.1;
if (interceptAngle < 44.9 || interceptAngle >= 45.1) {
if (leg.TurnDir === 'R') {
lastCourse = (lastCourse + increment).normaliseDegrees();
lastCourse =
reversal || updatedCrsToIntercept >= crsIntoEndpoint
? (lastCourse + increment).normaliseDegrees()
: lastCourse;
time = increment / turnRate;
} else {
lastCourse = (lastCourse - increment).normaliseDegrees();
lastCourse =
reversal || updatedCrsToIntercept <= crsIntoEndpoint
? (lastCourse - increment).normaliseDegrees()
: lastCourse;
time = increment / turnRate;
}
} else time = increment / turnRate;
@@ -80,7 +80,7 @@ export const TerminatorsFC = (
}
const targetFix: NavFix = {
...computeDestinationPoint(arcEnd, leg.Distance.toMetre(), lastCourse),
...computeDestinationPoint(arcEnd, leg.Distance.toMetre(), leg.Course.toTrue(refFix)),
name: leg.Distance.toString(),
isFlyOver: true,
altitude: leg.Alt ? leg.Alt.parseAltitude() : previousFix.altitude,
@@ -41,7 +41,7 @@ export const TerminatorsFD = (
// Compute intercept of crs from arc end and distance
const targetFix: NavFix = {
...computeDestinationPoint(arcEnd, remainingDistance, lastCourse),
...computeDestinationPoint(arcEnd, remainingDistance, crsIntoEndpoint),
name: leg.Distance.toString(),
isFlyOver: true,
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,
IsFAF: leg.IsFAF,
IsMAP: leg.IsMAP,
isInitial: true,
};
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,
previousFix,
{ latitude: leg.CenterLat, longitude: leg.CenterLon },
targetFix,
leg.TurnDir
);
@@ -32,7 +32,7 @@ export const TerminatorsTF = (
// Compute overfly arc
let arc1: LineSegment[] | null = null;
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);
} else {
arc1 = [[previousFix.longitude, previousFix.latitude]];
@@ -58,7 +58,7 @@ export const TerminatorsTF = (
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);
let updatedCrsToIntercept = getGreatCircleBearing(previousFix, targetFix);
@@ -80,10 +80,12 @@ export const TerminatorsTF = (
const increment = 0.1;
if (interceptAngle < 44.9 || interceptAngle >= 45.1) {
if (leg.TurnDir === 'R') {
lastCourse = (lastCourse + increment).normaliseDegrees();
lastCourse =
updatedCrsToIntercept >= crsIntoEndpoint ? (lastCourse + increment).normaliseDegrees() : lastCourse;
time = increment / turnRate;
} else {
lastCourse = (lastCourse - increment).normaliseDegrees();
lastCourse =
updatedCrsToIntercept >= crsIntoEndpoint ? (lastCourse - increment).normaliseDegrees() : lastCourse;
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';
/**
@@ -29,8 +30,12 @@ export const getCourseAndFixForIntercepts = (leg: TerminalEntry, origin: NavFix)
}
case 'AF': {
const _leg = leg as AFTerminalEntry;
const fix = { latitude: _leg.WptLat, longitude: _leg.WptLon };
return [_leg.Course.reciprocalCourse().toTrue(fix), fix];
const navAid = { latitude: _leg.NavLat, longitude: _leg.NavLon };
const fix = {
...computeDestinationPoint(navAid, _leg.NavDist.toMetre(), _leg.Course.toTrue(navAid)),
isIntersection: true,
};
return [_leg.Course.toTrue(fix), fix];
}
case 'DF': {
const _leg = leg as DFTerminalEntry;
+1
View File
@@ -0,0 +1 @@
@import 'tailwindcss';
@@ -26,9 +26,9 @@ export declare global {
*/
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 {
@@ -91,6 +91,7 @@ export declare global {
IsMAP?: boolean;
// For map
isIntersection?: boolean;
isInitial?: boolean;
};
type LineSegment = [number, number];

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