New:Socket for Asana Is Now Available.Learn more
Sign In

@squawk/flightplan

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@squawk/flightplan - npm Package Compare versions

Comparing version
0.2.2
to
0.3.0
+68
dist/route-distance.d.ts
/**
* Route distance and estimated time enroute computation for parsed flight
* plan routes. Extracts the ordered geographic point sequence from a
* {@link ParsedRoute} and sums great-circle leg distances.
*/
import type { ParsedRoute, RouteElement } from './resolver.js';
/**
* A single leg between two consecutive geographic points in a parsed route.
*/
export interface RouteLeg {
/** Identifier or raw token of the starting point. */
from: string;
/** Identifier or raw token of the ending point. */
to: string;
/** Great-circle distance of this leg in nautical miles. */
distanceNm: number;
/** Cumulative distance from the route start through the end of this leg in nautical miles. */
cumulativeDistanceNm: number;
}
/**
* Result of computing route distance and estimated time enroute from a
* parsed flight plan route.
*/
export interface RouteDistanceResult {
/** Ordered legs between consecutive geographic points. */
legs: RouteLeg[];
/** Total great-circle route distance in nautical miles. */
totalDistanceNm: number;
/** Estimated time enroute in hours, or `undefined` if no ground speed was provided. */
estimatedTimeEnrouteHrs: number | undefined;
/**
* Route elements of type `unresolved` that could not contribute coordinates.
* When these appear between geographic points the distance bridges the gap,
* so the total may be approximate.
*/
unresolvedElements: RouteElement[];
}
/**
* Computes the total great-circle route distance and optional estimated time
* enroute for a parsed flight plan route.
*
* Extracts the ordered sequence of geographic points from the route elements,
* sums leg distances, and divides by the given ground speed for ETE.
*
* Elements without coordinates (DCT, speed/altitude groups) are silently
* skipped. Unresolved tokens are collected in `unresolvedElements` to
* indicate which parts of the route could not contribute to the distance
* calculation.
*
* Airway segments use the FAA-published `distanceToNextNm` values when
* available, falling back to great-circle computation otherwise.
*
* ```typescript
* import { createFlightplanResolver, computeRouteDistance } from '@squawk/flightplan';
*
* const resolver = createFlightplanResolver({ airports, navaids, fixes, airways });
* const route = resolver.parse('KJFK DCT MERIT J60 MARTN DCT KLAX');
* const result = computeRouteDistance(route, 450);
* console.log(result.totalDistanceNm, result.estimatedTimeEnrouteHrs);
* ```
*
* @param route - A parsed route from {@link FlightplanResolver.parse}.
* @param groundSpeedKt - Ground speed in knots for ETE calculation. Omit to
* skip ETE computation.
* @returns Route distance breakdown with optional ETE.
*/
export declare function computeRouteDistance(route: ParsedRoute, groundSpeedKt?: number): RouteDistanceResult;
//# sourceMappingURL=route-distance.d.ts.map
{"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;AAM/D;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IACX,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,oBAAoB,EAAE,MAAM,CAAC;CAC9B;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;AA6HD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,WAAW,EAClB,aAAa,CAAC,EAAE,MAAM,GACrB,mBAAmB,CAkCrB"}
/**
* Route distance and estimated time enroute computation for parsed flight
* plan routes. Extracts the ordered geographic point sequence from a
* {@link ParsedRoute} and sums great-circle leg distances.
*/
import { distance } from '@squawk/units';
// ---------------------------------------------------------------------------
// Internal helpers
// ---------------------------------------------------------------------------
/** Epsilon for comparing coordinates to detect duplicate points. */
const COORD_EPSILON = 1e-9;
/**
* Returns true if two points share the same coordinates (within epsilon).
*/
function samePosition(a, b) {
return Math.abs(a.lat - b.lat) < COORD_EPSILON && Math.abs(a.lon - b.lon) < COORD_EPSILON;
}
/**
* Walks the route elements and extracts an ordered array of geographic
* points. Duplicate consecutive points (e.g. an airway entry fix that
* matches the preceding waypoint) are suppressed.
*
* Also collects all `unresolved` elements encountered during the walk.
*/
function extractGeoPoints(elements) {
const points = [];
const unresolvedElements = [];
function emit(point) {
if (points.length > 0 && samePosition(points[points.length - 1], point)) {
// When the duplicate carries a precomputed distance that the existing
// point lacks, adopt it. This happens when an airway's entry fix
// overlaps the preceding waypoint -- the airway waypoint has the
// published segment distance that would otherwise be lost.
const last = points[points.length - 1];
if (point.precomputedDistanceToNextNm !== undefined &&
last.precomputedDistanceToNextNm === undefined) {
last.precomputedDistanceToNextNm = point.precomputedDistanceToNextNm;
}
return;
}
points.push(point);
}
for (const el of elements) {
switch (el.type) {
case 'airport':
emit({ label: el.raw, lat: el.airport.lat, lon: el.airport.lon });
break;
case 'waypoint':
emit({ label: el.raw, lat: el.lat, lon: el.lon });
break;
case 'coordinate':
emit({ label: el.raw, lat: el.lat, lon: el.lon });
break;
case 'airway':
for (let i = 0; i < el.waypoints.length; i++) {
const wp = el.waypoints[i];
const isLast = i === el.waypoints.length - 1;
const point = {
label: wp.identifier ?? wp.name,
lat: wp.lat,
lon: wp.lon,
};
// Only carry precomputed distance for non-last waypoints (the
// last waypoint's distanceToNextNm points beyond this segment).
if (!isLast && wp.distanceToNextNm !== undefined) {
point.precomputedDistanceToNextNm = wp.distanceToNextNm;
}
emit(point);
}
break;
case 'sid':
case 'star':
for (const wp of el.waypoints) {
emit({ label: wp.fixIdentifier, lat: wp.lat, lon: wp.lon });
}
break;
case 'unresolved':
unresolvedElements.push(el);
break;
// 'direct' and 'speedAltitude' are expected non-geographic markers
// and are silently skipped.
case 'direct':
case 'speedAltitude':
break;
}
}
return { points, unresolvedElements };
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/**
* Computes the total great-circle route distance and optional estimated time
* enroute for a parsed flight plan route.
*
* Extracts the ordered sequence of geographic points from the route elements,
* sums leg distances, and divides by the given ground speed for ETE.
*
* Elements without coordinates (DCT, speed/altitude groups) are silently
* skipped. Unresolved tokens are collected in `unresolvedElements` to
* indicate which parts of the route could not contribute to the distance
* calculation.
*
* Airway segments use the FAA-published `distanceToNextNm` values when
* available, falling back to great-circle computation otherwise.
*
* ```typescript
* import { createFlightplanResolver, computeRouteDistance } from '@squawk/flightplan';
*
* const resolver = createFlightplanResolver({ airports, navaids, fixes, airways });
* const route = resolver.parse('KJFK DCT MERIT J60 MARTN DCT KLAX');
* const result = computeRouteDistance(route, 450);
* console.log(result.totalDistanceNm, result.estimatedTimeEnrouteHrs);
* ```
*
* @param route - A parsed route from {@link FlightplanResolver.parse}.
* @param groundSpeedKt - Ground speed in knots for ETE calculation. Omit to
* skip ETE computation.
* @returns Route distance breakdown with optional ETE.
*/
export function computeRouteDistance(route, groundSpeedKt) {
const { points, unresolvedElements } = extractGeoPoints(route.elements);
const legs = [];
let totalDistanceNm = 0;
for (let i = 0; i < points.length - 1; i++) {
const from = points[i];
const to = points[i + 1];
const legDistanceNm = from.precomputedDistanceToNextNm !== undefined
? from.precomputedDistanceToNextNm
: distance.greatCircleDistanceNm(from.lat, from.lon, to.lat, to.lon);
totalDistanceNm += legDistanceNm;
legs.push({
from: from.label,
to: to.label,
distanceNm: legDistanceNm,
cumulativeDistanceNm: totalDistanceNm,
});
}
const estimatedTimeEnrouteHrs = groundSpeedKt !== undefined && groundSpeedKt > 0 ? totalDistanceNm / groundSpeedKt : undefined;
return {
legs,
totalDistanceNm,
estimatedTimeEnrouteHrs,
unresolvedElements,
};
}
+2
-0

@@ -9,2 +9,4 @@ /**

export type { FlightplanResolver, FlightplanResolverOptions, FlightplanAirportLookup, FlightplanNavaidLookup, FlightplanFixLookup, FlightplanAirwayLookup, FlightplanProcedureLookup, ParsedRoute, RouteElement, AirportRouteElement, SidRouteElement, StarRouteElement, AirwayRouteElement, DirectRouteElement, WaypointRouteElement, CoordinateRouteElement, SpeedAltitudeRouteElement, UnresolvedRouteElement, } from './resolver.js';
export { computeRouteDistance } from './route-distance.js';
export type { RouteLeg, RouteDistanceResult } from './route-distance.js';
//# sourceMappingURL=index.d.ts.map
+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,YAAY,EACV,kBAAkB,EAClB,yBAAyB,EACzB,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,yBAAyB,EACzB,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,EACtB,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,eAAe,CAAC"}
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,YAAY,EACV,kBAAkB,EAClB,yBAAyB,EACzB,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,yBAAyB,EACzB,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,EACtB,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,YAAY,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}

@@ -8,1 +8,2 @@ /**

export { createFlightplanResolver } from './resolver.js';
export { computeRouteDistance } from './route-distance.js';
{
"name": "@squawk/flightplan",
"version": "0.2.2",
"version": "0.3.0",
"type": "module",

@@ -36,3 +36,4 @@ "description": "Flight plan route string parsing and resolution using composed navigation resolvers",

"dependencies": {
"@squawk/types": "*"
"@squawk/types": "*",
"@squawk/units": "*"
},

@@ -39,0 +40,0 @@ "devDependencies": {