95 lines
3.2 KiB
TypeScript
95 lines
3.2 KiB
TypeScript
import * as geolib from 'geolib';
|
|
import { computeIntersection } from '../utils/computeIntersection';
|
|
|
|
/**
|
|
* @param crsIntoEndpoint Course into arc endpoint
|
|
* @param crsFromOrigin Course from arc origin point
|
|
* @param start Arc origin point
|
|
* @param end Leg endpoint
|
|
* @param turnDir Turn direction
|
|
* @returns Line segments forming arc from `start`to `end`
|
|
*/
|
|
export const generateTangentArc = (
|
|
crsIntoEndpoint: number,
|
|
crsFromOrigin: number,
|
|
start: NavFix,
|
|
end: NavFix,
|
|
turnDir?: TurnDirection
|
|
) => {
|
|
const line: LineSegment[] = [[start.longitude, start.latitude]];
|
|
|
|
// Check if there even is an arc
|
|
if (!crsFromOrigin.equal(crsIntoEndpoint)) {
|
|
// Course to the end of the arc
|
|
let crsFromStartToEnd;
|
|
if (!turnDir || turnDir === 'E') {
|
|
let prov = crsFromOrigin - crsIntoEndpoint;
|
|
prov = prov > 180 ? prov - 360 : prov <= -180 ? prov + 360 : prov;
|
|
turnDir = prov > 0 ? 'L' : 'R';
|
|
}
|
|
if (turnDir === 'R') {
|
|
const delta = (360 - crsFromOrigin + crsIntoEndpoint).normaliseDegrees();
|
|
crsFromStartToEnd = (crsFromOrigin + delta / 2).normaliseDegrees();
|
|
} else {
|
|
const delta = (crsFromOrigin + 360 - crsIntoEndpoint).normaliseDegrees();
|
|
crsFromStartToEnd = (crsFromOrigin - delta / 2).normaliseDegrees();
|
|
}
|
|
|
|
// Arc end
|
|
const intcArcOnCrsIntoEndpoint = computeIntersection(
|
|
start,
|
|
crsFromStartToEnd,
|
|
end,
|
|
crsIntoEndpoint.reciprocalCourse()
|
|
);
|
|
if (!intcArcOnCrsIntoEndpoint) return null;
|
|
|
|
let crsOrthogonalOnOrigin;
|
|
let crsOrthogonalOnEndpoint;
|
|
if (turnDir === 'R') {
|
|
crsOrthogonalOnOrigin = (crsFromOrigin + 90).normaliseDegrees();
|
|
crsOrthogonalOnEndpoint = (crsIntoEndpoint + 90).normaliseDegrees();
|
|
} else {
|
|
crsOrthogonalOnOrigin = (crsFromOrigin - 90).normaliseDegrees();
|
|
crsOrthogonalOnEndpoint = (crsIntoEndpoint - 90).normaliseDegrees();
|
|
}
|
|
|
|
// Generate arc
|
|
const arcCenter = computeIntersection(
|
|
start,
|
|
crsOrthogonalOnOrigin,
|
|
intcArcOnCrsIntoEndpoint,
|
|
crsOrthogonalOnEndpoint
|
|
);
|
|
if (!arcCenter) return null;
|
|
const arcRad = geolib.getDistance(arcCenter, start);
|
|
|
|
crsOrthogonalOnOrigin = crsOrthogonalOnOrigin.reciprocalCourse();
|
|
crsOrthogonalOnEndpoint = crsOrthogonalOnEndpoint.reciprocalCourse();
|
|
// Start turn immediately
|
|
if (turnDir === 'R') {
|
|
crsOrthogonalOnOrigin += crsOrthogonalOnOrigin < 1 ? crsOrthogonalOnOrigin : 1;
|
|
} else {
|
|
crsOrthogonalOnOrigin -= crsOrthogonalOnOrigin < 1 ? crsOrthogonalOnOrigin : 1;
|
|
}
|
|
|
|
while (!crsOrthogonalOnOrigin.equal(crsOrthogonalOnEndpoint)) {
|
|
if (turnDir === 'R') {
|
|
const delta = (crsOrthogonalOnEndpoint - crsOrthogonalOnOrigin).normaliseDegrees();
|
|
crsOrthogonalOnOrigin += delta < 1 ? delta : 1;
|
|
crsOrthogonalOnOrigin = crsOrthogonalOnOrigin.normaliseDegrees();
|
|
} else {
|
|
const delta = (crsOrthogonalOnOrigin - crsOrthogonalOnEndpoint).normaliseDegrees();
|
|
crsOrthogonalOnOrigin -= delta < 1 ? delta : 1;
|
|
crsOrthogonalOnOrigin = crsOrthogonalOnOrigin.normaliseDegrees();
|
|
}
|
|
|
|
const arcFix = geolib.computeDestinationPoint(arcCenter, arcRad, crsOrthogonalOnOrigin);
|
|
|
|
line.push([arcFix.longitude, arcFix.latitude]);
|
|
}
|
|
}
|
|
|
|
return line;
|
|
};
|