@squawk/flightplan 0.11.0 → 0.12.1

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
@@ -33,7 +33,7 @@ const resolver = createFlightplanResolver({
33
33
  procedures: createProcedureResolver({ data: usBundledProcedures.records }),
34
34
  });
35
35
 
36
- const route = resolver.parse('KLAX DCT LAX J60 SAX DCT KJFK');
36
+ const route = resolver.parse('KSEA DCT SEA J70 GEP DCT KJFK');
37
37
  for (const element of route.elements) {
38
38
  console.log(element.type, element.raw);
39
39
  }
@@ -247,7 +247,7 @@ computation otherwise.
247
247
  ```typescript
248
248
  import { computeRouteDistance } from '@squawk/flightplan';
249
249
 
250
- const route = resolver.parse('KLAX DCT LAX J60 SAX DCT KJFK');
250
+ const route = resolver.parse('KSEA DCT SEA J70 GEP DCT KJFK');
251
251
  const result = computeRouteDistance(route, 450);
252
252
  console.log(result.totalDistanceNm, result.estimatedTimeEnrouteHrs);
253
253
  ```
@@ -259,7 +259,7 @@ console.log(result.totalDistanceNm, result.estimatedTimeEnrouteHrs);
259
259
 
260
260
  **Returns:** `RouteDistanceResult` with:
261
261
 
262
- - `legs` - ordered `RouteLeg` values, each with `from`/`to` point labels, their `fromLat`/`fromLon`/`toLat`/`toLon` coordinates in decimal degrees, `distanceNm`, `cumulativeDistanceNm`, `crossesGap`, which is true when the leg spans a published gap in the airway it came from (the leg is a straight line that counts toward the total but is not a flyable airway segment), and `unusable`, which is true when the leg is an airway segment the FAA marks unusable (counted toward the total but not to be flown)
262
+ - `legs` - ordered `RouteLeg` values, each with `from`/`to` point labels, their `fromLat`/`fromLon`/`toLat`/`toLon` coordinates in decimal degrees, `distanceNm`, `cumulativeDistanceNm`, `crossesGap`, which is true when the leg spans a published gap in the airway it came from (the leg is a straight line that counts toward the total but is not a flyable airway segment), `unusable`, which is true when the leg is an airway segment the FAA marks unusable (counted toward the total but not to be flown), and `procedureAirportMismatch`, which is true when the leg runs along a SID or STAR filed at an airport it does not serve (the element's `airportMismatch`), or joins the route to that airport: the leg in from the departure airport for a SID, the leg out to the arrival airport for a STAR
263
263
  - `totalDistanceNm` - total great-circle distance in nautical miles
264
264
  - `estimatedTimeEnrouteHrs` - ETE in hours, or `undefined` when no ground speed was given
265
265
  - `unresolvedElements` - route elements that could not contribute coordinates
@@ -284,7 +284,7 @@ wind correction angle is zero.
284
284
  ```typescript
285
285
  import { computeRouteTiming } from '@squawk/flightplan';
286
286
 
287
- const route = resolver.parse('KLAX DCT LAX J60 SAX DCT KJFK');
287
+ const route = resolver.parse('KSEA DCT SEA J70 GEP DCT KJFK');
288
288
  const result = computeRouteTiming(route, {
289
289
  trueAirspeedKt: 450,
290
290
  windProvider: (lat, lon) => ({ directionDeg: 270, speedKt: 80 }),
@@ -337,7 +337,7 @@ two drawable points, since a `LineString` requires at least two positions.
337
337
  ```typescript
338
338
  import { routeToLineString } from '@squawk/flightplan';
339
339
 
340
- const route = resolver.parse('KLAX DCT LAX J60 SAX DCT KJFK');
340
+ const route = resolver.parse('KSEA DCT SEA J70 GEP DCT KJFK');
341
341
  const line = routeToLineString(route);
342
342
  if (line) {
343
343
  map.addSource('route', { type: 'geojson', data: line });
@@ -318,7 +318,7 @@ export interface FlightplanResolver {
318
318
  * procedures: createProcedureResolver({ data: usBundledProcedures.records }),
319
319
  * });
320
320
  *
321
- * const route = resolver.parse('KLAX DCT LAX J60 SAX DCT KJFK');
321
+ * const route = resolver.parse('KSEA DCT SEA J70 GEP DCT KJFK');
322
322
  * for (const element of route.elements) {
323
323
  * console.log(element.type, element.raw);
324
324
  * }
package/dist/resolver.js CHANGED
@@ -315,7 +315,7 @@ function findNextAirport(tokens, start, airports, navaids, airways) {
315
315
  * procedures: createProcedureResolver({ data: usBundledProcedures.records }),
316
316
  * });
