48 lines
No EOL
2 KiB
TypeScript
48 lines
No EOL
2 KiB
TypeScript
const a = 6378137.0;
|
||
const b = 6356752.314245;
|
||
const f = (a-b) / a;
|
||
|
||
export function degToRad(deg: number): number {
|
||
return deg * (Math.PI / 180);
|
||
}
|
||
export function radToDeg(radian: number): number {
|
||
return radian * (180 / Math.PI);
|
||
}
|
||
|
||
|
||
export function forwardGeodesic(α1: number, φ1: number, λ1: number, s: number): [number, number, number] {
|
||
const sinα1 = Math.sin(α1);
|
||
const cosα1 = Math.cos(α1);
|
||
|
||
const tanU1 = (1-f) * Math.tan(φ1), cosU1 = 1 / Math.sqrt((1 + tanU1*tanU1)), sinU1 = tanU1 * cosU1;
|
||
const σ1 = Math.atan2(tanU1, cosα1); // σ1 = angular distance on the sphere from the equator to P1
|
||
const sinα = cosU1 * sinα1; // α = azimuth of the geodesic at the equator
|
||
const cosSqα = 1 - sinα*sinα;
|
||
const uSq = cosSqα * (a*a - b*b) / (b*b);
|
||
const A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
|
||
const B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
|
||
|
||
let σ = s / (b*A), sinσ = null, cosσ = null; // σ = angular distance P₁ P₂ on the sphere
|
||
let cos2σₘ = null; // σₘ = angular distance on the sphere from the equator to the midpoint of the line
|
||
|
||
let σʹ = null;
|
||
do {
|
||
cos2σₘ = Math.cos(2*σ1 + σ);
|
||
sinσ = Math.sin(σ);
|
||
cosσ = Math.cos(σ);
|
||
const Δσ = B*sinσ*(cos2σₘ+B/4*(cosσ*(-1+2*cos2σₘ*cos2σₘ)-B/6*cos2σₘ*(-3+4*sinσ*sinσ)*(-3+4*cos2σₘ*cos2σₘ)));
|
||
σʹ = σ;
|
||
σ = s / (b*A) + Δσ;
|
||
} while (Math.abs(σ-σʹ) > 1e-12);
|
||
|
||
const x = sinU1*sinσ - cosU1*cosσ*cosα1;
|
||
const φ2 = Math.atan2(sinU1*cosσ + cosU1*sinσ*cosα1, (1-f)*Math.sqrt(sinα*sinα + x*x));
|
||
const λ = Math.atan2(sinσ*sinα1, cosU1*cosσ - sinU1*sinσ*cosα1);
|
||
const C = f/16*cosSqα*(4+f*(4-3*cosSqα));
|
||
const L = λ - (1-C) * f * sinα * (σ + C*sinσ*(cos2σₘ+C*cosσ*(-1+2*cos2σₘ*cos2σₘ)));
|
||
const λ2 = λ1 + L;
|
||
|
||
const α2 = Math.atan2(sinα, -x); // final bearing
|
||
|
||
return [φ2, λ2, α2];
|
||
} |