106 lines
3.4 KiB
TypeScript
106 lines
3.4 KiB
TypeScript
import * as geolib from "geolib";
|
|
import { computeIntersection } from "../utils/computeIntersection.ts";
|
|
|
|
/**
|
|
* @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 !== 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 !== 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();
|
|
}
|
|
if (crsOrthogonalOnOrigin === crsOrthogonalOnEndpoint) break;
|
|
|
|
const arcFix = geolib.computeDestinationPoint(
|
|
arcCenter,
|
|
arcRad,
|
|
crsOrthogonalOnOrigin
|
|
);
|
|
|
|
line.push([arcFix.longitude, arcFix.latitude]);
|
|
}
|
|
}
|
|
|
|
return line;
|
|
};
|