ootk-core
Version:
Orbital Object Toolkit. A modern typed replacement for satellite.js including SGP4 propagation, TLE parsing, Sun and Moon calculations, and more.
148 lines (135 loc) • 5.76 kB
text/typescript
/**
* @author Theodore Kruczek.
* @license MIT
* @copyright (c) 2022-2025 Theodore Kruczek Permission is
* hereby granted, free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* eslint-disable class-methods-use-this */
import { Kilometers, KilometersPerSecond, Radians, Vector3D } from '../main.js';
import { Earth } from '../body/Earth.js';
import { Geodetic } from './Geodetic.js';
import { J2000 } from './J2000.js';
import { StateVector } from './StateVector.js';
/**
* The International Terrestrial Reference Frame (ITRF) is a geocentric reference frame for the Earth. It is the
* successor to the International Terrestrial Reference System (ITRS). The ITRF definition is maintained by the
* International Earth Rotation and Reference Systems Service (IERS). Several versions of ITRF exist, each with a
* different epoch, to address the issue of crustal motion. The latest version is ITRF2014, based on data collected from
* 1980 to 2014.
* @see https://en.wikipedia.org/wiki/International_Terrestrial_Reference_Frame
*
* This is a geocentric coordinate system, also referenced as ECF/ECEF (Earth Centered Earth Fixed). It is a Cartesian
* coordinate system with the origin at the center of the Earth. The x-axis intersects the sphere of the Earth at 0°
* latitude (the equator) and 0° longitude (the Prime Meridian). The z-axis goes through the North Pole. The y-axis goes
* through 90° East longitude.
* @see https://en.wikipedia.org/wiki/Earth-centered,_Earth-fixed_coordinate_system
*/
export class ITRF extends StateVector {
/**
* Gets the name of the ITRF coordinate system.
* @returns The name of the coordinate system.
*/
get name(): string {
return 'ITRF';
}
/**
* Gets a value indicating whether the coordinate system is inertial.
* @returns A boolean value indicating whether the coordinate system is inertial.
*/
get inertial(): boolean {
return false;
}
/**
* Gets the height of the ITRF coordinate above the surface of the Earth in kilometers.
* @returns The height in kilometers.
*/
get height(): Kilometers {
const a = Earth.radiusEquator;
const e2 = Earth.eccentricitySquared;
const r = this.position.magnitude();
const sl = this.position.z / r;
const cl2 = 1 - sl * sl;
const coeff = Math.sqrt((1 - e2) / (1 - e2 * cl2));
return (r - a * coeff) as Kilometers;
}
/**
* Gets the altitude in kilometers.
* @returns The altitude in kilometers.
*/
get alt(): Kilometers {
return this.height;
}
/**
* Converts the current coordinate to the J2000 coordinate system. This is an Earth-Centered Inertial (ECI) coordinate
* system with the origin at the center of the Earth.
* @see https://en.wikipedia.org/wiki/Epoch_(astronomy)#Julian_years_and_J2000
* @returns The coordinate in the J2000 coordinate system.
*/
toJ2000(): J2000 {
const p = Earth.precession(this.epoch);
const n = Earth.nutation(this.epoch);
const ast = this.epoch.gmstAngle() + n.eqEq;
const rTOD = this.position.rotZ(-ast as Radians);
const vTOD = this.velocity
// TODO: #13 Intermediate unit type is incorrect.
.add(Earth.rotation.cross(this.position) as unknown as Vector3D<KilometersPerSecond>)
.rotZ(-ast as Radians);
const rMOD = rTOD.rotX(n.eps).rotZ(n.dPsi).rotX(-n.mEps);
const vMOD = vTOD.rotX(n.eps).rotZ(n.dPsi).rotX(-n.mEps);
const rJ2000 = rMOD
.rotZ(p.zed)
.rotY(-p.theta as Radians)
.rotZ(p.zeta) as Vector3D<Kilometers>;
const vJ2000 = vMOD
.rotZ(p.zed)
.rotY(-p.theta as Radians)
.rotZ(p.zeta) as Vector3D<KilometersPerSecond>;
return new J2000(this.epoch, rJ2000, vJ2000);
}
/**
* Converts the current ITRF coordinate to Geodetic coordinate. This is a coordinate system for latitude, longitude,
* and altitude.
* @returns The converted Geodetic coordinate.
*/
toGeodetic(): Geodetic {
const sma = Earth.radiusEquator;
const esq = Earth.eccentricitySquared;
const x = this.position.x;
const y = this.position.y;
const z = this.position.z;
const lon = Math.atan2(y, x);
const r = Math.sqrt(x * x + y * y);
const phi = Math.atan(z / r);
let lat = phi;
let alt: Kilometers;
let c = 0.0;
if (x === 0 && y === 0) {
lat = phi;
alt = z > 0 ? ((z - Earth.radiusPolar) as Kilometers) : ((z + Earth.radiusPolar) as Kilometers);
} else {
for (let i = 0; i < 20; i++) {
const slat = Math.sin(lat);
c = 1 / Math.sqrt(1 - esq * slat * slat);
lat = Math.atan((z + sma * c * esq * slat) / r);
}
alt = (r / Math.cos(lat) - sma * c) as Kilometers;
}
return new Geodetic(lat as Radians, lon as Radians, alt);
}
}