317
317
  *
318
- * const route = resolver.parse('KLAX DCT LAX J60 SAX DCT KJFK');
318
+ * const route = resolver.parse('KSEA DCT SEA J70 GEP DCT KJFK');
319
319
  * for (const element of route.elements) {
320
320
  * console.log(element.type, element.raw);
321
321
  * }
@@ -37,6 +37,15 @@ export interface RouteLeg {
37
37
  * not be flown, so the route is not valid as filed.
38
38
  */
39
39
  unusable: boolean;
40
+ /**
41
+ * Whether this leg runs along, or joins the route to, a SID or STAR the
42
+ * route files at an airport no adaptation of it serves (the procedure
43
+ * element's `airportMismatch`): the procedure's own legs, plus the leg in
44
+ * from the departure airport for a SID or out to the arrival airport for a
45
+ * STAR. The leg is measured like any other, but the route is not valid as
46
+ * filed.
47
+ */
48
+ procedureAirportMismatch: boolean;
40
49
  }
41
50
  /**
42
51
  * Result of computing route distance and estimated time enroute from a
@@ -71,15 +80,17 @@ export interface RouteDistanceResult {
71
80
  * Airway segments use the FAA-published segment distance where the source
72
81
  * publishes a positive one and the airway element says which direction it is
73
82
  * flown in, falling back to great-circle computation otherwise. A leg that spans a published gap in its airway is still measured
74
- * as a straight line and counted, but is flagged with `crossesGap`, and a leg
75
- * on an airway segment the FAA marks unusable is flagged with `unusable`, so
76
- * the caller can see that the route is not valid as filed.
83
+ * as a straight line and counted, but is flagged with `crossesGap`, a leg
84
+ * on an airway segment the FAA marks unusable is flagged with `unusable`, and
85
+ * a leg along or into a procedure filed at an airport it does not serve is
86
+ * flagged with `procedureAirportMismatch`, so the caller can see that the
87
+ * route is not valid as filed.
77
88
  *
78
89
  * ```typescript
79
90
  * import { createFlightplanResolver, computeRouteDistance } from '@squawk/flightplan';
80
91
  *
81
92
  * const resolver = createFlightplanResolver({ airports, navaids, fixes, airways });
82
- * const route = resolver.parse('KLAX DCT LAX J60 SAX DCT KJFK');
93
+ * const route = resolver.parse('KSEA DCT SEA J70 GEP DCT KJFK');
83
94
  * const result = computeRouteDistance(route, 450);
84
95
  * console.log(result.totalDistanceNm, result.estimatedTimeEnrouteHrs);
85
96
  * ```
@@ -1 +1 @@
1
- {"version":3,"file":"route-distance.d.ts","sourceRoot":"","sources":["../src/route-distance.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAO/D;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IACX,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,oBAAoB,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,0DAA0D;IAC1D,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,2DAA2D;IAC3D,eAAe,EAAE,MAAM,CAAC;IACxB,uFAAuF;IACvF,uBAAuB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C;;;;OAIG;IACH,kBAAkB,EAAE,YAAY,EAAE,CAAC;CACpC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,WAAW,EAClB,aAAa,CAAC,EAAE,MAAM,GACrB,mBAAmB,CAwCrB"}
1
+ {"version":3,"file":"route-distance.d.ts","sourceRoot":"","sources":["../src/route-distance.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAO/D;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IACX,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,oBAAoB,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;;;OAOG;IACH,wBAAwB,EAAE,OAAO,CAAC;CACnC;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,0DAA0D;IAC1D,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,2DAA2D;IAC3D,eAAe,EAAE,MAAM,CAAC;IACxB,uFAAuF;IACvF,uBAAuB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C;;;;OAIG;IACH,kBAAkB,EAAE,YAAY,EAAE,CAAC;CACpC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,WAAW,EAClB,aAAa,CAAC,EAAE,MAAM,GACrB,mBAAmB,CAyCrB"}
@@ -23,15 +23,17 @@ import { extractGeoPoints } from './route-geometry.js';
23
23
  * Airway segments use the FAA-published segment distance where the source
24
24
  * publishes a positive one and the airway element says which direction it is
25
25
  * flown in, falling back to great-circle computation otherwise. A leg that spans a published gap in its airway is still measured
26
- * as a straight line and counted, but is flagged with `crossesGap`, and a leg
27
- * on an airway segment the FAA marks unusable is flagged with `unusable`, so
28
- * the caller can see that the route is not valid as filed.
26
+ * as a straight line and counted, but is flagged with `crossesGap`, a leg
27
+ * on an airway segment the FAA marks unusable is flagged with `unusable`, and
28
+ * a leg along or into a procedure filed at an airport it does not serve is
29
+ * flagged with `procedureAirportMismatch`, so the caller can see that the
30
+ * route is not valid as filed.
29
31
  *
30
32
  * ```typescript
31
33
  * import { createFlightplanResolver, computeRouteDistance } from '@squawk/flightplan';
32
34
  *
33
35
  * const resolver = createFlightplanResolver({ airports, navaids, fixes, airways });
34
- * const route = resolver.parse('KLAX DCT LAX J60 SAX DCT KJFK');
36
+ * const route = resolver.parse('KSEA DCT SEA J70 GEP DCT KJFK');
35
37
  * const result = computeRouteDistance(route, 450);
36
38
  * console.log(result.totalDistanceNm, result.estimatedTimeEnrouteHrs);
37
39
  * ```
@@ -63,6 +65,7 @@ export function computeRouteDistance(route, groundSpeedKt) {
63
65
  cumulativeDistanceNm: totalDistanceNm,
64
66
  crossesGap: from.gapToNext === true,
65
67
  unusable: from.unusableToNext === true,
68
+ procedureAirportMismatch: from.procedureMismatchToNext === true,
66
69
  });
67
70
  }
68
71
  const estimatedTimeEnrouteHrs = groundSpeedKt !== undefined && groundSpeedKt > 0 ? totalDistanceNm / groundSpeedKt : undefined;
@@ -50,6 +50,11 @@ export interface GeoPoint {
50
50
  * marks unusable.
51
51
  */
