@squawk/flightplan 0.9.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -117,17 +117,17 @@ the configured lookup providers.
117
117
 
118
118
  Each element has a `type` discriminant and a `raw` field with the original token.
119
119
 
120
- | Type | Description | Key fields |
121
- | --------------- | ----------------------------------------- | ---------------------------------------------------------------- |
122
- | `airport` | Resolved airport (ICAO or FAA ID) | `airport` |
123
- | `sid` | Standard Instrument Departure | `procedure`, `legs`, `transition` |
124
- | `star` | Standard Terminal Arrival Route | `procedure`, `legs`, `transition` |
125
- | `airway` | Airway segment between entry and exit fix | `airway`, `entryFix`, `exitFix`, `waypoints`, `gaps`, `unusable` |
126
- | `direct` | DCT (direct) indicator | - |
127
- | `waypoint` | Resolved fix or navaid | `fix` and/or `navaid`, `lat`, `lon` |
128
- | `coordinate` | Lat/lon specified in the route string | `lat`, `lon` |
129
- | `speedAltitude` | Speed/altitude group (e.g. N0450F350) | `speedKt`/`speedKmPerHr`/`mach`, `flightLevel`/`altitudeFt` |
130
- | `unresolved` | Token that could not be resolved | - |
120
+ | Type | Description | Key fields |
121
+ | --------------- | ----------------------------------------- | ---------------------------------------------------------------------------- |
122
+ | `airport` | Resolved airport (ICAO or FAA ID) | `airport` |
123
+ | `sid` | Standard Instrument Departure | `procedure`, `legs`, `transition` |
124
+ | `star` | Standard Terminal Arrival Route | `procedure`, `legs`, `transition` |
125
+ | `airway` | Airway segment between entry and exit fix | `airway`, `entryFix`, `exitFix`, `waypoints`, `gaps`, `unusable`, `reversed` |
126
+ | `direct` | DCT (direct) indicator | - |
127
+ | `waypoint` | Resolved fix or navaid | `fix` and/or `navaid`, `lat`, `lon` |
128
+ | `coordinate` | Lat/lon specified in the route string | `lat`, `lon` |
129
+ | `speedAltitude` | Speed/altitude group (e.g. N0450F350) | `speedKt`/`speedKmPerHr`/`mach`, `flightLevel`/`altitudeFt` |
130
+ | `unresolved` | Token that could not be resolved | - |
131
131
 
132
132
  An airway element's `gaps` lists any published discontinuity its expansion