52
52
  unusableToNext?: true;
53
+ /**
54
+ * Set when the leg from this point to the next runs along, or joins the
55
+ * route to, a SID or STAR filed at an airport no adaptation of it serves.
56
+ */
57
+ procedureMismatchToNext?: true;
53
58
  }
54
59
  /**
55
60
  * Walks the route elements and extracts an ordered array of geographic
@@ -84,7 +89,7 @@ export declare function extractGeoPoints(elements: RouteElement[]): {
84
89
  * import { createFlightplanResolver, extractRoutePoints } from '@squawk/flightplan';
85
90
  *
86
91
  * const resolver = createFlightplanResolver({ airports, navaids, fixes, airways });
87
- * const route = resolver.parse('KLAX DCT LAX J60 SAX DCT KJFK');
92
+ * const route = resolver.parse('KSEA DCT SEA J70 GEP DCT KJFK');
88
93
  * const points = extractRoutePoints(route);
89
94
  * ```
90
95
  *
@@ -104,7 +109,7 @@ export declare function extractRoutePoints(route: ParsedRoute): RoutePoint[];
104
109
  * import { createFlightplanResolver, routeToLineString } from '@squawk/flightplan';
105
110
  *
106
111
  * const resolver = createFlightplanResolver({ airports, navaids, fixes, airways });
107
- * const route = resolver.parse('KLAX DCT LAX J60 SAX DCT KJFK');
112
+ * const route = resolver.parse('KSEA DCT SEA J70 GEP DCT KJFK');
108
113
  * const line = routeToLineString(route);
109
114
  * if (line) {
110
115
  * map.addSource('route', { type: 'geojson', data: line });
@@ -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,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"}
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;IACtB;;;OAGG;IACH,uBAAuB,CAAC,EAAE,IAAI,CAAC;CAChC;AAuBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG;IAC1D,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,kBAAkB,EAAE,YAAY,EAAE,CAAC;CACpC,CA0HA;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"}
@@ -53,14 +53,17 @@ export function extractGeoPoints(elements) {
53
53
  last.precomputedDistanceToNextNm === undefined) {
54
54
  last.precomputedDistanceToNextNm = point.precomputedDistanceToNextNm;
55
55
  }
56
- // Likewise carry a gap or unusable marker, so the leg out of the merged
57
- // point is still reported as crossing the gap or as unusable.
56
+ // Likewise carry a gap, unusable or procedure-mismatch marker, so the
57
+ // leg out of the merged point is still reported.
58
58
  if (point.gapToNext) {
59
59
  last.gapToNext = true;
60
60
  }
61
61
  if (point.unusableToNext) {
62
62
  last.unusableToNext = true;
63
63
  }
64
+ if (point.procedureMismatchToNext) {
65
+ last.procedureMismatchToNext = true;
66
+ }
64
67
  return;
65
68
  }
66
69
  points.push(point);
@@ -115,14 +118,25 @@ export function extractGeoPoints(elements) {
115
118
  break;
116
119
  }
117
120
  case 'sid':
118
- case 'star':
119
- for (const leg of el.legs) {
120
- if (leg.fixIdentifier === undefined || leg.lat === undefined || leg.lon === undefined) {
121
- continue;
122
- }
123
- emit({ label: leg.fixIdentifier, lat: leg.lat, lon: leg.lon });
121
+ case 'star': {
122
+ // A procedure filed at an airport it does not serve flags its own legs
123
+ // and the leg joining it to that airport: the leg in from the
124
+ // departure for a SID, the leg out to the arrival for a STAR.
125
+ const mismatched = el.airportMismatch !== undefined;
126
+ if (mismatched && el.type === 'sid' && points.length > 0) {
127
+ points[points.length - 1].procedureMismatchToNext = true;
124
128
  }
129
+ const drawable = el.legs.flatMap((leg) => leg.fixIdentifier !== undefined && leg.lat !== undefined && leg.lon !== undefined
130
+ ? [{ label: leg.fixIdentifier, lat: leg.lat, lon: leg.lon }]
131
+ : []);
132
+ drawable.forEach((point, index) => {
133
+ if (mismatched && (el.type === 'star' || index < drawable.length - 1)) {
134
+ point.procedureMismatchToNext = true;
135
+ }
136
+ emit(point);
137
+ });
125
138
  break;
139
+ }
126
140
  case 'unresolved':
127
141
  unresolvedElements.push(el);
128
142
  break;
@@ -154,7 +168,7 @@ export function extractGeoPoints(elements) {
154
168
  * import { createFlightplanResolver, extractRoutePoints } from '@squawk/flightplan';
155
169
  *
156
170
  * const resolver = createFlightplanResolver({ airports, navaids, fixes, airways });
157
- * const route = resolver.parse('KLAX DCT LAX J60 SAX DCT KJFK');
171
+ * const route = resolver.parse('KSEA DCT SEA J70 GEP DCT KJFK');
158
172
  * const points = extractRoutePoints(route);
159
173
  * ```
160
174
  *
@@ -177,7 +191,7 @@ export function extractRoutePoints(route) {
177
191
  * import { createFlightplanResolver, routeToLineString } from '@squawk/flightplan';
178
192
  *
179
193
  * const resolver = createFlightplanResolver({ airports, navaids, fixes, airways });
180
- * const route = resolver.parse('KLAX DCT LAX J60 SAX DCT KJFK');
194
+ * const route = resolver.parse('KSEA DCT SEA J70 GEP DCT KJFK');
181
195
  * const line = routeToLineString(route);
182
196
  * if (line) {
183
197
  * map.addSource('route', { type: 'geojson', data: line });
@@ -72,6 +72,8 @@ export interface RouteTimingLeg {
72
72
  crossesGap: boolean;
73
73
  /** Whether this leg is an airway segment the FAA marks unusable, as on `RouteLeg`. */