133
133
  crosses (the FAA discontinues some airways partway, such as J60 between JOT and
@@ -136,7 +136,11 @@ and measured, but a non-empty `gaps` means the route files the airway where it
136
136
  is not defined and is not valid as filed. Its `unusable` lists, in the same
137
137
  shape, any segment the FAA marks unusable (J34 between DRYER and GAABE, for
138
138
  example): the segment is still published with its distance but may not be
139
- flown, so a route across it is not valid as filed either.
139
+ flown, so a route across it is not valid as filed either. Its `reversed` is
140
+ true when the route flies the airway against its published waypoint order. Each
141
+ waypoint's segment fields (`distanceToNextNm`, the MEAs, the course) describe
142
+ the segment to the next waypoint in published order, so in a reversed element
143
+ they describe the segment between the waypoint and the one before it.
140
144
 
141
145
  ### Coordinate formats
142
146
 
@@ -158,6 +162,25 @@ between those fixes. The exit fix token is consumed as part of the airway
158
162
  element. If expansion fails, the airway token is marked `unresolved` and the
159
163
  exit fix token is parsed on its own.
160
164
 
165
+ An airway lookup supplied in place of `@squawk/airways` may leave out
166
+ `reversed`. The route is still expanded, and the legs of that airway are
167
+ measured as great circles instead of with the published segment distances.
168
+
169
+ ### What the resolver does not check
170
+
171
+ Parsing, distance and timing describe the route as filed. Nothing in this
172
+ package validates altitudes or applies constraints:
173
+
174
+ - Airway altitudes (MEA, MAA, MOCA, the GNSS and DME/DME/IRU MEAs, minimum
175
+ crossing altitudes, and their directions) are carried on the airway waypoints
176
+ as published. A cruise altitude in a speed/altitude group is not compared
177
+ with them, and no altitude is chosen for the direction of flight.
178
+ - Procedure legs keep their altitude and speed constraints, path terminators,
179
+ holds and arc data as published. Distance and geometry use only the legs that
180
+ end at a fix, joined by straight lines.
181
+ - Airway changeover points, signal gaps and the US-airspace-only flag are
182
+ returned as published and do not affect the route.
183
+
161
184
  ### Procedure handling
162
185
 
163
186
  A token that names a SID or STAR is expanded through the procedure provider.
@@ -199,7 +222,8 @@ Computes the total great-circle route distance and optional estimated time
199
222
  enroute from a parsed route. Walks the same ordered point sequence as the
200
223
  geometry helpers below, so distance and geometry stay in agreement. Airway
201
224
  segments use the FAA-published per-segment distance where the data carries a
202
- positive one, falling back to great-circle computation otherwise.
225
+ positive one, in either direction of travel, falling back to great-circle
226
+ computation otherwise.
203
227
 
204
228
  ```typescript
205
229
  import { computeRouteDistance } from '@squawk/flightplan';
@@ -50,13 +50,18 @@ export interface FlightplanAirwayLookup {
50
50
  * Expands an airway between entry and exit fixes, returning ordered
51
51
  * waypoints. `gaps` lists any published discontinuity the expansion crosses
52
52
  * and `unusable` any segment the FAA marks unusable; a lookup that cannot
53
- * report either may omit it, and the route then reports none.
53
+ * report either may omit it, and the route then reports none. `reversed`
54
+ * says whether the waypoints run against the airway's published order; a
55
+ * lookup that cannot report it may omit it, and the route then measures
56
+ * that airway's legs as great-circle distances instead of reading the
57
+ * published segment distances.
54
58
  */
55
59
  expand(designation: string, entryFix: string, exitFix: string): {
56
60
  airway: Airway;
57
61
  waypoints: AirwayWaypoint[];
58
62
  gaps?: AirwayGap[];
59
63
  unusable?: AirwaySegmentReference[];
64
+ reversed?: boolean;
60
65
  } | undefined;
61
66
  }
62
67
  /**
@@ -144,6 +149,14 @@ export interface AirwayRouteElement {
144
149
  * an unusable segment is not valid as filed.
145
150
  */
146
151
  unusable: AirwaySegmentReference[];
152
+ /**
153
+ * Whether the airway is flown against its published waypoint order. Each
154
+ * waypoint's segment fields (`distanceToNextNm`, the MEAs, the course)
155
+ * describe the segment to the next waypoint in published order, so in a
156
+ * reversed element they describe the segment between the waypoint and the
157
+ * one before it. Absent when the airway lookup does not report it.
158
+ */
159
+ reversed?: boolean;
147
160
  }
148
161
  /**
149
162
  * A DCT (direct) indicator between two waypoints.
@@ -1 +1 @@
1
- {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"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"}
package/dist/resolver.js CHANGED
@@ -292,7 +292,7 @@ export function createFlightplanResolver(options) {
292
292
  const exitFix = tokens[i + 1].toUpperCase();
293
293
  const expansion = airways.expand(token, lastWaypointIdent, exitFix);
294
294
  if (expansion) {
295
- elements.push({
295
+ const airwayElement = {
296
296
  type: 'airway',
297
297
  raw: token,
298
298
  airway: expansion.airway,
@@ -301,7 +301,11 @@ export function createFlightplanResolver(options) {
301
301
  waypoints: expansion.waypoints,
302
302
  gaps: expansion.gaps ?? [],
303
303
  unusable: expansion.unusable ?? [],
304
- });
304
+ };
305
+ if (expansion.reversed !== undefined) {
306
+ airwayElement.reversed = expansion.reversed;
307
+ }
308
+ elements.push(airwayElement);
305
309
  // The exit fix is consumed as part of the airway; update last waypoint
306
310
  lastWaypointIdent = exitFix;
307
311
  const exitWaypoint = expansion.waypoints[expansion.waypoints.length - 1];
@@ -68,9 +68,9 @@ export interface RouteDistanceResult {
68
68
  * indicate which parts of the route could not contribute to the distance
69
69
  * calculation.
70
70
  *
71
- * Airway segments use the FAA-published `distanceToNextNm` value where the
72
- * source publishes a positive one, falling back to great-circle computation
73
- * otherwise. A leg that spans a published gap in its airway is still measured
71
+ * Airway segments use the FAA-published segment distance where the source
72
+ * publishes a positive one and the airway element says which direction it is
73
+ * flown in, falling back to great-circle computation otherwise. A leg that spans a published gap in its airway is still measured
74
74
  * as a straight line and counted, but is flagged with `crossesGap`, and a leg
75
75
  * on an airway segment the FAA marks unusable is flagged with `unusable`, so
76
76
  * the caller can see that the route is not valid as filed.
@@ -20,9 +20,9 @@ import { extractGeoPoints } from './route-geometry.js';
20
20
  * indicate which parts of the route could not contribute to the distance
21
21
  * calculation.
22
22
  *
23
- * Airway segments use the FAA-published `distanceToNextNm` value where the
24
- * source publishes a positive one, falling back to great-circle computation
25
- * otherwise. A leg that spans a published gap in its airway is still measured
23
+ * Airway segments use the FAA-published segment distance where the source
24
+ * publishes a positive one and the airway element says which direction it is
25
+ * flown in, falling back to great-circle computation otherwise. A leg that spans a published gap in its airway is still measured
26
26
  * as a straight line and counted, but is flagged with `crossesGap`, and a leg
27
27
  * on an airway segment the FAA marks unusable is flagged with `unusable`, so
28
28
  * the caller can see that the route is not valid as filed.
@@ -1 +1 @@
1
- {"version":3,"file":"route-geometry.d.ts","sourceRoot":"","sources":["../src/route-geometry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAM/D;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;CACb;AAMD;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC;;;OAGG;IACH,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB;;;OAGG;IACH,cAAc,CAAC,EAAE,IAAI,CAAC;CACvB;AAuBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG;IAC1D,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,kBAAkB,EAAE,YAAY,EAAE,CAAC;CACpC,CA+FA;AAMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,EAAE,CAGnE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,SAAS,CAS5E"}
1
+ {"version":3,"file":"route-geometry.d.ts","sourceRoot":"","sources":["../src/route-geometry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAM/D;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;CACb;AAMD;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC;;;OAGG;IACH,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB;;;OAGG;IACH,cAAc,CAAC,EAAE,IAAI,CAAC;CACvB;AAuBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG;IAC1D,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,kBAAkB,EAAE,YAAY,EAAE,CAAC;CACpC,CA0GA;AAMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,EAAE,CAGnE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,SAAS,CAS5E"}
@@ -87,11 +87,22 @@ export function extractGeoPoints(elements) {
87
87
  lat: wp.lat,
88
88
  lon: wp.lon,
89
89
  };
90
- // Only carry a published distance for non-last waypoints (the last
91
- // waypoint's distanceToNextNm points beyond this segment), and only
92
- // a positive one: a zero means the source published no distance.
93
- if (!isLast && wp.distanceToNextNm !== undefined && wp.distanceToNextNm > 0) {
94
- point.precomputedDistanceToNextNm = wp.distanceToNextNm;
90
+ // The published distance of the leg to the next waypoint sits on
91
+ // whichever of the two starts the segment in the airway's published
92
+ // order: this waypoint when the airway is flown forward, the next one
93
+ // when it is flown in reverse. When the direction is unknown the leg
94
+ // is measured as a great circle. Only a positive distance is used: a
95
+ // zero means the source published none.
96
+ const segmentStart = isLast
97
+ ? undefined
98
+ : el.reversed === false
99
+ ? wp
100
+ : el.reversed === true
101
+ ? el.waypoints[i + 1]
102
+ : undefined;
103
+ const published = segmentStart?.distanceToNextNm;
104
+ if (published !== undefined && published > 0) {
105
+ point.precomputedDistanceToNextNm = published;
95
106
  }
96
107
  if (!isLast && gapIndexes.has(i)) {
97
108
  point.gapToNext = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squawk/flightplan",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "description": "Flight plan route string parsing and resolution using composed navigation resolvers",
6
6
  "author": "Neil Cochran",
@@ -43,22 +43,22 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "@squawk/flight-math": "^0.5.9",
46
- "@squawk/geo": "^0.5.5",
47
- "@squawk/types": "^0.15.0",
46
+ "@squawk/geo": "^0.5.6",
47
+ "@squawk/types": "^0.16.1",
48
48
  "@types/geojson": "^7946.0.16"
49
49
  },
50
50
  "devDependencies": {
51
- "@squawk/airport-data": "^0.9.0",
52
- "@squawk/airports": "^0.7.8",
53
- "@squawk/airway-data": "^0.7.1",
54
- "@squawk/airways": "^0.7.1",
55
- "@squawk/fix-data": "^0.7.7",
56
- "@squawk/fixes": "^0.5.8",
57
- "@squawk/navaid-data": "^0.7.7",
58
- "@squawk/navaids": "^0.6.8",
59
- "@squawk/procedure-data": "^0.9.3",
60
- "@squawk/procedures": "^0.8.3",
61
- "@types/node": "^26.6.4"
51
+ "@squawk/airport-data": "^0.9.1",
52
+ "@squawk/airports": "^0.8.0",
53
+ "@squawk/airway-data": "^0.7.2",
54
+ "@squawk/airways": "^0.8.0",
55
+ "@squawk/fix-data": "^0.8.0",
56
+ "@squawk/fixes": "^0.5.9",
57
+ "@squawk/navaid-data": "^0.8.1",
58
+ "@squawk/navaids": "^0.7.0",
59
+ "@squawk/procedure-data": "^0.9.4",
60
+ "@squawk/procedures": "^0.8.5",
61
+ "@types/node": "^26.6.5"
62
62
  },
63
63
  "keywords": [
64
64
  "aviation",