74
74
  unusable: boolean;
75
+ /** Whether this leg runs along or into a procedure filed at an airport it does not serve, as on `RouteLeg`. */
76
+ procedureAirportMismatch: boolean;
75
77
  /** Initial great-circle true course for the leg in degrees (0-360). */
76
78
  trueCourseDeg: number;
77
79
  /** True heading to fly to hold the course given the wind, in degrees (0-360). */
@@ -156,7 +158,7 @@ export interface RouteTimingResult {
156
158
  * import { createFlightplanResolver, computeRouteTiming } from '@squawk/flightplan';
157
159
  *
158
160
  * const resolver = createFlightplanResolver({ airports, navaids, fixes, airways });
159
- * const route = resolver.parse('KLAX DCT LAX J60 SAX DCT KJFK');
161
+ * const route = resolver.parse('KSEA DCT SEA J70 GEP DCT KJFK');
160
162
  * const result = computeRouteTiming(route, {
161
163
  * trueAirspeedKt: 450,
162
164
  * windProvider: (lat, lon) => ({ directionDeg: 270, speedKt: 80 }),
@@ -1 +1 @@
1
- {"version":3,"file":"route-timing.d.ts","sourceRoot":"","sources":["../src/route-timing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtD,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAO/D;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAC;AAEhF;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,cAAc,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IACX,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mGAAmG;IACnG,UAAU,EAAE,OAAO,CAAC;IACpB,sFAAsF;IACtF,QAAQ,EAAE,OAAO,CAAC;IAClB,uEAAuE;IACvE,aAAa,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,cAAc,EAAE,MAAM,CAAC;IACvB,6FAA6F;IAC7F,sBAAsB,EAAE,MAAM,CAAC;IAC/B,mDAAmD;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,IAAI,EAAE,UAAU,GAAG,SAAS,CAAC;IAC7B,mGAAmG;IACnG,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B;;;OAGG;IACH,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC;;;OAGG;IACH,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB,2DAA2D;IAC3D,eAAe,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC;;;OAGG;IACH,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC;;;OAGG;IACH,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC;;;OAGG;IACH,cAAc,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC;;;OAGG;IACH,kBAAkB,EAAE,YAAY,EAAE,CAAC;CACpC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,kBAAkB,GAC1B,iBAAiB,CA0FnB"}
1
+ {"version":3,"file":"route-timing.d.ts","sourceRoot":"","sources":["../src/route-timing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtD,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAO/D;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAC;AAEhF;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,cAAc,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IACX,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mGAAmG;IACnG,UAAU,EAAE,OAAO,CAAC;IACpB,sFAAsF;IACtF,QAAQ,EAAE,OAAO,CAAC;IAClB,+GAA+G;IAC/G,wBAAwB,EAAE,OAAO,CAAC;IAClC,uEAAuE;IACvE,aAAa,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,cAAc,EAAE,MAAM,CAAC;IACvB,6FAA6F;IAC7F,sBAAsB,EAAE,MAAM,CAAC;IAC/B,mDAAmD;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,IAAI,EAAE,UAAU,GAAG,SAAS,CAAC;IAC7B,mGAAmG;IACnG,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B;;;OAGG;IACH,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC;;;OAGG;IACH,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB,2DAA2D;IAC3D,eAAe,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC;;;OAGG;IACH,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC;;;OAGG;IACH,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC;;;OAGG;IACH,cAAc,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC;;;OAGG;IACH,kBAAkB,EAAE,YAAY,EAAE,CAAC;CACpC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,kBAAkB,GAC1B,iBAAiB,CA2FnB"}
@@ -43,7 +43,7 @@ import { computeRouteDistance } from './route-distance.js';
43
43
  * import { createFlightplanResolver, computeRouteTiming } from '@squawk/flightplan';
44
44
  *
45
45
  * const resolver = createFlightplanResolver({ airports, navaids, fixes, airways });
46
- * const route = resolver.parse('KLAX DCT LAX J60 SAX DCT KJFK');
46
+ * const route = resolver.parse('KSEA DCT SEA J70 GEP DCT KJFK');
47
47
  * const result = computeRouteTiming(route, {
48
48
  * trueAirspeedKt: 450,
49
49
  * windProvider: (lat, lon) => ({ directionDeg: 270, speedKt: 80 }),
@@ -102,6 +102,7 @@ export function computeRouteTiming(route, options) {
102
102
  cumulativeDistanceNm: leg.cumulativeDistanceNm,
103
103
  crossesGap: leg.crossesGap,
104
104
  unusable: leg.unusable,
105
+ procedureAirportMismatch: leg.procedureAirportMismatch,
105
106
  trueCourseDeg,
106
107
  trueHeadingDeg: triangle.trueHeadingDeg,
107
108
  windCorrectionAngleDeg: triangle.windCorrectionAngleDeg,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squawk/flightplan",
3
- "version": "0.11.0",
3
+ "version": "0.12.1",
4
4
  "type": "module",
5
5
  "description": "Flight plan route string parsing and resolution using composed navigation resolvers",
6
6
  "author": "Neil Cochran",
@@ -43,19 +43,19 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "@squawk/flight-math": "^0.5.9",
46
- "@squawk/geo": "^0.5.7",
46
+ "@squawk/geo": "^0.6.0",
47
47
  "@squawk/types": "^0.17.0",
48
48
  "@types/geojson": "^7946.0.16"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@squawk/airport-data": "^0.9.2",
52
- "@squawk/airports": "^0.8.1",
52
+ "@squawk/airports": "^0.8.2",
53
53
  "@squawk/airway-data": "^0.7.3",
54
- "@squawk/airways": "^0.8.1",
54
+ "@squawk/airways": "^0.8.2",
55
55
  "@squawk/fix-data": "^0.8.1",
56
- "@squawk/fixes": "^0.5.10",
56
+ "@squawk/fixes": "^0.5.11",
57
57
  "@squawk/navaid-data": "^0.8.2",
58
- "@squawk/navaids": "^0.7.1",
58
+ "@squawk/navaids": "^0.7.2",
59
59
  "@squawk/procedure-data": "^0.9.5",
60
60
  "@squawk/procedures": "^0.8.6",
61
61
  "@types/node": "^26.6.5"