diff --git a/.eslintrc.json b/.eslintrc.json index c1a1dd8..badb2f6 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -5,14 +5,14 @@ "node": true, "jest": true }, - "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:jsdoc/recommended-typescript-error"], "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": 12, "sourceType": "module" }, - "plugins": ["@typescript-eslint"], - "rules": { + "plugins": ["@typescript-eslint", "jsdoc"], + "rules": { "accessor-pairs": "error", "array-bracket-newline": "error", "array-bracket-spacing": "error", @@ -163,7 +163,7 @@ "no-template-curly-in-string": "error", "no-ternary": "off", "no-throw-literal": "error", - "no-trailing-spaces": "error", + "no-trailing-spaces": ["error", { "ignoreComments": true }], "no-undef-init": "error", "no-undefined": "error", "no-underscore-dangle": "off", diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 5d4c011..0000000 --- a/.prettierrc +++ /dev/null @@ -1,17 +0,0 @@ -{ - "printWidth": 120, - "tabWidth": 2, - "useTabs": false, - "semi": true, - "singleQuote": true, - "quoteProps": "consistent", - "trailingComma": "all", - "bracketSpacing": true, - "arrowParens": "always", - "requirePragma": false, - "insertPragma": false, - "proseWrap": "always", - "htmlWhitespaceSensitivity": "ignore", - "endOfLine": "lf", - "embeddedLanguageFormatting": "off" -} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1331f3f..8596797 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,8 +20,8 @@ "babel-eslint": "^10.1.0", "babel-loader": "^9.1.3", "eslint": "^8.56.0", + "eslint-plugin-jsdoc": "^48.0.2", "jest": "^28.1.3", - "prettier": "^3.2.1", "tsx": "^4.7.0", "typescript": "^4.9.5" } @@ -1848,6 +1848,20 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", + "integrity": "sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==", + "dev": true, + "dependencies": { + "comment-parser": "1.4.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.19.11", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz", @@ -5059,6 +5073,15 @@ "node": ">= 8" } }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -5441,6 +5464,18 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -5588,6 +5623,15 @@ "dev": true, "peer": true }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/common-path-prefix": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", @@ -5897,6 +5941,56 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-plugin-jsdoc": { + "version": "48.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.0.2.tgz", + "integrity": "sha512-CBFl5Jc7+jlV36RwDm+PQ8Uw5r28pn2/uW/OaB+Gw5bFwn4Py/1eYMZ3hGf9S4meUFZ/sRvS+hVif2mRAp6WqQ==", + "dev": true, + "dependencies": { + "@es-joy/jsdoccomment": "~0.41.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.5.4", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -6828,6 +6922,21 @@ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-core-module": { "version": "2.12.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", @@ -10082,6 +10191,15 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -10649,21 +10767,6 @@ "node": ">= 0.8.0" } }, - "node_modules/prettier": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.1.tgz", - "integrity": "sha512-qSUWshj1IobVbKc226Gw2pync27t0Kf0EdufZa9j7uBSJay1CC+B3K5lAAZoqgX3ASiKuWsk6OmzKRetXNObWg==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -11076,6 +11179,28 @@ "source-map": "^0.6.0" } }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", diff --git a/package.json b/package.json index 6491ce2..641d0a9 100644 --- a/package.json +++ b/package.json @@ -45,10 +45,10 @@ "babel-eslint": "^10.1.0", "babel-loader": "^9.1.3", "eslint": "^8.56.0", + "eslint-plugin-jsdoc": "^48.0.2", "jest": "^28.1.3", - "prettier": "^3.2.1", "tsx": "^4.7.0", "typescript": "^4.9.5" }, "homepage": "https://github.com/thkruz/ootk-core" -} \ No newline at end of file +} diff --git a/src/body/Celestial.ts b/src/body/Celestial.ts index a9a5182..fa245c6 100644 --- a/src/body/Celestial.ts +++ b/src/body/Celestial.ts @@ -1,8 +1,31 @@ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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. + */ + import { AzEl, Degrees, Kilometers, RAD2DEG, RaDec, Radians, Sun } from '../main'; /** - * Celestial is a static class that provides methods for calculating the position of celestial objects such - * as the Sun, Moon, and planets in the sky. + * Celestial is a static class that provides methods for calculating the position of celestial objects such as the Sun, + * Moon, and planets in the sky. */ export class Celestial { private constructor() { @@ -48,8 +71,8 @@ export class Celestial { * A familiar example of atmospheric refraction is observed during sunrise and sunset. The Sun appears to * be above the horizon when it is actually just below it. This is because the light from the Sun is bent * upwards as it passes through the atmosphere. - * @param {Radians} h - elevation - * @returns {number} refraction + * @param h - elevation + * @returns refraction */ static atmosphericRefraction(h: Radians): Radians { if (h < 0) { @@ -62,9 +85,9 @@ export class Celestial { /** * Calculate the declination. Similar to latitude on Earth, declination is another celestial coordinate. * It measures how far north or south an object is from the celestial equator - * @param {number} l - ecliptic longitude - * @param {number} b - ecliptic latitude - * @returns {number} declination + * @param l - ecliptic longitude + * @param b - ecliptic latitude + * @returns declination */ static declination(l: number, b: number): Radians { return Math.asin(Math.sin(b) * Math.cos(Sun.e) + Math.cos(b) * Math.sin(Sun.e) * Math.sin(l)); @@ -74,9 +97,9 @@ export class Celestial { * Calculate the right ascension. This is a celestial coordinate used to determine the position of objects * in the sky. It's analogous to longitude on Earth. Right Ascension indicates how far east an object is * from the vernal equinox along the celestial equator. - * @param {number} l - ecliptic longitude - * @param {number} b - ecliptic latitude - * @returns {number} right ascension + * @param l - ecliptic longitude + * @param b - ecliptic latitude + * @returns right ascension */ static rightAscension(l: number, b: number): Radians { return Math.atan2(Math.sin(l) * Math.cos(Sun.e) - Math.tan(b) * Math.sin(Sun.e), Math.cos(l)); @@ -87,10 +110,10 @@ export class Celestial { * observer's local horizon. It's commonly expressed in degrees, where 0 degrees is right at the horizon * and 90 degrees is directly overhead (the zenith), but we are using radians to support trigonometric * functions like Math.sin() and Math.cos(). - * @param {number} H - siderealTime - * @param {Radians} phi - latitude - * @param {Radians} dec - The declination of the sun - * @returns {Radians} elevation + * @param H - siderealTime + * @param phi - latitude + * @param dec - The declination of the sun + * @returns elevation */ static elevation(H: number, phi: Radians, dec: Radians): Radians { return Math.asin(Math.sin(phi) * Math.sin(dec) + Math.cos(phi) * Math.cos(dec) * Math.cos(H)); @@ -100,10 +123,10 @@ export class Celestial { * Calculate the azimuth. This is a compass direction measurement. Azimuth measures the angle along * the horizon from a specific reference direction (usually true north) to the point where a vertical * line from the object intersects the horizon. - * @param {number} H - siderealTime - * @param {Radians} phi - latitude - * @param {Radians} dec - The declination of the sun - * @returns {Radians} azimuth in rad + * @param H - siderealTime + * @param phi - latitude + * @param dec - The declination of the sun + * @returns azimuth in rad */ static azimuth(H: number, phi: Radians, dec: Radians): Radians { return (Math.PI + Math.atan2(Math.sin(H), Math.cos(H) * Math.sin(phi) - Math.tan(dec) * Math.cos(phi))); diff --git a/src/body/Earth.ts b/src/body/Earth.ts index 57870f4..27acfe7 100644 --- a/src/body/Earth.ts +++ b/src/body/Earth.ts @@ -1,3 +1,26 @@ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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. + */ + import { angularDiameter, AngularDiameterMethod, @@ -68,7 +91,6 @@ export class Earth { /** * Converts revolutions per day to semi-major axis. - * * @param rpd - The number of revolutions per day. * @returns The semi-major axis value. */ @@ -153,8 +175,8 @@ export class Earth { /** * Calculates the diameter of the Earth based on the satellite position. - * @param satPos The position of the satellite. @returns The diameter of the - * Earth. + * @param satPos The position of the satellite. + * @returns The diameter of the Earth. */ static diameter(satPos: Vector3D): number { return angularDiameter(Earth.radiusEquator * 2, satPos.magnitude(), AngularDiameterMethod.Sphere); diff --git a/src/body/Moon.ts b/src/body/Moon.ts index 7593bb2..2d6fff3 100644 --- a/src/body/Moon.ts +++ b/src/body/Moon.ts @@ -1,32 +1,13 @@ /** * @author Theodore Kruczek. - * @description Orbital Object ToolKit Core (ootk-core) is a collection of tools - * for working with satellites and other orbital objects. - * - * Some of the math in this file was originally created by Vladimir Agafonkin. - * Robert Gester's update was referenced for documentation. There were a couple - * of bugs in both versions so there will be some differences if you are - * migrating from either to this library. - * - * @Copyright (c) 2011-2015, Vladimir Agafonkin SunCalc is a JavaScript library - * for calculating sun/moon position and light phases. - * https://github.com/mourner/suncalc - * - * Reworked and enhanced by Robert Gester @Copyright (c) 2022 Robert Gester - * https://github.com/hypnos3/suncalc3 - * - * moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html - * formulas - * - * @license MIT License - * - * @Copyright (c) 2022-2024 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: + * @license MIT + * @copyright (c) 2022-2024 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. @@ -38,6 +19,21 @@ * 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. + * @copyright (c) 2011-2015, Vladimir Agafonkin + * @copyright (c) 2022 Robert Gester https://github.com/hypnos3/suncalc3 + * @see suncalc.LICENSE.md + * Some of the math in this file was originally created by Vladimir Agafonkin. + * Robert Gester's update was referenced for documentation. There were a couple + * of bugs in both versions so there will be some differences if you are + * migrating from either to this library. + * + * suncalc is a JavaScript library for calculating sun/moon position and light + * phases. https://github.com/mourner/suncalc + * It was reworked and enhanced by Robert Gester. + * + * The original suncalc is released under the terms of the BSD 2-Clause License. + * @see http://aa.quae.nl/en/reken/hemelpositie.html + * moon calculations are based on formulas from this website */ import { AngularDiameterMethod, Celestial, Degrees, Kilometers, RaDec, Radians } from '../main'; @@ -143,10 +139,9 @@ export class Moon { /** * Calculates the illumination of the Moon at a given epoch. - * * @param epoch - The epoch in UTC. - * @param origin - The origin vector. Defaults to the origin vector if not - * provided. @returns The illumination of the Moon, ranging from 0 to 1. + * @param origin - The origin vector. Defaults to the origin vector if not provided. + * @returns The illumination of the Moon, ranging from 0 to 1. */ static illumination(epoch: EpochUTC, origin?: Vector3D): number { const orig = origin ?? (Vector3D.origin as Vector3D); @@ -159,10 +154,9 @@ export class Moon { /** * Calculates the diameter of the Moon. - * * @param obsPos - The position of the observer. - * @param moonPos - The position of the Moon. @returns The diameter of the - * Moon. + * @param moonPos - The position of the Moon. + * @returns The diameter of the Moon. */ static diameter(obsPos: Vector3D, moonPos: Vector3D): number { return angularDiameter(this.radiusEquator * 2, obsPos.subtract(moonPos).magnitude(), AngularDiameterMethod.Sphere); @@ -170,12 +164,10 @@ export class Moon { /** * calculations for illumination parameters of the moon, based on - * http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and Chapter - * 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, - * Richmond) 1998. - * @param {number | Date} date Date object or timestamp for calculating - * moon-illumination @return {MoonIlluminationData} result object of - * moon-illumination + * http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and Chapter 48 of "Astronomical Algorithms" 2nd + * edition by Jean Meeus (Willmann-Bell, Richmond) 1998. + * @param date Date object or timestamp for calculating moon-illumination + * @returns result object of moon-illumination */ // eslint-disable-next-line max-statements static getMoonIllumination(date: number | Date): MoonIlluminationData { @@ -320,8 +312,12 @@ export class Moon { } /** - * calculations for moon rise/set times are based on - * http://www.stargazing.net/kepler/moonrise.html article + * calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article + * @param date Date object or timestamp for calculating moon rise/set + * @param lat Latitude of observer in degrees + * @param lon Longitude of observer in degrees + * @param isUtc If true, date will be interpreted as UTC + * @returns result object of moon rise/set */ static getMoonTimes(date: Date, lat: Degrees, lon: Degrees, isUtc = false) { // Clone the date so we don't change the original @@ -378,7 +374,6 @@ export class Moon { /** * Calculates the geocentric ecliptic coordinates of the moon. - * * @param d - The number of days since year 2000. * @returns An object containing the right ascension, declination, and * distance to the moon. diff --git a/src/body/Sun.ts b/src/body/Sun.ts index ee8a6f8..0eb4ed9 100644 --- a/src/body/Sun.ts +++ b/src/body/Sun.ts @@ -1,3 +1,39 @@ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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. + * @copyright (c) 2011-2015, Vladimir Agafonkin + * @copyright (c) 2022 Robert Gester https://github.com/hypnos3/suncalc3 + * @see suncalc.LICENSE.md + * Some of the math in this file was originally created by Vladimir Agafonkin. + * Robert Gester's update was referenced for documentation. There were a couple + * of bugs in both versions so there will be some differences if you are + * migrating from either to this library. + * + * suncalc is a JavaScript library for calculating sun/moon position and light + * phases. https://github.com/mourner/suncalc + * It was reworked and enhanced by Robert Gester. + * + * The original suncalc is released under the terms of the BSD 2-Clause License. + */ + import { angularDiameter, AngularDiameterMethod, @@ -83,10 +119,12 @@ export class Sun { * Calculates the azimuth and elevation of the Sun for a given date, latitude, * and longitude. * @param date - The date for which to calculate the azimuth and elevation. - * @param lat - The latitude in degrees. @param lon - The longitude in - * degrees. @param c - The right ascension and declination of the target. - * Defaults to the Sun's right ascension and declination @returns An object - * containing the azimuth and elevation of the Sun in radians. + * @param lat - The latitude in degrees. + * @param lon - The longitude in degrees. + * @param c - The right ascension and declination of the target. Defaults to + * the Sun's right ascension and declination + * @returns An object containing the azimuth and elevation of the Sun in + * radians. */ static azEl(date: Date, lat: Degrees, lon: Degrees, c?: RaDec): AzEl { const lw = (-lon * DEG2RAD); @@ -104,44 +142,47 @@ export class Sun { /** * get number of days for a dateValue since 2000 - * * See: https://en.wikipedia.org/wiki/Epoch_(astronomy) - * - * @param {number} date date as timestamp to get days - * @return {number} count of days + * @param date date as timestamp to get days + * @returns count of days */ static date2jSince2000(date: Date): number { return date.getTime() / MS_PER_DAY + Sun.J1970_ - Sun.J2000_; } /** - * Calculate the Sun's angular diameter _(rad)_ from an ECI observer position - * [obsPos] and Sun position [sunPos] _(km)_. + * Calculates the angular diameter of the Sun given the observer's position + * and the Sun's position. + * @param obsPos The observer's position in kilometers. + * @param sunPos The Sun's position in kilometers. + * @returns The angular diameter of the Sun in radians. */ - static diameter(obsPos: Vector3D, sunPos: Vector3D): number { - return angularDiameter(this.radius * 2, obsPos.subtract(sunPos).magnitude(), AngularDiameterMethod.Sphere); + static diameter(obsPos: Vector3D, sunPos: Vector3D): Radians { + return angularDiameter( + this.radius * 2, + obsPos.subtract(sunPos).magnitude(), + AngularDiameterMethod.Sphere, + ) as Radians; } /** - * Calculate eclipse angles given a satellite ECI position [satPos] _(km)_ and - * Sun ECI position [sunPos] _(km)_. - * - * Returns a tuple containing the following three values: - * - central body angle _(rad)_ - * - central body apparant radius _(rad)_ - * - sun apparant radius _(rad)_ + * Calculate eclipse angles given a satellite ECI position and Sun ECI + * position. + * @param satPos the satellite position + * @param sunPos the sun position + * @returns [central body angle, central body apparent radius, sun apparent] */ - static eclipseAngles(satPos: Vector3D, sunPos: Vector3D): [number, number, number] { + static eclipseAngles(satPos: Vector3D, sunPos: Vector3D): [Radians, Radians, Radians] { const satSun = sunPos.subtract(satPos); const r = satPos.magnitude(); return [ // central body angle - satSun.angle(satPos.negate()), + satSun.angle(satPos.negate()) as Radians, // central body apparent radius - Math.asin(Earth.radiusEquator / r), + Math.asin(Earth.radiusEquator / r) as Radians, // sun apparent radius - Math.asin(this.radius / satSun.magnitude()), + Math.asin(this.radius / satSun.magnitude()) as Radians, ]; } @@ -149,9 +190,8 @@ export class Sun { * Ecliptic latitude measures the distance north or south of the ecliptic, * attaining +90° at the north ecliptic pole (NEP) and -90° at the south * ecliptic pole (SEP). The ecliptic itself is 0° latitude. - * - * @param {number} B - ? - * @returns {number} ecliptic latitude + * @param B - ? + * @returns ecliptic latitude */ static eclipticLatitude(B: number): number { const C = TAU / 360; @@ -168,7 +208,8 @@ export class Sun { * Earth towards the Sun at the vernal equinox of the Northern Hemisphere. Due * to axial precession, the ecliptic longitude of most "fixed stars" increases * by about 50.3 arcseconds per year, or 83.8 arcminutes per century. - * @param {number} M - solar mean anomaly @returns {number} ecliptic longitude + * @param M - solar mean anomaly + * @returns ecliptic longitude */ static eclipticLongitude(M: number): Radians { const C = DEG2RAD * (1.9148 * Math.sin(M) + 0.02 * Math.sin(2 * M) + 0.0003 * Math.sin(3 * M)); @@ -179,10 +220,14 @@ export class Sun { /** * returns set time for the given sun altitude - * @param {number} h - height at 0 @param {number} lw - rad * -lng @param - * {number} phi - rad * lat; @param {number} dec - declination @param - * {number} n - Julian cycle @param {number} M - solar mean anomal @param - * {number} L - ecliptic longitude @returns {number} set time + * @param h - height at 0 + * @param lw - rad * -lng + * @param phi - rad * lat; + * @param dec - declination + * @param n - Julian cycle + * @param M - solar mean anomal + * @param L - ecliptic longitude + * @returns set time */ static getSetJulian(h: Meters, lw: number, phi: number, dec: number, n: number, M: number, L: number): number { const w = Sun.hourAngle(h, phi, dec); @@ -192,33 +237,14 @@ export class Sun { } /** - * Convert Date to Solar Date/Time - * - * Based on - * https://www.pveducation.org/pvcdrom/properties-of-sunlight/solar-time - * - * See: https://github.com/mourner/suncalc/pull/156 - */ - static getSolarTime(date: Date, utcOffset: number, lon: Degrees) { - // calculate the day of year - const start = new Date(); - - start.setUTCFullYear(date.getUTCFullYear(), 0, 1); - start.setUTCHours(0, 0, 0, 0); - const diff = date.getTime() - start.getTime(); - const dayOfYear = Math.floor(diff / MS_PER_DAY); - - const b = (360 / 365) * (dayOfYear - 81) * DEG2RAD; - const equationOfTime = 9.87 * Math.sin(2 * b) - 7.53 * Math.cos(b) - 1.5 * Math.sin(b); - const localSolarTimeMeridian = 15 * utcOffset; - const timeCorrection = equationOfTime + 4 * (lon - localSolarTimeMeridian); - - return new Date(date.getTime() + timeCorrection * 60 * 1000); - } - - /** - * Calculates time for a given azimuth angle for a given date and - * latitude/longitude + * Calculates the time of the sun based on the given azimuth. + * @param dateValue - The date value or Date object. + * @param lat - The latitude in degrees. + * @param lon - The longitude in degrees. + * @param az - The azimuth in radians or degrees. + * @param isDegrees - Indicates if the azimuth is in degrees. Default is false. + * @returns The calculated time of the sun. + * @throws Error if the azimuth, latitude, or longitude is missing. */ static getSunTimeByAz( dateValue: number | Date, @@ -272,6 +298,13 @@ export class Sun { * * Default altitude is 0 meters. If `isUtc` is `true`, the times are returned * as UTC, otherwise in local time. + * @param dateVal - The date value or Date object. + * @param lat - The latitude in degrees. + * @param lon - The longitude in degrees. + * @param alt - The altitude in meters. Default is 0. + * @param isUtc - Indicates if the times should be returned as UTC. Default is + * false. + * @returns An object containing the times of the sun. */ static getTimes(dateVal: Date | number, lat: Degrees, lon: Degrees, alt: Meters = 0, isUtc = false): SunTime { if (isNaN(lat)) { @@ -322,8 +355,10 @@ export class Sun { /** * hour angle - * @param {number} h - heigh at 0 @param {number} phi - rad * lat; @param - * {number} dec - declination @returns {number} hour angle + * @param h - heigh at 0 + * @param phi - rad * lat; + * @param dec - declination + * @returns hour angle */ static hourAngle(h: number, phi: number, dec: number): number { return Math.acos((Math.sin(h) - Math.sin(phi) * Math.sin(dec)) / (Math.cos(phi) * Math.cos(dec))); @@ -331,8 +366,8 @@ export class Sun { /** * convert Julian calendar to date object - * @param {number} julian day number in Julian calendar to convert @return - * {number} result date as timestamp + * @param julian day number in Julian calendar to convert + * @returns result date as timestamp */ static julian2date(julian: number): Date { return new Date((julian - Sun.J1970_) * MS_PER_DAY); @@ -356,9 +391,9 @@ export class Sun { * cycle of 28 years and the Roman Indiction repeats every 15 years. Thus the * Julian Period is calculated to be 7980 years long or 2,914,695 days because * 19*28*15 = 7980. - * - * @param {Date} date - Date object for calculating julian cycle - * @param {Degrees} lon - Degrees longitude @returns {number} julian cycle + * @param date - Date object for calculating julian cycle + * @param lon - Degrees longitude + * @returns julian cycle */ static julianCycle(date: Date, lon: Degrees): number { const lw = (-lon * DEG2RAD); @@ -373,8 +408,11 @@ export class Sun { * * Returns `1.0` if the satellite is fully illuminated and `0.0` when fully * eclipsed. + * @param satPos - The position of the satellite. + * @param sunPos - The position of the sun. + * @returns The lighting ratio. */ - static lightingRatio(satPos: Vector3D, sunPos: Vector3D): number { + static lightingRatio(satPos: Vector3D, sunPos: Vector3D): number { const [sunSatAngle, aCent, aSun] = Sun.eclipseAngles(satPos, sunPos); if (sunSatAngle - aCent + aSun <= 1e-10) { @@ -401,15 +439,12 @@ export class Sun { } /** - * Calculates the lighting factor based on the position of the satellite and - * the sun. - * - * @deprecated - * This method was previously used. It is now deprecated and will be removed + * Calculates the lighting factor based on the position of the satellite and the sun. + * @deprecated This method was previously used. It is now deprecated and will be removed * in a future release. - * * @param satPos The position of the satellite. - * @param sunPos The position of the sun. @returns The lighting factor. + * @param sunPos The position of the sun. + * @returns The lighting factor. */ static sunlightLegacy(satPos: Vector3D, sunPos: Vector3D): number { let lighting = 1.0; @@ -426,8 +461,8 @@ export class Sun { const theta = Math.acos( satPos.negate().dot(sunPos.negate()) / - (Math.sqrt((-satPos.x) ** 2 + (-satPos.y) ** 2 + (-satPos.z) ** 2) * - Math.sqrt((-satPos.x + sunPos.x) ** 2 + (-satPos.y + sunPos.y) ** 2 + (-satPos.z + sunPos.z) ** 2)), + (Math.sqrt((-satPos.x) ** 2 + (-satPos.y) ** 2 + (-satPos.z) ** 2) * + Math.sqrt((-satPos.x + sunPos.x) ** 2 + (-satPos.y + sunPos.y) ** 2 + (-satPos.z + sunPos.z) ** 2)), ) * RAD2DEG; if (semiDiamEarth > semiDiamSun && theta < semiDiamEarth - semiDiamSun) { @@ -452,8 +487,8 @@ export class Sun { /** * Calculates the position vector of the Sun at a given epoch in the * Earth-centered inertial (ECI) coordinate system. - * @param epoch - The epoch in UTC. @returns The position vector of the Sun in - * Kilometers. + * @param epoch - The epoch in UTC. + * @returns The position vector of the Sun in Kilometers. */ static position(epoch: EpochUTC): Vector3D { const jc = epoch.toJulianCenturies(); @@ -480,8 +515,10 @@ export class Sun { /** * Calculate the Sun's apparent ECI position _(km)_ from Earth for a given UTC * [epoch]. + * @param epoch - The epoch in UTC. + * @returns The Sun's apparent ECI position in kilometers. */ - static positionApparent(epoch: EpochUTC): Vector3D { + static positionApparent(epoch: EpochUTC): Vector3D { const distance = Sun.position(epoch).magnitude(); const dSec = distance / cKmPerSec; @@ -490,11 +527,8 @@ export class Sun { /** * Calculates the right ascension and declination of the Sun for a given date. - * - * @param date - The date for which to calculate the right ascension and - * declination. - * @returns An object containing the declination and right ascension of the - * Sun. + * @param date - The date for which to calculate the right ascension and declination. + * @returns An object containing the declination and right ascension of the Sun. */ static raDec(date: Date): RaDec { const d = Sun.date2jSince2000(date); @@ -511,8 +545,11 @@ export class Sun { /** * Return `true` if the ECI satellite position [posSat] is in eclipse at the * given UTC [epoch]. + * @param epoch - The epoch in UTC. + * @param posSat - The ECI position of the satellite in kilometers. + * @returns `true` if the satellite is in eclipse. */ - static shadow(epoch: EpochUTC, posSat: Vector3D): boolean { + static shadow(epoch: EpochUTC, posSat: Vector3D): boolean { const posSun = Sun.positionApparent(epoch); let shadow = false; @@ -533,8 +570,9 @@ export class Sun { /** * side real time - * @param {number} d - julian day @param {Radians} lw - longitude of the - * observer @returns {number} sidereal time + * @param d - julian day + * @param lw - longitude of the observer + * @returns sidereal time */ static siderealTime(d: number, lw: Radians): number { return DEG2RAD * (280.16 + 360.9856235 * d) - lw; @@ -542,9 +580,10 @@ export class Sun { /** * solar transit in Julian - * @param {number} ds - approxTransit @param {number} M - solar mean anomal - * @param {number} L - ecliptic longitude @returns {number} solar transit in - * Julian + * @param ds approxTransit + * @param M solar mean anomal + * @param L ecliptic longitude + * @returns solar transit in Julian */ static solarTransitJulian(ds: number, M: number, L: number): number { return Sun.J2000_ + ds + 0.0053 * Math.sin(M) - 0.0069 * Math.sin(2 * L); @@ -552,8 +591,10 @@ export class Sun { /** * The approximate transit time - * @param {number} Ht - hourAngle @param {number} lw - rad * -lng @param - * {number} n - Julian cycle @returns {number} approx transit + * @param Ht hourAngle + * @param lw rad * -lng + * @param n Julian cycle + * @returns approx transit */ private static approxTransit_(Ht: number, lw: number, n: number): number { return Sun.J0_ + (Ht + lw) / TAU + n; @@ -577,10 +618,14 @@ export class Sun { /** * returns set time for the given sun altitude - * @param {Meters} alt - altitude at 0 @param {Radians} lw - -lng @param - * {Radians} phi - lat; @param {Radians} dec - declination @param {number} n - - * Julian cycle @param {number} M - solar mean anomal @param {number} L - - * ecliptic longitude @return {number} sunset time in days since 2000 + * @param alt altitude at 0 + * @param lw lng + * @param phi lat + * @param dec declination + * @param n Julian cycle + * @param M solar mean anomal + * @param L ecliptic longitude + * @returns sunset time in days since 2000 */ private static getSetJ_( alt: Meters, @@ -605,8 +650,8 @@ export class Sun { /** * calculates the obderver angle - * @param {number} alt the observer altitude (in meters) relative to the - * horizon @returns {Degrees} height for further calculations + * @param alt the observer altitude (in meters) relative to the horizon + * @returns height for further calculations */ private static observerAngle_(alt: Meters): Degrees { return ((-2.076 * Math.sqrt(alt)) / 60); @@ -614,7 +659,8 @@ export class Sun { /** * get solar mean anomaly - * @param {number} d - julian day @returns {number} solar mean anomaly + * @param d julian day + * @returns solar mean anomaly */ private static solarMeanAnomaly_(d: number): number { return DEG2RAD * (357.5291 + 0.98560028 * d); diff --git a/src/body/suncalc.LICENSE.md b/src/body/suncalc.LICENSE.md new file mode 100644 index 0000000..62798ed --- /dev/null +++ b/src/body/suncalc.LICENSE.md @@ -0,0 +1,18 @@ +Copyright (c) 2014, Vladimir Agafonkin All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following + disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/coordinate/ClassicalElements.ts b/src/coordinate/ClassicalElements.ts index bd7787a..563052d 100644 --- a/src/coordinate/ClassicalElements.ts +++ b/src/coordinate/ClassicalElements.ts @@ -1,3 +1,26 @@ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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. + */ + import { Minutes, PositionVelocity, Degrees, Kilometers, Radians, Seconds } from '../main'; import { Vector3D } from '../operations/Vector3D'; import { EpochUTC } from '../time/EpochUTC'; @@ -9,9 +32,7 @@ import { StateVector } from './StateVector'; import { ClassicalElementsParams } from '../interfaces/ClassicalElementsParams'; /** - * The ClassicalElements class represents the classical orbital elements of an - * object. - * + * The ClassicalElements class represents the classical orbital elements of an object. * @example * ```ts * const epoch = EpochUTC.fromDateTime(new Date('2024-01-14T14:39:39.914Z')); @@ -59,10 +80,10 @@ export class ClassicalElements { /** * Creates a new instance of ClassicalElements from a StateVector. - * @param state The StateVector to convert. @param mu The gravitational - * parameter of the central body. Default value is Earth's gravitational - * parameter. @returns A new instance of ClassicalElements. @throws Error if - * the StateVector is not in an inertial frame. + * @param state The StateVector to convert. + * @param mu The gravitational parameter of the central body. Default value is Earth's gravitational parameter. + * @returns A new instance of ClassicalElements. + * @throws Error if the StateVector is not in an inertial frame. */ static fromStateVector(state: StateVector, mu = earthGravityParam): ClassicalElements { if (!state.inertial) { @@ -243,7 +264,7 @@ export class ClassicalElements { /** * Converts the classical elements to equinoctial elements. - * @returns {EquinoctialElements} The equinoctial elements. + * @returns The equinoctial elements. */ toEquinoctialElements(): EquinoctialElements { const I = this.inclination > Math.PI / 2 ? -1 : 1; @@ -260,7 +281,6 @@ export class ClassicalElements { /** * Propagates the classical elements to a given epoch. - * * @param propEpoch - The epoch to propagate the classical elements to. * @returns The classical elements at the propagated epoch. */ diff --git a/src/coordinate/EquinoctialElements.ts b/src/coordinate/EquinoctialElements.ts index ed8526b..60bd05d 100644 --- a/src/coordinate/EquinoctialElements.ts +++ b/src/coordinate/EquinoctialElements.ts @@ -1,3 +1,26 @@ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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. + */ + import { Kilometers, Radians, Seconds } from '../main'; import { EpochUTC } from '../time/EpochUTC'; import { earthGravityParam, MINUTES_PER_DAY, TAU } from '../utils/constants'; @@ -17,42 +40,25 @@ import { EquinoctialElementsParams } from '../interfaces/EquinoctialElementsPara * singularities at zero eccentricity (circular orbits) or zero inclination * (equatorial orbits). This makes them more reliable for numerical simulations * and analytical studies, especially in these edge cases. - * * @see https://faculty.nps.edu/dad/orbital/th0.pdf */ export class EquinoctialElements { epoch: EpochUTC; - /** - * The semi-major axis of the orbit in kilometers. - */ + /** The semi-major axis of the orbit in kilometers. */ a: Kilometers; - /** - * The h component of the eccentricity vector. - */ + /** The h component of the eccentricity vector. */ h: number; - /** - * The k component of the eccentricity vector. - */ + /** The k component of the eccentricity vector. */ k: number; - /** - * The p component of the ascending node vector. - */ + /** The p component of the ascending node vector. */ p: number; - /** - * The q component of the ascending node vector. - */ + /** The q component of the ascending node vector. */ q: number; - /** - * The mean longitude of the orbit in radians. - */ + /** The mean longitude of the orbit in radians. */ lambda: Radians; - /** - * The gravitational parameter of the central body in km³/s². - */ + /** The gravitational parameter of the central body in km³/s². */ mu: number; - /** - * The retrograde factor. 1 for prograde orbits, -1 for retrograde orbits. - */ + /** The retrograde factor. 1 for prograde orbits, -1 for retrograde orbits. */ I: 1 | -1; constructor({ epoch, h, k, lambda, a, p, q, mu, I }: EquinoctialElementsParams) { this.epoch = epoch; @@ -101,7 +107,6 @@ export class EquinoctialElements { /** * Calculates the mean motion of the celestial object. - * * @returns The mean motion in units of radians per second. */ get meanMotion(): number { @@ -110,7 +115,6 @@ export class EquinoctialElements { /** * Gets the retrograde factor. - * * @returns The retrograde factor. */ get retrogradeFactor(): number { @@ -119,7 +123,7 @@ export class EquinoctialElements { /** * Checks if the orbit is prograde. - * @returns {boolean} True if the orbit is prograde, false otherwise. + * @returns True if the orbit is prograde, false otherwise. */ isPrograde(): boolean { return this.I === 1; @@ -127,7 +131,7 @@ export class EquinoctialElements { /** * Checks if the orbit is retrograde. - * @returns {boolean} True if the orbit is retrograde, false otherwise. + * @returns True if the orbit is retrograde, false otherwise. */ isRetrograde(): boolean { return this.I === -1; @@ -145,7 +149,6 @@ export class EquinoctialElements { /** * Gets the number of revolutions per day. - * * @returns The number of revolutions per day. */ get revsPerDay(): number { diff --git a/src/coordinate/FormatTle.ts b/src/coordinate/FormatTle.ts index 237405e..4d512b5 100644 --- a/src/coordinate/FormatTle.ts +++ b/src/coordinate/FormatTle.ts @@ -1,3 +1,26 @@ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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. + */ + import { StringifiedNumber, TleParams } from 'src/types/types'; import { Tle } from './Tle'; @@ -12,7 +35,6 @@ export abstract class FormatTle { /** * Creates a TLE (Two-Line Element) string based on the provided TleParams. * @param tleParams - The parameters used to generate the TLE. - * * @returns An object containing the TLE strings tle1 and tle2. */ static createTle(tleParams: TleParams): { tle1: string; tle2: string } { @@ -45,11 +67,8 @@ export abstract class FormatTle { /** * Converts the argument of perigee to a stringified number. - * - * @param argPe - The argument of perigee to be converted. Can be either a - * number or a string. + * @param argPe - The argument of perigee to be converted. Can be either a number or a string. * @returns The argument of perigee as a stringified number. - * * @throws Error if the length of the argument of perigee is not 8. */ static argumentOfPerigee(argPe: number | string): StringifiedNumber { @@ -69,10 +88,8 @@ export abstract class FormatTle { /** * Returns the eccentricity value of a given string. - * * @param ecen - The string representing the eccentricity. * @returns The eccentricity value. - * * @throws Error if the length of the eccentricity string is not 7. */ static eccentricity(ecen: string): string { @@ -92,10 +109,8 @@ export abstract class FormatTle { /** * Converts the inclination value to a string representation. - * * @param inc - The inclination value to be converted. * @returns The string representation of the inclination value. - * * @throws Error if the length of the converted value is not 8. */ static inclination(inc: number | string): StringifiedNumber { @@ -114,14 +129,9 @@ export abstract class FormatTle { } /** - * Converts the mean anomaly to a string representation with 8 digits, padded - * with leading zeros. - * @param meana - The mean anomaly to be converted. Can be either a number or - * a string. - * - * @returns The mean anomaly as a string with 8 digits, padded with leading - * zeros. - * + * Converts the mean anomaly to a string representation with 8 digits, padded with leading zeros. + * @param meana - The mean anomaly to be converted. Can be either a number or a string. + * @returns The mean anomaly as a string with 8 digits, padded with leading zeros. * @throws Error if the length of the mean anomaly is not 8. */ static meanAnomaly(meana: number | string): StringifiedNumber { @@ -146,11 +156,9 @@ export abstract class FormatTle { * with 8 decimal places. The resulting string is padded with leading zeros to * ensure a length of 11 characters. Throws an error if the resulting string * does not have a length of 11 characters. - * * @param meanmo - The mean motion value to be converted. * @returns The string representation of the mean motion value with 8 decimal * places and padded with leading zeros. - * * @throws Error if the resulting string does not have a length of 11 * characters. */ @@ -171,7 +179,6 @@ export abstract class FormatTle { /** * Converts the right ascension value to a stringified number. - * * @param rasc - The right ascension value to convert. * @returns The stringified number representation of the right ascension. * @throws Error if the length of the converted right ascension is not 8. @@ -192,14 +199,11 @@ export abstract class FormatTle { } /** - * Sets a character at a specific index in a string. If the index is out of - * range, the original string is returned. + * Sets a character at a specific index in a string. If the index is out of range, the original string is returned. * @param str - The input string. - * * @param index - The index at which to set the character. - * - * @param chr - The character to set at the specified index. @returns The - * modified string with the character set at the specified index. + * @param chr - The character to set at the specified index. + * @returns The modified string with the character set at the specified index. */ static setCharAt(str: string, index: number, chr: string): string { if (index > str.length - 1) { diff --git a/src/coordinate/Geodetic.ts b/src/coordinate/Geodetic.ts index e55f90a..6511967 100644 --- a/src/coordinate/Geodetic.ts +++ b/src/coordinate/Geodetic.ts @@ -1,3 +1,26 @@ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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. + */ + import { Earth } from '../body/Earth'; import { AngularDistanceMethod, Degrees, GroundObject, Kilometers, Radians } from '../main'; import { Vector3D } from '../operations/Vector3D'; @@ -46,11 +69,8 @@ export class Geodetic { * Creates a Geodetic object from latitude, longitude, and altitude values in * degrees. * @param latitude The latitude value in degrees. - * * @param longitude The longitude value in degrees. - * * @param altitude The altitude value in kilometers. - * * @returns A Geodetic object representing the specified latitude, longitude, * and altitude. */ @@ -60,9 +80,7 @@ export class Geodetic { /** * Returns a string representation of the Geodetic object. - * - * @returns A string containing the latitude, longitude, and altitude of the - * Geodetic object. + * @returns A string containing the latitude, longitude, and altitude of the Geodetic object. */ toString(): string { return [ @@ -104,7 +122,8 @@ export class Geodetic { /** * Converts the geodetic coordinates to the International Terrestrial * Reference Frame (ITRF) coordinates. - * @param epoch The epoch in UTC. @returns The ITRF coordinates. + * @param epoch The epoch in UTC. + * @returns The ITRF coordinates. */ toITRF(epoch: EpochUTC): ITRF { const sLat = Math.sin(this.lat); @@ -121,10 +140,9 @@ export class Geodetic { /** * Calculates the angle between two geodetic coordinates. - * @param g The geodetic coordinate to calculate the angle to. @param method - * The method to use for calculating the angular distance (optional, default - * is Haversine). @returns The angle between the two geodetic coordinates in - * radians. + * @param g The geodetic coordinate to calculate the angle to. + * @param method The method to use for calculating the angular distance (optional, default is Haversine). + * @returns The angle between the two geodetic coordinates in radians. */ angle(g: Geodetic, method: AngularDistanceMethod = AngularDistanceMethod.Haversine): Radians { return angularDistance(this.lon, this.lat, g.lon, g.lat, method) as Radians; @@ -132,9 +150,9 @@ export class Geodetic { /** * Calculates the angle in degrees between two Geodetic coordinates. - * @param g The Geodetic coordinate to calculate the angle with. @param method - * The method to use for calculating the angular distance (optional, default - * is Haversine). @returns The angle in degrees. + * @param g The Geodetic coordinate to calculate the angle with. + * @param method The method to use for calculating the angular distance (optional, default is Haversine). + * @returns The angle in degrees. */ angleDeg(g: Geodetic, method: AngularDistanceMethod = AngularDistanceMethod.Haversine): Degrees { return (this.angle(g, method) * RAD2DEG) as Degrees; @@ -142,10 +160,9 @@ export class Geodetic { /** * Calculates the distance between two geodetic coordinates. - * @param g The geodetic coordinates to calculate the distance to. @param - * method The method to use for calculating the angular distance. Default is - * Haversine. @returns The distance between the two geodetic coordinates in - * kilometers. + * @param g The geodetic coordinates to calculate the distance to. + * @param method The method to use for calculating the angular distance. Default is Haversine. + * @returns The distance between the two geodetic coordinates in kilometers. */ distance(g: Geodetic, method: AngularDistanceMethod = AngularDistanceMethod.Haversine): Kilometers { return (this.angle(g, method) * Earth.radiusMean) as Kilometers; @@ -160,12 +177,10 @@ export class Geodetic { } /** - * Determines if the current geodetic coordinate can see another geodetic - * coordinate. - * @param g The geodetic coordinate to check for visibility. @param method The - * method to use for calculating the angular distance (optional, default is - * Haversine). @returns A boolean indicating if the current coordinate can see - * the other coordinate. + * Determines if the current geodetic coordinate can see another geodetic coordinate. + * @param g The geodetic coordinate to check for visibility. + * @param method The method to use for calculating the angular distance (optional, default is Haversine). + * @returns A boolean indicating if the current coordinate can see the other coordinate. */ isInView(g: Geodetic, method: AngularDistanceMethod = AngularDistanceMethod.Haversine): boolean { const fov = Math.max(this.fieldOfView(), g.fieldOfView()); diff --git a/src/coordinate/ITRF.ts b/src/coordinate/ITRF.ts index 25f7ce0..259debc 100644 --- a/src/coordinate/ITRF.ts +++ b/src/coordinate/ITRF.ts @@ -1,3 +1,26 @@ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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, Radians, Vector3D } from 'src/main'; import { Earth } from '../body/Earth'; @@ -6,23 +29,18 @@ import { J2000 } from './J2000'; import { StateVector } from './StateVector'; /** - * 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 + * 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 + * 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 { /** @@ -35,17 +53,14 @@ export class ITRF extends StateVector { /** * Gets a value indicating whether the coordinate system is inertial. - * @returns A boolean 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. - * + * Gets the height of the ITRF coordinate above the surface of the Earth in kilometers. * @returns The height in kilometers. */ get height(): Kilometers { @@ -68,10 +83,8 @@ export class ITRF extends StateVector { } /** - * 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. - * + * 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. */ @@ -96,10 +109,9 @@ export class ITRF extends StateVector { } /** - * Converts the current ITRF coordinate to Geodetic coordinate. This is a - * coordinate system for latitude, longitude, and altitude. - * - * @returns {Geodetic} The converted Geodetic coordinate. + * 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; diff --git a/src/coordinate/J2000.ts b/src/coordinate/J2000.ts index 3e6fa38..4bb011f 100644 --- a/src/coordinate/J2000.ts +++ b/src/coordinate/J2000.ts @@ -1,4 +1,26 @@ -/* eslint-disable class-methods-use-this */ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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. + */ + import { Kilometers, Radians, Vector3D } from '../main'; import { Earth } from '../body/Earth'; import { ClassicalElements } from './ClassicalElements'; @@ -7,22 +29,20 @@ import { StateVector } from './StateVector'; import { TEME } from './TEME'; /** - * Represents a position and velocity in the J2000 coordinate system. This is an - * Earth-centered inertial (ECI) coordinate system. - * - * Commonly used ECI frame is defined with the Earth's Mean Equator and Mean - * Equinox (MEME) at 12:00 Terrestrial Time on 1 January 2000. It can be - * referred to as J2K, J2000 or EME2000. The x-axis is aligned with the mean - * vernal equinox. The z-axis is aligned with the Earth's rotation axis (or - * equivalently, the celestial North Pole) as it was at that time. The y-axis is - * rotated by 90° East about the celestial equator. + * Represents a position and velocity in the J2000 coordinate system. This is an Earth-centered inertial (ECI) + * coordinate system. * + * Commonly used ECI frame is defined with the Earth's Mean Equator and Mean Equinox (MEME) at 12:00 Terrestrial Time on + * 1 January 2000. It can be referred to as J2K, J2000 or EME2000. The x-axis is aligned with the mean vernal equinox. + * The z-axis is aligned with the Earth's rotation axis (or equivalently, the celestial North Pole) as it was at that + * time. The y-axis is rotated by 90° East about the celestial equator. * @see https://en.wikipedia.org/wiki/Earth-centered_inertial */ export class J2000 extends StateVector { /** * Creates a J2000 coordinate from classical elements. - * @param elements The classical elements. @returns The J2000 coordinate. + * @param elements The classical elements. + * @returns The J2000 coordinate. */ static fromClassicalElements(elements: ClassicalElements): J2000 { const rv = elements.toPositionVelocity(); @@ -40,19 +60,15 @@ export class J2000 extends StateVector { /** * Gets a value indicating whether the coordinate system is inertial. - * @returns A boolean value indicating whether the coordinate system is - * inertial. + * @returns A boolean value indicating whether the coordinate system is inertial. */ get inertial(): boolean { return true; } /** - * Converts the coordinates from J2000 to the International Terrestrial - * Reference Frame (ITRF). - * + * Converts the coordinates from J2000 to the International Terrestrial Reference Frame (ITRF). * This is an ECI to ECF transformation. - * * @returns The ITRF coordinates. */ toITRF(): ITRF { @@ -83,7 +99,6 @@ export class J2000 extends StateVector { /** * Converts the J2000 coordinate to the TEME coordinate. - * * @returns The TEME coordinate. */ toTEME(): TEME { diff --git a/src/coordinate/RIC.ts b/src/coordinate/RIC.ts index a5546f2..713b4c3 100644 --- a/src/coordinate/RIC.ts +++ b/src/coordinate/RIC.ts @@ -1,4 +1,26 @@ -/* eslint-disable class-methods-use-this */ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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. + */ + import { Matrix } from '../operations/Matrix'; import { J2000 } from './J2000'; import { RelativeState } from './RelativeState'; @@ -16,15 +38,10 @@ export class RIC extends RelativeState { } /** - * Creates a new RIC (Radial-Intrack-Crosstrack) coordinate from the J2000 - * state vectors. - * + * Creates a new RIC (Radial-Intrack-Crosstrack) coordinate from the J2000 state vectors. * @param state - The J2000 state vector. - * * @param origin - The J2000 state vector of the origin. - * * @param transform - The transformation matrix. - * * @returns The RIC coordinate. */ static fromJ2000Matrix(state: J2000, origin: J2000, transform: Matrix): RIC { @@ -35,12 +52,9 @@ export class RIC extends RelativeState { } /** - * Creates a RIC (Radial-Intrack-Crosstrack) coordinate system from a J2000 - * state and origin. + * Creates a RIC (Radial-Intrack-Crosstrack) coordinate system from a J2000 state and origin. * @param state The J2000 state. - * * @param origin The J2000 origin. - * * @returns The RIC coordinate system. */ static fromJ2000(state: J2000, origin: J2000): RIC { @@ -48,12 +62,10 @@ export class RIC extends RelativeState { } /** - * Transforms the current RIC coordinate to the J2000 coordinate system using - * the provided origin and transform matrix + * Transforms the current RIC coordinate to the J2000 coordinate system using the provided origin and transform + * matrix. * @param origin The origin J2000 coordinate. - * * @param transform The transformation matrix. - * * @returns The transformed J2000 coordinate. */ toJ2000Matrix(origin: J2000, transform: Matrix): J2000 { @@ -65,10 +77,8 @@ export class RIC extends RelativeState { } /** - * Transforms the current RIC coordinate to the J2000 coordinate system using - * the provided origin. + * Transforms the current RIC coordinate to the J2000 coordinate system using the provided origin. * @param origin The origin J2000 coordinate. - * * @returns The transformed J2000 coordinate. */ toJ2000(origin: J2000): J2000 { diff --git a/src/coordinate/RelativeState.ts b/src/coordinate/RelativeState.ts index 52d6847..d34b984 100644 --- a/src/coordinate/RelativeState.ts +++ b/src/coordinate/RelativeState.ts @@ -1,3 +1,26 @@ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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. + */ + import { Kilometers } from 'src/main'; import { Matrix } from '../operations/Matrix'; import { Vector3D } from '../operations/Vector3D'; @@ -16,15 +39,13 @@ export abstract class RelativeState { /** * Gets the name of the coordinate system. - * * @returns The name of the coordinate system. */ abstract get name(): string; /** - * Returns a string representation of the RelativeState object. The string - * includes the name, position, and velocity of the object. - * + * Returns a string representation of the RelativeState object. The string includes the name, position, and velocity + * of the object. * @returns A string representation of the RelativeState object. */ toString(): string { @@ -38,19 +59,15 @@ export abstract class RelativeState { /** * Transforms the current RelativeState coordinate to the J2000 coordinate * @param origin The origin J2000 coordinate. - * * @returns The transformed J2000 coordinate. */ abstract toJ2000(origin: J2000): J2000; /** - * Creates a matrix based on the given position and velocity vectors. The - * matrix represents the relative state of an object in 3D space. - * + * Creates a matrix based on the given position and velocity vectors. The matrix represents the relative state of an + * object in 3D space. * @param position - The position vector. - * * @param velocity - The velocity vector. - * * @returns The matrix representing the relative state. */ static createMatrix(position: Vector3D, velocity: Vector3D): Matrix { @@ -74,9 +91,8 @@ export abstract class RelativeState { } /** - * Calculates the range rate of the relative state. Range rate is the dot - * product of the position and velocity divided by the range. - * + * Calculates the range rate of the relative state. Range rate is the dot product of the position and velocity divided + * by the range. * @returns The range rate in Kilometers per second. */ get rangeRate(): number { diff --git a/src/coordinate/StateVector.ts b/src/coordinate/StateVector.ts index 6559ee5..15b7a13 100644 --- a/src/coordinate/StateVector.ts +++ b/src/coordinate/StateVector.ts @@ -1,3 +1,26 @@ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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. + */ + import { Kilometers, Minutes } from 'src/main'; import { Earth } from '../body/Earth'; import type { Vector3D } from '../operations/Vector3D'; @@ -21,17 +44,19 @@ export abstract class StateVector { /** * The name of the reference frame in which the state vector is defined. + * @returns The name of the reference frame. */ abstract get name(): string; /** * Whether the state vector is defined in an inertial reference frame. + * @returns True if the state vector is defined in an inertial reference */ abstract get inertial(): boolean; /** - * Returns a string representation of the StateVector object. The string - * includes the name, epoch, position, and velocity. + * Returns a string representation of the StateVector object. The string includes the name, epoch, position, and + * velocity. * @returns A string representation of the StateVector object. */ toString(): string { @@ -45,7 +70,6 @@ export abstract class StateVector { /** * Calculates the mechanical energy of the state vector. - * * @returns The mechanical energy value. */ get mechanicalEnergy(): number { @@ -57,7 +81,6 @@ export abstract class StateVector { /** * Calculates the semimajor axis of the state vector. - * * @returns The semimajor axis in kilometers. */ get semimajorAxis(): Kilometers { @@ -68,7 +91,6 @@ export abstract class StateVector { /** * Gets the period of the state vector in minutes. - * * @returns The period in minutes. */ get period(): Minutes { @@ -80,7 +102,6 @@ export abstract class StateVector { /** * Gets the angular rate of the state vector. - * * @returns The angular rate. */ get angularRate(): number { @@ -91,12 +112,11 @@ export abstract class StateVector { /** * Converts the state vector to classical elements. - * @param mu The gravitational parameter of the celestial body. Defaults to - * Earth's gravitational parameter. @returns The classical elements - * corresponding to the state vector. @throws Error if classical elements are - * undefined for fixed frames. + * @param mu The gravitational parameter of the celestial body. Defaults to Earth's gravitational parameter. + * @returns The classical elements corresponding to the state vector. + * @throws Error if classical elements are undefined for fixed frames. */ - toClassicalElements({ mu = Earth.mu }: { mu?: number } = {}): ClassicalElements { + toClassicalElements(mu = Earth.mu): ClassicalElements { if (!this.inertial) { throw new Error('Classical elements are undefined for fixed frames.'); } diff --git a/src/coordinate/TEME.ts b/src/coordinate/TEME.ts index fa2bb77..ed5dc2b 100644 --- a/src/coordinate/TEME.ts +++ b/src/coordinate/TEME.ts @@ -1,4 +1,26 @@ -/* eslint-disable class-methods-use-this */ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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. + */ + import { Kilometers, Radians, Vector3D } from '../main'; import { Earth } from '../body/Earth'; import type { ClassicalElements } from './ClassicalElements'; @@ -6,16 +28,13 @@ import { J2000 } from './J2000'; import { StateVector } from './StateVector'; /** - * True Equator Mean Equinox (TEME) is a coordinate system commonly used in - * satellite tracking and orbit prediction. It is a reference frame that defines - * the position and orientation of an object relative to the Earth's equator and + * True Equator Mean Equinox (TEME) is a coordinate system commonly used in satellite tracking and orbit prediction. It + * is a reference frame that defines the position and orientation of an object relative to the Earth's equator and * equinox. * - * By using the True Equator Mean Equinox (TEME) coordinate system, we can - * accurately describe the position and motion of satellites relative to the - * Earth's equator and equinox. This is particularly useful for tracking and - * predicting satellite orbits in various applications, such as satellite - * communication, navigation, and remote sensing. + * By using the True Equator Mean Equinox (TEME) coordinate system, we can accurately describe the position and motion + * of satellites relative to the Earth's equator and equinox. This is particularly useful for tracking and predicting + * satellite orbits in various applications, such as satellite communication, navigation, and remote sensing. */ export class TEME extends StateVector { /** @@ -35,9 +54,7 @@ export class TEME extends StateVector { } /** - * Creates a TEME (True Equator Mean Equinox) object from classical orbital - * elements. - * + * Creates a TEME (True Equator Mean Equinox) object from classical orbital elements. * @param elements - The classical orbital elements. * @returns A new TEME object. */ @@ -48,8 +65,7 @@ export class TEME extends StateVector { } /** - * Converts the TEME (True Equator Mean Equinox) coordinates to J2000 - * coordinates. + * Converts the TEME (True Equator Mean Equinox) coordinates to J2000 coordinates. * @returns The J2000 coordinates. */ toJ2000(): J2000 { diff --git a/src/coordinate/Tle.ts b/src/coordinate/Tle.ts index 1ee86d6..578fb76 100644 --- a/src/coordinate/Tle.ts +++ b/src/coordinate/Tle.ts @@ -1,20 +1,13 @@ /** * @author Theodore Kruczek. - * @description Orbital Object ToolKit Core (ootk-core) is a collection of tools - * for working with satellites and other orbital objects. - * - * @file The Tle module contains a collection of functions for working with - * TLEs. - * - * @license MIT License - * - * @Copyright (c) 2024 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: + * @license MIT + * @copyright (c) 2022-2024 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. @@ -152,36 +145,73 @@ export class Tle { return `${this.line1}\n${this.line2}`; } + /** + * Gets the semimajor axis of the TLE. + * @returns The semimajor axis value. + */ get semimajorAxis(): number { return Tle.tleSma_(this.line2); } + /** + * Gets the eccentricity of the TLE. + * @returns The eccentricity value. + */ get eccentricity(): number { return Tle.tleEcc_(this.line2); } + /** + * Gets the inclination of the TLE. + * @returns The inclination in degrees. + */ get inclination(): number { return Tle.tleInc_(this.line2); } + /** + * Gets the inclination in degrees. + * @returns The inclination in degrees. + */ get inclinationDegrees(): number { return Tle.tleInc_(this.line2) * RAD2DEG; } + /** + * Gets the apogee of the TLE (Two-Line Elements) object. + * Apogee is the point in an orbit that is farthest from the Earth. + * It is calculated as the product of the semimajor axis and (1 + eccentricity). + * @returns The apogee value. + */ get apogee(): number { return this.semimajorAxis * (1 + this.eccentricity); } + /** + * Gets the perigee of the TLE (Two-Line Element Set). + * The perigee is the point in the orbit of a satellite or other celestial body where it is closest to the Earth. + * It is calculated as the product of the semimajor axis and the difference between 1 and the eccentricity. + * @returns The perigee value. + */ get perigee(): number { return this.semimajorAxis * (1 - this.eccentricity); } + /** + * Gets the period of the TLE in minutes. + * @returns The period of the TLE in minutes. + */ get period(): Minutes { const periodSec = (TAU * Math.sqrt(this.semimajorAxis ** 3 / earthGravityParam)) as Seconds; return (periodSec / 60) as Minutes; } + /** + * Parses the epoch string and returns the corresponding EpochUTC object. + * @param epochStr - The epoch string to parse. + * @returns The parsed EpochUTC object. + */ private static parseEpoch_(epochStr: string): EpochUTC { let year = parseInt(epochStr.substring(0, 2)); @@ -195,6 +225,13 @@ export class Tle { return EpochUTC.fromDateTimeString(`${year}-01-01T00:00:00.000Z`).roll(days * secondsPerDay); } + /** + * Propagates the TLE (Two-Line Element Set) to a specific epoch and returns the TEME (True Equator Mean Equinox) + * coordinates. + * @param epoch The epoch to propagate the TLE to. + * @returns The TEME coordinates at the specified epoch. + * @throws Error if propagation fails. + */ propagate(epoch: EpochUTC): TEME { const r = new Float64Array(3); const v = new Float64Array(3); @@ -214,6 +251,12 @@ export class Tle { ); } + /** + * Converts the state vector to position and velocity arrays. + * @param stateVector - The state vector containing position and velocity information. + * @param r - The array to store the position values. + * @param v - The array to store the velocity values. + */ private static sv2rv_(stateVector: StateVectorSgp4, r: Float64Array, v: Float64Array) { const pos = stateVector.position as EciVec3; const vel = stateVector.velocity as EciVec3; @@ -226,6 +269,10 @@ export class Tle { v[2] = vel.z; } + /** + * Returns the current state of the satellite in the TEME coordinate system. + * @returns The current state of the satellite. + */ private currentState_(): TEME { const r = new Float64Array(3); const v = new Float64Array(3); @@ -241,24 +288,48 @@ export class Tle { ); } + /** + * Gets the state of the TLE in the TEME coordinate system. + * @returns The state of the TLE in the TEME coordinate system. + */ get state(): TEME { return this.currentState_(); } + /** + * Calculates the Semi-Major Axis (SMA) from the second line of a TLE. + * @param line2 The second line of the TLE. + * @returns The Semi-Major Axis (SMA) in kilometers. + */ private static tleSma_(line2: string): number { const n = parseFloat(line2.substring(52, 63)); return earthGravityParam ** (1 / 3) / ((TAU * n) / secondsPerDay) ** (2 / 3); } + /** + * Parses the eccentricity value from the second line of a TLE. + * @param line2 The second line of the TLE. + * @returns The eccentricity value. + */ private static tleEcc_(line2: string): number { return parseFloat(`0.${line2.substring(26, 33)}`); } + /** + * Calculates the inclination angle from the second line of a TLE. + * @param line2 The second line of the TLE. + * @returns The inclination angle in radians. + */ private static tleInc_(line2: string): number { return parseFloat(line2.substring(8, 16)) * DEG2RAD; } + /** + * Creates a TLE (Two-Line Element) object from classical orbital elements. + * @param elements - The classical orbital elements. + * @returns A TLE object. + */ static fromClassicalElements(elements: ClassicalElements): Tle { const { epochYr, epochDay } = elements.epoch.toEpochYearAndDay(); const intl = '58001A '; @@ -281,16 +352,11 @@ export class Tle { } /** - * Argument of perigee. See https://en.wikipedia.org/wiki/Argument_of_perigee - * - * Units: degrees - * - * Range: 0 to 359.9999 - * - * Example: 69.9862 - * - * @param {string} tleLine2 The second line of the Tle to parse. - * @returns {Degrees} The argument of perigee in degrees. + * Argument of perigee. + * @see https://en.wikipedia.org/wiki/Argument_of_perigee + * @example 69.9862 + * @param tleLine2 The second line of the Tle to parse. + * @returns The argument of perigee in degrees (0 to 359.9999). */ static argOfPerigee(tleLine2: TleLine2): Degrees { const argPe = parseFloat(tleLine2.substring(Tle.argPerigee_.start, Tle.argPerigee_.stop)); @@ -303,15 +369,12 @@ export class Tle { } /** - * BSTAR drag term (decimal point assumed). Estimates the effects of - * atmospheric drag on the satellite's motion. - * - * Units: EarthRadii ^ -1 - * - * Example: 0.000036771 ('36771-4' in the original Tle [= 0.36771 * 10 ^ -4]) - * - * @param {string} tleLine1 The first line of the Tle to parse. - * @returns {number} The drag coefficient. + * BSTAR drag term (decimal point assumed). Estimates the effects of atmospheric drag on the satellite's motion. + * @see https://en.wikipedia.org/wiki/BSTAR + * @example 0.000036771 + * @description ('36771-4' in the original Tle or 0.36771 * 10 ^ -4) + * @param tleLine1 The first line of the Tle to parse. + * @returns The drag coefficient. */ static bstar(tleLine1: TleLine1): number { const BSTAR_PART_2 = Tle.bstar_.start + 1; @@ -344,13 +407,10 @@ export class Tle { } /** - * Tle line 1 checksum (modulo 10), for verifying the integrity of this line - * of the Tle. - * - * Range: 0 to 9 Example: 3 - * - * @param {string} tleLine The first line of the Tle to parse. - * @returns {number} The checksum value. + * Tle line 1 checksum (modulo 10), for verifying the integrity of this line of the Tle. + * @example 3 + * @param tleLine The first line of the Tle to parse. + * @returns The checksum value (0 to 9) */ static checksum(tleLine: TleLine1 | TleLine2): number { return parseInt(tleLine.substring(Tle.checksum_.start, Tle.checksum_.stop)); @@ -358,31 +418,28 @@ export class Tle { /** * Returns the satellite classification. - * * 'U' = unclassified - * * 'C' = confidential - * * 'S' = secret - * - * Example: 'U' - * * Some websites like https://KeepTrack.space and Celestrak.org will embed * information in this field about the source of the Tle. - * + * @example 'U' + * unclassified + * @example 'C' + * confidential + * @example 'S' + * secret + * @param tleLine1 The first line of the Tle to parse. + * @returns The satellite classification. */ static classification(tleLine1: TleLine1): string { return tleLine1.substring(Tle.classification_.start, Tle.classification_.stop); } /** - * Orbital eccentricity, decimal point assumed. All artificial Earth - * satellites have an eccentricity between 0 (perfect circle) and 1 (parabolic - * orbit). - * - * Range: 0 to 1 - * - * Example: 0.0006317 (`0006317` in the original Tle) - * - * @param {string} tleLine2 The second line of the Tle to parse. - * @returns {number} The eccentricity of the satellite. + * Orbital eccentricity, decimal point assumed. All artificial Earth satellites have an eccentricity between 0 + * (perfect circle) and 1 (parabolic orbit). + * @example 0.0006317 + * (`0006317` in the original Tle) + * @param tleLine2 The second line of the Tle to parse. + * @returns The eccentricity of the satellite (0 to 1) */ static eccentricity(tleLine2: TleLine2): number { const ecc = parseFloat(`0.${tleLine2.substring(Tle.eccentricity_.start, Tle.eccentricity_.stop)}`); @@ -395,33 +452,25 @@ export class Tle { } /** - * Tle element set number, incremented for each new Tle generated. 999 seems - * to mean the Tle has maxed out. - * - * Range: Technically 1 to 9999, though in practice the maximum number seems - * to be 999. - * - * Example: 999 - * @param {string} tleLine1 The first line of the Tle to parse. @returns - * {number} The element number. + * Tle element set number, incremented for each new Tle generated. + * @see https://en.wikipedia.org/wiki/Two-line_element_set + * @example 999 + * @param tleLine1 The first line of the Tle to parse. + * @returns The element number (1 to 999) */ static elsetNum(tleLine1: TleLine1): number { return parseInt(tleLine1.substring(Tle.elsetNum_.start, Tle.elsetNum_.stop)); } /** - * Private value - used by United States Space Force to reference the orbit - * model used to generate the Tle. Will always be seen as zero externally - * (e.g. by "us", unless you are "them" - in which case, hello!). - * - * Example: 0 - * - * Starting in 2024, this may contain a 4 if the Tle was generated using the - * new SGP4-XP model. Until the source code is released, there is no way to - * support that format in JavaScript or TypeScript. - * - * @param {string} tleLine1 The first line of the Tle to parse. - * @returns {0} The ephemeris type. + * Private value - used by United States Space Force to reference the orbit model used to generate the Tle. Will + * always be seen as zero externally (e.g. by "us", unless you are "them" - in which case, hello!). + * + * Starting in 2024, this may contain a 4 if the Tle was generated using the new SGP4-XP model. Until the source code + * is released, there is no way to support that format in JavaScript or TypeScript. + * @example 0 + * @param tleLine1 The first line of the Tle to parse. + * @returns The ephemeris type. */ static ephemerisType(tleLine1: TleLine1): 0 { const ephemerisType = parseInt(tleLine1.substring(Tle.ephemerisType_.start, Tle.ephemerisType_.stop)); @@ -439,13 +488,9 @@ export class Tle { /** * Fractional day of the year when the Tle was generated (Tle epoch). - * - * Range: 1 to 365.99999999 - * - * Example: 206.18396726 - * - * @param {string} tleLine1 The first line of the Tle to parse. - * @returns {number} The day of the year the Tle was generated. + * @example 206.18396726 + * @param tleLine1 The first line of the Tle to parse. + * @returns The day of the year the Tle was generated. (1 to 365.99999999) */ static epochDay(tleLine1: string): number { const epochDay = parseFloat(tleLine1.substring(Tle.epochDay_.start, Tle.epochDay_.stop)); @@ -459,13 +504,9 @@ export class Tle { /** * Year when the Tle was generated (Tle epoch), last two digits. - * - * Range: 00 to 99 - * - * Example: 17 - * - * @param {string} tleLine1 The first line of the Tle to parse. - * @returns {number} The year the Tle was generated. + * @example 17 + * @param tleLine1 The first line of the Tle to parse. + * @returns The year the Tle was generated. (0 to 99) */ static epochYear(tleLine1: TleLine1) { const epochYear = parseInt(tleLine1.substring(Tle.epochYear_.start, Tle.epochYear_.stop)); @@ -479,13 +520,9 @@ export class Tle { /** * Year when the Tle was generated (Tle epoch), four digits. - * - * Range: 1957 to 2056 - * - * Example: 2008 - * - * @param {string} tleLine1 The first line of the Tle to parse. - * @returns {number} The year the Tle was generated. + * @example 2008 + * @param tleLine1 The first line of the Tle to parse. + * @returns The year the Tle was generated. (1957 to 2056) */ static epochYearFull(tleLine1: TleLine1) { const epochYear = parseInt(tleLine1.substring(Tle.epochYear_.start, Tle.epochYear_.stop)); @@ -502,17 +539,11 @@ export class Tle { } /** - * Inclination relative to the Earth's equatorial plane in degrees. 0 to 90 - * degrees is a prograde orbit and 90 to 180 degrees is a retrograde orbit. - * - * Units: degrees - * - * Range: 0 to 180 - * - * Example: 51.6400 - * - * @param {string} tleLine2 The second line of the Tle to parse. - * @returns {Degrees} The inclination of the satellite. + * Inclination relative to the Earth's equatorial plane in degrees. 0 to 90 degrees is a prograde orbit and 90 to 180 + * degrees is a retrograde orbit. + * @example 51.6400 + * @param tleLine2 The second line of the Tle to parse. + * @returns The inclination of the satellite. (0 to 180) */ static inclination(tleLine2: TleLine2): Degrees { const inc = parseFloat(tleLine2.substring(Tle.inclination_.start, Tle.inclination_.stop)); @@ -525,10 +556,10 @@ export class Tle { } /** - * International Designator (COSPAR ID) See - * https://en.wikipedia.org/wiki/International_Designator - * @param {string} tleLine1 The first line of the Tle to parse. @returns - * {string} The International Designator. + * International Designator (COSPAR ID) + * @see https://en.wikipedia.org/wiki/International_Designator + * @param tleLine1 The first line of the Tle to parse. + * @returns The International Designator. */ static intlDes(tleLine1: TleLine1): string { return tleLine1.substring(Tle.intlDes_.start, Tle.intlDes_.stop).trim(); @@ -536,13 +567,9 @@ export class Tle { /** * International Designator (COSPAR ID): Launch number of the year. - * - * Range: 1 to 999 - * - * Example: 67 - * - * @param {string} tleLine1 The first line of the Tle to parse. - * @returns {number} The launch number of the International Designator. + * @example 67 + * @param tleLine1 The first line of the Tle to parse. + * @returns The launch number of the International Designator. (1 to 999) */ static intlDesLaunchNum(tleLine1: string): number { return parseInt(tleLine1.substring(Tle.intlDesLaunchNum_.start, Tle.intlDesLaunchNum_.stop)); @@ -550,13 +577,9 @@ export class Tle { /** * International Designator (COSPAR ID): Piece of the launch. - * - * Range: A to ZZZ - * - * Example: 'A' - * - * @param {string} tleLine1 The first line of the Tle to parse. - * @returns {string} The launch piece of the International Designator. + * @example 'A' + * @param tleLine1 The first line of the Tle to parse. + * @returns The launch piece of the International Designator. (A to ZZZ) */ static intlDesLaunchPiece(tleLine1: TleLine1): string { return tleLine1.substring(Tle.intlDesLaunchPiece_.start, Tle.intlDesLaunchPiece_.stop).trim(); @@ -564,13 +587,9 @@ export class Tle { /** * International Designator (COSPAR ID): Last 2 digits of launch year. - * - * Range: 00 to 99 - * - * Example: 98 - * - * @param {string} tleLine1 The first line of the Tle to parse. - * @returns {number} The year of the International Designator. + * @example 98 + * @param tleLine1 The first line of the Tle to parse. + * @returns The year of the International Designator. (0 to 99) */ static intlDesYear(tleLine1: TleLine1): number { return parseInt(tleLine1.substring(Tle.intlDesYear_.start, Tle.intlDesYear_.stop)); @@ -578,8 +597,9 @@ export class Tle { /** * This should always return a 1 or a 2. - * @param {string} tleLine The first line of the Tle to parse. @returns - * {number} The line number of the Tle. + * @example 1 + * @param tleLine The first line of the Tle to parse. + * @returns The line number of the Tle. (1 or 2) */ static lineNumber(tleLine: TleLine1 | TleLine2): 1 | 2 { const lineNum = parseInt(tleLine.substring(Tle.lineNumber_.start, Tle.lineNumber_.stop)); @@ -592,17 +612,11 @@ export class Tle { } /** - * Mean anomaly. Indicates where the satellite was located within its orbit at - * the time of the Tle epoch. See https://en.wikipedia.org/wiki/Mean_Anomaly - * - * Units: degrees - * - * Range: 0 to 359.9999 - * - * Example: 25.2906 - * - * @param {string} tleLine2 The second line of the Tle to parse. - * @returns {Degrees} The mean anomaly of the satellite. + * Mean anomaly. Indicates where the satellite was located within its orbit at the time of the Tle epoch. + * @see https://en.wikipedia.org/wiki/Mean_Anomaly + * @example 25.2906 + * @param tleLine2 The second line of the Tle to parse. + * @returns The mean anomaly of the satellite. (0 to 359.9999) */ static meanAnomaly(tleLine2: TleLine2): Degrees { const meanA = parseFloat(tleLine2.substring(Tle.meanAnom_.start, Tle.meanAnom_.stop)); @@ -615,16 +629,12 @@ export class Tle { } /** - * First Time Derivative of the Mean Motion divided by two. Defines how mean - * motion changes over time, so Tle propagators can still be used to make - * reasonable guesses when times are distant from the original Tle epoch. - * - * Units: Orbits / day ^ 2 - * - * Example: 0.00001961 - * - * @param {string} tleLine1 The first line of the Tle to parse. - * @returns {number} The first derivative of the mean motion. + * First Time Derivative of the Mean Motion divided by two. Defines how mean motion changes over time, so Tle + * propagators can still be used to make reasonable guesses when times are distant from the original Tle epoch. This + * is recorded in units of orbits per day per day. + * @example 0.00001961 + * @param tleLine1 The first line of the Tle to parse. + * @returns The first derivative of the mean motion. */ static meanMoDev1(tleLine1: TleLine1): number { const meanMoDev1 = parseFloat(tleLine1.substring(Tle.meanMoDev1_.start, Tle.meanMoDev1_.stop)); @@ -637,18 +647,14 @@ export class Tle { } /** - * Second Time Derivative of Mean Motion divided by six (decimal point - * assumed). Measures rate of change in the Mean Motion Dot so software can - * make reasonable guesses when times are distant from the original Tle epoch. - * - * Usually zero, unless the satellite is manuevering or in a decaying orbit. - * - * Units: Orbits / day ^ 3. - * - * Example: 0 ('00000-0' in the original Tle [= 0.00000 * 10 ^ 0]) - * - * @param {string} tleLine1 The first line of the Tle to parse. - * @returns {number} The second derivative of the mean motion. + * Second Time Derivative of Mean Motion divided by six (decimal point assumed). Measures rate of change in the Mean + * Motion Dot so software can make reasonable guesses when times are distant from the original Tle epoch. Usually + * zero, unless the satellite is manuevering or in a decaying orbit. This is recorded in units of orbits per day per + * day per day. + * @example 0 + * '00000-0' in the original Tle or 0.00000 * 10 ^ 0 + * @param tleLine1 The first line of the Tle to parse. + * @returns The second derivative of the mean motion. */ static meanMoDev2(tleLine1: string): number { const meanMoDev2 = parseFloat(tleLine1.substring(Tle.meanMoDev2_.start, Tle.meanMoDev2_.stop)); @@ -662,12 +668,11 @@ export class Tle { } /** - * Revolutions around the Earth per day (mean motion). See - * https://en.wikipedia.org/wiki/Mean_Motion - * - * Range: 0 to 17 (theoretically) Example: 15.54225995 - * @param {string} tleLine2 The second line of the Tle to parse. @returns - * {number} The mean motion of the satellite. + * Revolutions around the Earth per day (mean motion). + * @see https://en.wikipedia.org/wiki/Mean_Motion + * @example 15.54225995 + * @param tleLine2 The second line of the Tle to parse. + * @returns The mean motion of the satellite. (0 to 17) */ static meanMotion(tleLine2: TleLine2): number { const meanMo = parseFloat(tleLine2.substring(Tle.meanMo_.start, Tle.meanMo_.stop)); @@ -681,7 +686,7 @@ export class Tle { /** * Calculates the period of a satellite orbit based on the given Tle line 2. - * + * @example 92.53035747 * @param tleLine2 The Tle line 2. * @returns The period of the satellite orbit in minutes. */ @@ -692,18 +697,11 @@ export class Tle { } /** - * Right ascension of the ascending node in degrees. Essentially, this is the - * angle of the satellite as it crosses northward (ascending) across the - * Earth's equator (equatorial plane). - * - * Units: degrees - * - * Range: 0 to 359.9999 - * - * Example: 208.9163 - * - * @param {string} tleLine2 The second line of the Tle to parse. - * @returns {Degrees} The right ascension of the satellite. + * Right ascension of the ascending node in degrees. Essentially, this is the angle of the satellite as it crosses + * northward (ascending) across the Earth's equator (equatorial plane). + * @example 208.9163 + * @param tleLine2 The second line of the Tle to parse. + * @returns The right ascension of the satellite. (0 to 359.9999) */ static rightAscension(tleLine2: TleLine2): Degrees { const rightAscension = parseFloat(tleLine2.substring(Tle.rightAscension_.start, Tle.rightAscension_.stop)); @@ -716,49 +714,35 @@ export class Tle { } /** - * See https://en.wikipedia.org/wiki/Satellite_Catalog_Number - * - * Range: 0 to 99999 or 26999. - * - * NOTE: To support Alpha-5, the first digit can be a letter. This will NOT be - * converted to a number. Use getSatNum() for that. - * - * Example: 25544 or B1234 (e.g. Sputnik's rocket body was number 00001) - * - * @param {string} tleLine The first line of the Tle to parse. - * @returns {string} NORAD catalog number. + * NORAD catalog number. To support Alpha-5, the first digit can be a letter. This will NOT be converted to a number. + * Use satNum() for that. + * @see https://en.wikipedia.org/wiki/Satellite_Catalog_Number + * @example 25544 + * @example B1234 + * @param tleLine The first line of the Tle to parse. + * @returns NORAD catalog number. */ static rawSatNum(tleLine: TleLine1 | TleLine2): string { return tleLine.substring(Tle.satNum_.start, Tle.satNum_.stop); } /** - * Total satellite revolutions when this Tle was generated. This number rolls - * over (e.g. 99999 -> 0). - * - * Range: 0 to 99999 - * - * Example: 6766 - * - * @param {string} tleLine2 The second line of the Tle to parse. - * @returns {number} The revolutions around the Earth per day (mean motion). + * Total satellite revolutions when this Tle was generated. This number rolls over (e.g. 99999 -> 0). + * @example 6766 + * @param tleLine2 The second line of the Tle to parse. + * @returns The revolutions around the Earth per day (mean motion). (0 to 99999) */ static revNum(tleLine2: TleLine2): number { return parseInt(tleLine2.substring(Tle.revNum_.start, Tle.revNum_.stop)); } /** - * See https://en.wikipedia.org/wiki/Satellite_Catalog_Number - * - * Range: 0 to 99999 or 26999. - * - * NOTE: To support Alpha-5, the first digit can be a letter. This will be - * converted to a number in order to expand the range to 26999. - * - * Example: 25544 or B1234 (e.g. Sputnik's rocket body was number 00001) - * - * @param {string} tleLine The first line of the Tle to parse. - * @returns {number} NORAD catalog number. + * NORAD catalog number converted to a number. + * @see https://en.wikipedia.org/wiki/Satellite_Catalog_Number + * @example 25544 + * @example 111234 + * @param tleLine The first line of the Tle to parse. + * @returns NORAD catalog number. (0 to 339999) */ static satNum(tleLine: TleLine1 | TleLine2): number { const satNumStr = tleLine.substring(Tle.satNum_.start, Tle.satNum_.stop); @@ -769,8 +753,8 @@ export class Tle { /** * Parse the first line of the Tle. - * @param {TleLine1} tleLine1 The first line of the Tle to parse. @returns - * {Line1Data} Returns the data from the first line of the Tle. + * @param tleLine1 The first line of the Tle to parse. + * @returns Returns the data from the first line of the Tle. */ static parseLine1(tleLine1: TleLine1): Line1Data { const lineNumber1 = Tle.lineNumber(tleLine1); @@ -814,8 +798,8 @@ export class Tle { /** * Parse the second line of the Tle. - * @param {TleLine2} tleLine2 The second line of the Tle to parse. @returns - * {Line2Data} Returns the data from the second line of the Tle. + * @param tleLine2 The second line of the Tle to parse. + * @returns Returns the data from the second line of the Tle. */ static parseLine2(tleLine2: TleLine2): Line2Data { const lineNumber2 = Tle.lineNumber(tleLine2); @@ -851,8 +835,9 @@ export class Tle { * Parses the Tle into orbital data. * * If you want all of the data then use parseTleFull instead. - * @param {TleLine1} tleLine1 Tle line 1 @param {TleLine2} tleLine2 Tle line 2 - * @returns {TleData} Returns most commonly used orbital data from Tle + * @param tleLine1 Tle line 1 + * @param tleLine2 Tle line 2 + * @returns Returns most commonly used orbital data from Tle */ static parse(tleLine1: TleLine1, tleLine2: TleLine2): TleData { const line1 = Tle.parseLine1(tleLine1); @@ -896,9 +881,9 @@ export class Tle { * Parses all of the data contained in the Tle. * * If you only want the most commonly used data then use parseTle instead. - * @param {TleLine1} tleLine1 The first line of the Tle to parse. @param - * {TleLine2} tleLine2 The second line of the Tle to parse. @returns - * {TleDataFull} Returns all of the data from the Tle. + * @param tleLine1 The first line of the Tle to parse. + * @param tleLine2 The second line of the Tle to parse. + * @returns Returns all of the data from the Tle. */ static parseAll(tleLine1: TleLine1, tleLine2: TleLine2): TleDataFull { const line1 = Tle.parseLine1(tleLine1); @@ -925,6 +910,8 @@ export class Tle { /** * Converts a 6 digit SCC number to a 5 digit SCC alpha 5 number + * @param sccNum The 6 digit SCC number + * @returns The 5 digit SCC alpha 5 number */ static convert6DigitToA5(sccNum: string): string { // Only applies to 6 digit numbers @@ -955,6 +942,11 @@ export class Tle { return `${String.fromCharCode(first + 55)}${rest}`; } + /** + * Converts a 5-digit SCC number to a 6-digit SCC number. + * @param sccNum - The 5-digit SCC number to convert. + * @returns The converted 6-digit SCC number. + */ static convertA5to6Digit(sccNum: string): string { const values = sccNum.toUpperCase().split(''); diff --git a/src/coordinate/tle-format-data.ts b/src/coordinate/tle-format-data.ts index bc1c2d7..9649bb1 100644 --- a/src/coordinate/tle-format-data.ts +++ b/src/coordinate/tle-format-data.ts @@ -1,3 +1,26 @@ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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. + */ + /** * Represents the format data of a TLE (Two-Line Element) set. This is used to * make it easier to remember the starting and ending positions of the columns diff --git a/src/interfaces/SensorParams.ts b/src/interfaces/SensorParams.ts index 9c993b5..d0ff7df 100644 --- a/src/interfaces/SensorParams.ts +++ b/src/interfaces/SensorParams.ts @@ -1,21 +1,38 @@ import { Degrees, Kilometers, SpaceObjectType } from '../types/types'; export interface SensorParams { + /** Altitude in Kilometers */ alt: Kilometers; + /** Latitude in Degrees */ lat: Degrees; + /** Longitude in Degrees */ lon: Degrees; + /** Maximum Azimuth in Degrees */ maxAz: Degrees; + /** Secondary Maximum Azimuth in Degrees */ maxAz2?: Degrees; + /** Maximum Elevation in Degrees */ maxEl: Degrees; + /** Secondary Maximum Elevation in Degrees */ maxEl2?: Degrees; + /** Maximum Range in Kilometers */ maxRng: Kilometers; + /** Secondary Maximum Range in Kilometers */ maxRng2?: Kilometers; + /** Minimum Azimuth in Degrees */ minAz: Degrees; + /** Secondary Minimum Azimuth in Degrees */ minAz2?: Degrees; + /** Minimum Elevation in Degrees */ minEl: Degrees; + /** Secondary Minimum Elevation in Degrees */ minEl2?: Degrees; + /** Minimum Range in Kilometers */ minRng: Kilometers; + /** Secondary Minimum Range in Kilometers */ minRng2?: Kilometers; + /** Name as a string */ name?: string; + /** Type of sensor */ type?: SpaceObjectType; } diff --git a/src/interfaces/TimeVariables.ts b/src/interfaces/TimeVariables.ts new file mode 100644 index 0000000..8ae0cce --- /dev/null +++ b/src/interfaces/TimeVariables.ts @@ -0,0 +1,7 @@ +import { GreenwichMeanSiderealTime } from '../types/types'; + +export interface TimeVariables { + gmst: GreenwichMeanSiderealTime; + m: number | null; + j: number; +} diff --git a/src/objects/BaseObject.ts b/src/objects/BaseObject.ts index 4cda5b4..4cf9c45 100644 --- a/src/objects/BaseObject.ts +++ b/src/objects/BaseObject.ts @@ -1,29 +1,24 @@ /** * @author Theodore Kruczek. - * @description Orbital Object ToolKit Core (ootk-core) is a collection of tools for working - * with satellites and other orbital objects. + * @license MIT + * @copyright (c) 2022-2024 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: * - * @file The BaseObject class is used for creating core properties and methods applicable - * to ground and space based objects. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * @license MIT License - * - * @Copyright (c) 2024 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. + * 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. */ import { BaseObjectParams } from '../interfaces/BaseObjectParams'; @@ -60,7 +55,7 @@ export class BaseObject { /** * Checks if the object is a satellite. - * @returns {boolean} True if the object is a satellite, false otherwise. + * @returns True if the object is a satellite, false otherwise. */ isSatellite(): boolean { return false; @@ -68,7 +63,7 @@ export class BaseObject { /** * Checks if the object is a land object. - * @returns {boolean} True if the object is a land object, false otherwise. + * @returns True if the object is a land object, false otherwise. */ isLandObject(): boolean { switch (this.type) { @@ -90,7 +85,7 @@ export class BaseObject { /** * Returns whether the object is a sensor. - * @returns {boolean} True if the object is a sensor, false otherwise. + * @returns True if the object is a sensor, false otherwise. */ isSensor(): boolean { return false; @@ -98,7 +93,7 @@ export class BaseObject { /** * Checks if the object is a marker. - * @returns {boolean} True if the object is a marker, false otherwise. + * @returns True if the object is a marker, false otherwise. */ isMarker(): boolean { return false; @@ -106,7 +101,7 @@ export class BaseObject { /** * Returns whether the object's position is static. - * @returns {boolean} True if the object is static, false otherwise. + * @returns True if the object is static, false otherwise. */ isStatic(): boolean { return true; @@ -169,4 +164,20 @@ export class BaseObject { return typeToStringMap[this.type] ?? 'Unknown'; } + + /** + * Validates a parameter value against a minimum and maximum value. + * @param value - The value to be validated. + * @param minValue - The minimum allowed value. + * @param maxValue - The maximum allowed value. + * @param errorMessage - The error message to be thrown if the value is invalid. + */ + validateParameter(value: T, minValue: T, maxValue: T, errorMessage: string): void { + if (typeof minValue !== 'undefined' && minValue !== null && (value as number) < (minValue as number)) { + throw new Error(errorMessage); + } + if (typeof maxValue !== 'undefined' && maxValue !== null && (value as number) > (maxValue as number)) { + throw new Error(errorMessage); + } + } } diff --git a/src/objects/GroundObject.ts b/src/objects/GroundObject.ts index 87b768c..78c188b 100644 --- a/src/objects/GroundObject.ts +++ b/src/objects/GroundObject.ts @@ -1,3 +1,26 @@ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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. + */ + import { GroundPositionParams, Degrees, @@ -26,18 +49,17 @@ export class GroundObject extends BaseObject { constructor(info: GroundPositionParams) { super(info); - this.validateInputData_(info); + this.validateGroundObjectInputData_(info); this.lat = info.lat; this.lon = info.lon; this.alt = info.alt; } /** - * Calculates the relative azimuth, elevation, and range between this - * GroundObject and a Satellite. - * @param satellite The Satellite object. @param date The date for which to - * calculate the RAE values. Defaults to the current date. @returns The - * relative azimuth, elevation, and range values in kilometers and degrees. + * Calculates the relative azimuth, elevation, and range between this GroundObject and a Satellite. + * @param satellite The Satellite object. + * @param date The date for which to calculate the RAE values. Defaults to the current date. + * @returns The relative azimuth, elevation, and range values in kilometers and degrees. */ rae(satellite: Satellite, date: Date = new Date()): RaeVec3 { return satellite.rae(this, date); @@ -45,22 +67,17 @@ export class GroundObject extends BaseObject { /** * Calculates ECF position at a given time. - * - * @optimized version of this.toGeodetic().toITRF().position; + * @variation optimized version of this.toGeodetic().toITRF().position; + * @returns The ECF position vector of the ground object. */ ecf(): EcfVec3 { return llaRad2ecf(this.toGeodetic()); } /** - * Calculates the Earth-Centered Inertial (ECI) position vector of the ground - * object at a given date. - * - * @optimzed version of this.toGeodetic().toITRF().toJ2000().position; - * - * @param date The date for which to calculate the ECI position vector. - * Defaults to the current date. - * + * Calculates the Earth-Centered Inertial (ECI) position vector of the ground object at a given date. + * @variation optimzed version of this.toGeodetic().toITRF().toJ2000().position; + * @param date The date for which to calculate the ECI position vector. Defaults to the current date. * @returns The ECI position vector of the ground object. */ eci(date: Date = new Date()): EciVec3 { @@ -70,12 +87,9 @@ export class GroundObject extends BaseObject { } /** - * Converts the latitude, longitude, and altitude of the GroundObject to - * radians and kilometers. - * - * @optimized version of this.toGeodetic() without class instantiation for - * better performance and serialization. - * + * Converts the latitude, longitude, and altitude of the GroundObject to radians and kilometers. + * @variation optimized version of this.toGeodetic() without class instantiation for better performance and + * serialization. * @returns An object containing the latitude, longitude, and altitude in * radians and kilometers. */ @@ -89,7 +103,6 @@ export class GroundObject extends BaseObject { /** * Creates a GroundObject object from a Geodetic position. - * * @param geodetic The geodetic coordinates. * @returns A new GroundObject object. */ @@ -114,28 +127,9 @@ export class GroundObject extends BaseObject { * @param info - The GroundPositionParams object containing the latitude, * longitude, and altitude. @returns void */ - private validateInputData_(info: GroundPositionParams) { - this.validateParameter_(info.lat, -90, 90, 'Invalid latitude - must be between -90 and 90'); - this.validateParameter_(info.lon, -180, 180, 'Invalid longitude - must be between -180 and 180'); - this.validateParameter_(info.alt, 0, null, 'Invalid altitude - must be greater than 0'); - } - - /** - * Validates a parameter value against a minimum and maximum value. - * @template T - The type of the parameter value. @param value - The parameter - * value to validate. @param minValue - The minimum allowed value. If not - * provided, no minimum value check will be performed. @param maxValue - The - * maximum allowed value. If not provided, no maximum value check will be - * performed. @param errorMessage - The error message to throw if the value is - * outside the allowed range. @throws {Error} - Throws an error with the - * specified error message if the value is outside the allowed range. - */ - private validateParameter_(value: T, minValue: T, maxValue: T, errorMessage: string): void { - if (minValue && value < minValue) { - throw new Error(errorMessage); - } - if (maxValue && value > maxValue) { - throw new Error(errorMessage); - } + private validateGroundObjectInputData_(info: GroundPositionParams) { + this.validateParameter(info.lat, -90, 90, 'Invalid latitude - must be between -90 and 90'); + this.validateParameter(info.lon, -180, 180, 'Invalid longitude - must be between -180 and 180'); + this.validateParameter(info.alt, 0, null, 'Invalid altitude - must be greater than 0'); } } diff --git a/src/objects/Satellite.ts b/src/objects/Satellite.ts index b138989..251cbb4 100644 --- a/src/objects/Satellite.ts +++ b/src/objects/Satellite.ts @@ -1,19 +1,13 @@ /** * @author Theodore Kruczek. - * @description Orbital Object ToolKit Core (ootk-core) is a collection of tools - * for working with satellites and other orbital objects. - * - * @file The Satellite class provides functions for calculating satellites - * positions relative to earth based sensors and other orbital objects. - * - * @license MIT License @Copyright (c) 2020-2024 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: + * @license MIT + * @copyright (c) 2022-2024 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. @@ -44,7 +38,6 @@ import { Degrees, EcfVec3, EciVec3, - GreenwichMeanSiderealTime, Kilometers, LlaVec3, Minutes, @@ -59,6 +52,7 @@ import { DEG2RAD, MILLISECONDS_TO_DAYS, MINUTES_PER_DAY, RAD2DEG } from '../util import { dopplerFactor } from './../utils/functions'; import { BaseObject } from './BaseObject'; import { GroundObject } from './GroundObject'; +import { TimeVariables } from '../interfaces/TimeVariables'; /** * Represents a satellite object with orbital information and methods for @@ -77,33 +71,22 @@ export class Satellite extends BaseObject { meanMoDev1: number; meanMoDev2: number; meanMotion: number; - // eslint-disable-next-line @typescript-eslint/no-explicit-any options: OptionsParams; perigee: Kilometers; period: Minutes; rightAscension: Degrees; satrec: SatelliteRecord; - /** - * The satellite catalog number as listed in the TLE. - */ + /** The satellite catalog number as listed in the TLE. */ sccNum: string; - /** - * The 5 digit alpha-numeric satellite catalog number. - */ + /** The 5 digit alpha-numeric satellite catalog number. */ sccNum5: string; - /** - * The 6 digit numeric satellite catalog number. - */ + /** The 6 digit numeric satellite catalog number. */ sccNum6: string; tle1: TleLine1; tle2: TleLine2; - /** - * The semi-major axis of the satellite's orbit. - */ + /** The semi-major axis of the satellite's orbit. */ semiMajorAxis: Kilometers; - /** - * The semi-minor axis of the satellite's orbit. - */ + /** The semi-minor axis of the satellite's orbit. */ semiMinorAxis: Kilometers; constructor(info: SatelliteParams, options?: OptionsParams) { @@ -143,19 +126,26 @@ export class Satellite extends BaseObject { }; } + /** + * Checks if the object is a satellite. + * @returns True if the object is a satellite, false otherwise. + */ isSatellite(): boolean { return true; } + /** + * Returns whether the satellite is static or not. + * @returns True if the satellite is static, false otherwise. + */ isStatic(): boolean { return false; } /** - * Checks if the given SatelliteRecord object is valid by checking if its - * properties are all numbers. - * @param satrec - The SatelliteRecord object to check. @returns True if the - * SatelliteRecord object is valid, false otherwise. + * Checks if the given SatelliteRecord object is valid by checking if its properties are all numbers. + * @param satrec - The SatelliteRecord object to check. + * @returns True if the SatelliteRecord object is valid, false otherwise. */ static isValidSatrec(satrec: SatelliteRecord): boolean { if ( @@ -174,21 +164,24 @@ export class Satellite extends BaseObject { } /** - * Calculates the azimuth angle of the satellite relative to the given sensor - * at the specified date. If no date is provided, the current time of the - * satellite is used. - * - * @optimized + * Calculates the azimuth angle of the satellite relative to the given sensor at the specified date. If no date is + * provided, the current time of the satellite is used. + * @variation optimized + * @param observer - The observer's position on the ground. + * @param date - The date at which to calculate the azimuth angle. Optional, defaults to the current date. + * @returns The azimuth angle of the satellite relative to the given sensor at the specified date. */ az(observer: GroundObject, date: Date = new Date()): Degrees { return (this.rae(observer, date).az * RAD2DEG) as Degrees; } /** - * Calculates the RAE (Range, Azimuth, Elevation) values for a given sensor - * and date. If no date is provided, the current time is used. - * - * @expanded + * Calculates the RAE (Range, Azimuth, Elevation) values for a given sensor and date. If no date is provided, the + * current time is used. + * @variation expanded + * @param observer - The observer's position on the ground. + * @param date - The date at which to calculate the RAE values. Optional, defaults to the current date. + * @returns The RAE values for the given sensor and date. */ toRae(observer: GroundObject, date: Date = new Date()): RAE { const rae = this.rae(observer, date); @@ -211,8 +204,9 @@ export class Satellite extends BaseObject { /** * Calculates ECF position at a given time. - * - * @optimized + * @variation optimized + * @param date - The date at which to calculate the ECF position. Optional, defaults to the current date. + * @returns The ECF position at the specified date. */ ecf(date: Date = new Date()): EcfVec3 { const { gmst } = Satellite.calculateTimeVariables(date); @@ -222,8 +216,9 @@ export class Satellite extends BaseObject { /** * Calculates ECI position at a given time. - * - * @optimized + * @variation optimized + * @param date - The date at which to calculate the ECI position. Optional, defaults to the current date. + * @returns The ECI position at the specified date. */ eci(date: Date = new Date()): PosVel { const { m } = Satellite.calculateTimeVariables(date, this.satrec); @@ -241,11 +236,11 @@ export class Satellite extends BaseObject { } /** - * Calculates the J2000 coordinates for a given date. If no date is provided, - * the current time is used. - * @param date - The date for which to calculate the J2000 coordinates. - * @returns The J2000 coordinates for the specified date. @throws Error if - * propagation fails. + * Calculates the J2000 coordinates for a given date. If no date is provided, the current time is used. + * @variation expanded + * @param date - The date for which to calculate the J2000 coordinates, defaults to the current date. + * @returns The J2000 coordinates for the specified date. + * @throws Error if propagation fails. */ toJ2000(date: Date = new Date()): J2000 { const { m } = Satellite.calculateTimeVariables(date, this.satrec); @@ -270,10 +265,11 @@ export class Satellite extends BaseObject { } /** - * Returns the elevation angle of the satellite as seen by the given sensor at - * the specified time. - * - * @optimized + * Returns the elevation angle of the satellite as seen by the given sensor at the specified time. + * @variation optimized + * @param observer - The observer's position on the ground. + * @param date - The date at which to calculate the elevation angle. Optional, defaults to the current date. + * @returns The elevation angle of the satellite as seen by the given sensor at the specified time. */ el(observer: GroundObject, date: Date = new Date()): Degrees { return (this.rae(observer, date).el * RAD2DEG) as Degrees; @@ -281,6 +277,9 @@ export class Satellite extends BaseObject { /** * Calculates LLA position at a given time. + * @variation optimized + * @param date - The date at which to calculate the LLA position. Optional, defaults to the current date. + * @returns The LLA position at the specified date. */ lla(date: Date = new Date()): LlaVec3 { const { gmst } = Satellite.calculateTimeVariables(date, this.satrec); @@ -290,31 +289,62 @@ export class Satellite extends BaseObject { return lla; } + /** + * Converts the satellite's position to geodetic coordinates. + * @variation expanded + * @param date The date for which to calculate the geodetic coordinates. Defaults to the current date. + * @returns The geodetic coordinates of the satellite. + */ toGeodetic(date: Date = new Date()): Geodetic { return this.toJ2000(date).toITRF().toGeodetic(); } + /** + * Converts the satellite's position to the International Terrestrial Reference Frame (ITRF) at the specified date. + * If no date is provided, the current date is used. + * @variation expanded + * @param date The date for which to convert the position. Defaults to the current date. + * @returns The satellite's position in the ITRF at the specified date. + */ toITRF(date: Date = new Date()): ITRF { return this.toJ2000(date).toITRF(); } + /** + * Converts the current satellite's position to the Reference-Inertial-Celestial (RIC) frame + * relative to the specified reference satellite at the given date. + * @variation expanded + * @param reference The reference satellite. + * @param date The date for which to calculate the RIC frame. Defaults to the current date. + * @returns The RIC frame representing the current satellite's position relative to the reference satellite. + */ toRIC(reference: Satellite, date: Date = new Date()): RIC { return RIC.fromJ2000(this.toJ2000(date), reference.toJ2000(date)); } + /** + * Converts the satellite object to a TLE (Two-Line Element) object. + * @returns The TLE object representing the satellite. + */ toTle(): Tle { return new Tle(this.tle1, this.tle2); } + /** + * Converts the satellite's position to classical orbital elements. + * @param date The date for which to calculate the classical elements. Defaults to the current date. + * @returns The classical orbital elements of the satellite. + */ toClassicalElements(date: Date = new Date()): ClassicalElements { return this.toJ2000(date).toClassicalElements(); } /** - * Calculates the RAE (Range, Azimuth, Elevation) vector for a given sensor - * and time. - * - * @optimized + * Calculates the RAE (Range, Azimuth, Elevation) vector for a given sensor and time. + * @variation optimized + * @param observer - The observer's position on the ground. + * @param date - The date at which to calculate the RAE vector. Optional, defaults to the current date. + * @returns The RAE vector for the given sensor and time. */ rae(observer: GroundObject, date: Date = new Date()): RaeVec3 { const { gmst } = Satellite.calculateTimeVariables(date, this.satrec); @@ -325,21 +355,21 @@ export class Satellite extends BaseObject { } /** - * Returns the range of the satellite from the given sensor at the specified - * time. - * - * @optimized + * Returns the range of the satellite from the given sensor at the specified time. + * @variation optimized + * @param observer - The observer's position on the ground. + * @param date - The date at which to calculate the range. Optional, defaults to the current date. + * @returns The range of the satellite from the given sensor at the specified time. */ range(observer: GroundObject, date: Date = new Date()): Kilometers { return this.rae(observer, date).rng; } /** - * Applies the Doppler effect to the given frequency based on the observer's - * position and the date. - * @param freq - The frequency to apply the Doppler effect to. @param observer - * - The observer's position on the ground. @param date - The date at which to - * calculate the Doppler effect. Optional, defaults to the current date. + * Applies the Doppler effect to the given frequency based on the observer's position and the date. + * @param freq - The frequency to apply the Doppler effect to. + * @param observer - The observer's position on the ground. + * @param date - The date at which to calculate the Doppler effect. Optional, defaults to the current date. * @returns The frequency after applying the Doppler effect. */ applyDoppler(freq: number, observer: GroundObject, date?: Date): number { @@ -350,11 +380,9 @@ export class Satellite extends BaseObject { /** * Calculates the Doppler factor for the satellite. - * * @param observer The observer's ground position. - * @param date The optional date for which to calculate the Doppler factor. If - * not provided, the current date is used. @returns The calculated Doppler - * factor. + * @param date The optional date for which to calculate the Doppler factor. If not provided, the current date is used. + * @returns The calculated Doppler factor. */ dopplerFactor(observer: GroundObject, date?: Date): number { const position = this.eci(date); @@ -364,26 +392,20 @@ export class Satellite extends BaseObject { /** * Calculates the time variables for a given date relative to the TLE epoch. - * @param {Date} date Date to calculate @param {SatelliteRecord} satrec - * Satellite orbital information @returns {{m: number, gmst: - * GreenwichMeanSiderealTime, j: number}} Time variables + * @param date Date to calculate + * @param satrec Satellite orbital information + * @returns Time variables */ - private static calculateTimeVariables( - date: Date, - satrec?: SatelliteRecord, - ): { gmst: GreenwichMeanSiderealTime; m: number | null; j: number } { - const j = - jday( - date.getUTCFullYear(), - date.getUTCMonth() + 1, - date.getUTCDate(), - date.getUTCHours(), - date.getUTCMinutes(), - date.getUTCSeconds(), - ) + - date.getUTCMilliseconds() * MILLISECONDS_TO_DAYS; + private static calculateTimeVariables(date: Date, satrec?: SatelliteRecord): TimeVariables { + const j = jday( + date.getUTCFullYear(), + date.getUTCMonth() + 1, + date.getUTCDate(), + date.getUTCHours(), + date.getUTCMinutes(), + date.getUTCSeconds(), + ) + date.getUTCMilliseconds() * MILLISECONDS_TO_DAYS; const gmst = Sgp4.gstime(j); - const m = satrec ? (j - satrec.jdsatepoch) * MINUTES_PER_DAY : null; return { gmst, m, j }; diff --git a/src/objects/Sensor.ts b/src/objects/Sensor.ts index 76af261..22e1aca 100644 --- a/src/objects/Sensor.ts +++ b/src/objects/Sensor.ts @@ -1,3 +1,26 @@ +/** + * @author Theodore Kruczek. + * @license MIT + * @copyright (c) 2022-2024 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. + */ + import { PassType } from '../enums/PassType'; import { SensorParams } from '../interfaces/SensorParams'; import { Degrees, Kilometers, Lookangle, RaeVec3, SpaceObjectType } from '../types/types'; @@ -18,20 +41,6 @@ export class Sensor extends GroundObject { maxAz2?: Degrees; maxEl2?: Degrees; - /** - * * name: Name as a string - OPTIONAL - * * type: SpaceObjectType - OPTIONAL - * * lat: Latitude in Radians - * * lon: Longitude in Radians - * * alt: Altitude in Kilometers - * * minAz: Minimum Azimuth in Degrees - * * maxAz: Maximum Azimuth in Degrees - * * minEl: Minimum Elevation in Degrees - * * maxEl: Maximum Elevation in Degrees - * * minRng: Minimum Range in Kilometers - * * maxRng: Maximum Range in Kilometers - * @param {SensorParams} info SensorParams object containing the object's information - */ constructor(info: SensorParams) { // If there is a sensor type verify it is valid if (info.type) { @@ -50,7 +59,7 @@ export class Sensor extends GroundObject { super(info); - this.validateInputData(info); + this.validateSensorInputData_(info); this.minRng = info.minRng; this.minAz = info.minAz; @@ -66,6 +75,10 @@ export class Sensor extends GroundObject { this.maxEl2 = info.maxEl2; } + /** + * Checks if the object is a sensor. + * @returns True if the object is a sensor, false otherwise. + */ isSensor(): boolean { return true; } @@ -117,6 +130,12 @@ export class Sensor extends GroundObject { return msnPlanPasses; } + /** + * Checks if the given RAE vector is within the field of view of the sensor. + * TODO: #8 This doesn't account for secondary sensor FOV + * @param rae - The RAE vector to check. + * @returns True if the RAE vector is within the field of view, false otherwise. + */ isRaeInFov(rae: RaeVec3): boolean { if (rae.el < this.minEl || rae.el > this.maxEl) { return false; @@ -139,18 +158,38 @@ export class Sensor extends GroundObject { return true; } + /** + * Checks if a satellite is in the field of view (FOV) of the sensor. + * @param sat - The satellite to check. + * @param date - The date to use for the calculation. Defaults to the current date. + * @returns A boolean indicating whether the satellite is in the FOV. + */ isSatInFov(sat: Satellite, date: Date = new Date()): boolean { return this.isRaeInFov(this.rae(sat, date)); } + /** + * Checks if the sensor is in deep space. + * @returns True if the sensor is in deep space, false otherwise. + */ isDeepSpace(): boolean { return this.maxRng > 6000; } + /** + * Checks if the sensor is near Earth. + * @returns True if the sensor is near Earth, false otherwise. + */ isNearEarth(): boolean { return this.maxRng <= 6000; } + /** + * Returns the pass type based on the current and previous visibility states. + * @param isInView - Indicates if the object is currently in view. + * @param isInViewLast - Indicates if the object was in view in the previous state. + * @returns The pass type. + */ private static getPassType_(isInView: boolean, isInViewLast: boolean) { let type = PassType.OUT_OF_VIEW; @@ -165,7 +204,11 @@ export class Sensor extends GroundObject { return type; } - private validateFov(info: SensorParams) { + /** + * Validates the field of view (FOV) parameters of the sensor. + * @param info - The sensor parameters. + */ + private validateFov_(info: SensorParams) { this.validateParameter(info.maxAz, 0, 360, 'Invalid maximum azimuth - must be between 0 and 360'); this.validateParameter(info.minAz, 0, 360, 'Invalid maximum azimuth - must be between 0 and 360'); this.validateParameter(info.maxEl, -15, 180, 'Invalid maximum elevation - must be between 0 and 180'); @@ -174,7 +217,11 @@ export class Sensor extends GroundObject { this.validateParameter(info.minRng, 0, null, 'Invalid minimum range - must be greater than 0'); } - private validateFov2(info: SensorParams) { + /** + * Validates the field of view parameters for the sensor. + * @param info - The sensor parameters. + */ + private validateFov2_(info: SensorParams) { this.validateParameter(info.maxAz2, 0, 360, 'Invalid maximum azimuth2 - must be between 0 and 360'); this.validateParameter(info.minAz2, 0, 360, 'Invalid maximum azimuth2 - must be between 0 and 360'); this.validateParameter(info.maxEl2, -15, 180, 'Invalid maximum elevation2 - must be between 0 and 180'); @@ -183,26 +230,25 @@ export class Sensor extends GroundObject { this.validateParameter(info.minRng2, 0, null, 'Invalid minimum range2 - must be greater than 0'); } - private validateInputData(info: SensorParams) { - this.validateLla(info); - this.validateFov(info); + /** + * Validates the input data for the sensor. + * @param info - The sensor parameters. + */ + private validateSensorInputData_(info: SensorParams) { + this.validateLla_(info); + this.validateFov_(info); if (info.minAz2 || info.maxAz2 || info.minEl2 || info.maxEl2 || info.minRng2 || info.maxRng2) { - this.validateFov2(info); + this.validateFov2_(info); } } - private validateLla(info: SensorParams) { + /** + * Validates the latitude, longitude, and altitude of a sensor. + * @param info - The sensor parameters containing the latitude, longitude, and altitude. + */ + private validateLla_(info: SensorParams) { this.validateParameter(info.lat, -90, 90, 'Invalid latitude - must be between -90 and 90'); this.validateParameter(info.lon, -180, 180, 'Invalid longitude - must be between -180 and 180'); this.validateParameter(info.alt, 0, null, 'Invalid altitude - must be greater than 0'); } - - private validateParameter(value: T, minValue: T, maxValue: T, errorMessage: string): void { - if (typeof minValue !== 'undefined' && minValue !== null && (value as number) < (minValue as number)) { - throw new Error(errorMessage); - } - if (typeof maxValue !== 'undefined' && maxValue !== null && (value as number) > (maxValue as number)) { - throw new Error(errorMessage); - } - } } diff --git a/src/operations/Vector3D.ts b/src/operations/Vector3D.ts index 3484860..cd8f4d1 100644 --- a/src/operations/Vector3D.ts +++ b/src/operations/Vector3D.ts @@ -1,4 +1,4 @@ -import { Radians, linearDistance } from '../main'; +import { Kilometers, Radians, linearDistance } from '../main'; import { Matrix } from './Matrix'; import { Vector } from './Vector'; @@ -13,8 +13,10 @@ export class Vector3D { } /** - * Create a new [Vector3D] object from the first three elements of a [Vector] + * Create a new Vector3D object from the first three elements of a Vector * object. + * @param v The Vector object to convert. + * @returns A new Vector3D object. */ static fromVector(v: Vector): Vector3D { return new Vector3D(v.x as U, v.y as U, v.z as U); @@ -52,9 +54,10 @@ export class Vector3D { } /** - * Return the [Vector3D] element at the provided [index]. - * - * @deprecated don't do + * Return the Vector3D element at the provided index. + * @deprecated don't do this + * @param index The index of the element to return. + * @returns The element at the provided index. */ public getElement(index: number): number { switch (index) { @@ -104,19 +107,22 @@ export class Vector3D { } // / Return a copy of this [Vector3D] with the elements negated. - negate(): Vector3D { - return this.scale(-1); + negate(): Vector3D { + return this.scale(-1) as Vector3D; } /** - * Return the Euclidean distance between this and another [Vector3D]. + * Return the Euclidean distance between this and another Vector3D. + * @param v The other Vector3D. + * @returns The distance between this and the other Vector3D. */ distance(v: Vector3D): number { return linearDistance(this, v); } /** - * Convert this to a unit [Vector3D]. + * Convert this to a unit Vector3D. + * @returns A unit Vector3D. */ normalize(): Vector3D { const m = this.magnitude(); @@ -179,7 +185,7 @@ export class Vector3D { const cosT = Math.cos(theta); const sinT = Math.sin(theta); - return new Vector3D((cosT * this.x + -sinT * this.z) as T, this.y as T, (sinT * this.x + cosT * this.z) as T); + return new Vector3D((cosT * this.x + -sinT * this.z) as T, this.y, (sinT * this.x + cosT * this.z) as T); } /* diff --git a/test/body/Moon.test.ts b/test/body/Moon.test.ts index 654f155..ac15527 100644 --- a/test/body/Moon.test.ts +++ b/test/body/Moon.test.ts @@ -114,7 +114,7 @@ describe('Moon', () => { * 'rise', 'set', 'ye', 'alwaysUp', 'alwaysDown', and 'highest' properties. */ it("should return an object with 'rise', 'set', 'ye', 'alwaysUp', 'alwaysDown', and 'highest' properties", () => { - const date = new Date(1635724800000); // November 1, 2021 + const date = exampleDate; const lat = 37.7749 as Degrees; // San Francisco latitude const lon = -122.4194 as Degrees; // San Francisco longitude const isUtc = false; @@ -143,7 +143,7 @@ describe('Moon', () => { * 'rise', 'set', 'ye', 'alwaysUp', 'alwaysDown', and 'highest' properties. */ it("should return an object with 'rise', 'set', 'ye', 'alwaysUp', 'alwaysDown', and 'highest' properties", () => { - const date = new Date(exampleDate); // November 1, 2021 + const date = exampleDate; const lat = 37.7749 as Degrees; // San Francisco latitude const lon = -122.4194 as Degrees; // San Francisco longitude const isUtc = false; diff --git a/test/body/Sun.test.ts b/test/body/Sun.test.ts index 90b3f30..c18fc73 100644 --- a/test/body/Sun.test.ts +++ b/test/body/Sun.test.ts @@ -2,7 +2,10 @@ import { Degrees, EpochUTC, Meters, Sun, Vector3D } from '../../src/main'; import { exampleDate } from '../lib/mockData'; describe('Sun', () => { - // The 'azEl' method should return the azimuth and elevation of the sun given a date, latitude, and longitude. + /* + * The 'azEl' method should return the azimuth and elevation of the sun given + * a date, latitude, and longitude. + */ it('should return the azimuth and elevation of the sun given a date, latitude, and longitude', () => { const lat = 37.7749 as Degrees; const lon = -122.4194 as Degrees; @@ -11,7 +14,10 @@ describe('Sun', () => { expect(result).toMatchSnapshot(); }); - // The 'date2jSince2000' method should return the number of days since January 1, 2000, for a given date. + /* + * The 'date2jSince2000' method should return the number of days since January + * 1, 2000, for a given date. + */ it('should return the number of days since January 1, 2000, for a given date', () => { const result = Sun.date2jSince2000(exampleDate); @@ -19,8 +25,8 @@ describe('Sun', () => { }); /* - * The 'diameter' method should return the angular diameter of the sun given the observer's position - * and the sun's position. + * The 'diameter' method should return the angular diameter of the sun given + * the observer's position and the sun's position. */ it('should return the angular diameter of the sun given the observers position and the suns position', () => { const obsPos = new Vector3D(0, 0, 0); @@ -31,8 +37,8 @@ describe('Sun', () => { }); /* - * The 'eclipseAngles' method should return the angles necessary to determine if a satellite is in - * the shadow of the earth. + * The 'eclipseAngles' method should return the angles necessary to determine + * if a satellite is in the shadow of the earth. */ it('should return the angles necessary to determine if a satellite is in the shadow of the earth', () => { const satPos = new Vector3D(0, 0, 0); @@ -42,7 +48,10 @@ describe('Sun', () => { expect(result).toMatchSnapshot(); }); - // The 'eclipticLatitude' method should return the ecliptic latitude of the sun given the solar latitude. + /* + * The 'eclipticLatitude' method should return the ecliptic latitude of the + * sun given the solar latitude. + */ it('should return the ecliptic latitude of the sun given the solar latitude', () => { const B = 23.4397; const result = Sun.eclipticLatitude(B); @@ -50,7 +59,10 @@ describe('Sun', () => { expect(result).toMatchSnapshot(); }); - // The 'eclipticLongitude' method should return the ecliptic longitude of the sun given the solar mean anomaly. + /* + * The 'eclipticLongitude' method should return the ecliptic longitude of the + * sun given the solar mean anomaly. + */ it('should return the ecliptic longitude of the sun given the solar mean anomaly', () => { const M = 0; const result = Sun.eclipticLongitude(M); @@ -66,7 +78,10 @@ describe('Sun', () => { expect(result).toMatchSnapshot(); }); - // The 'diameter' method should handle cases where the observer's position is the same as the sun's position. + /* + * The 'diameter' method should handle cases where the observer's position is + * the same as the sun's position. + */ it('should handle cases where the observers position is the same as the suns position', () => { const obsPos = new Vector3D(1, 1, 1); const sunPos = new Vector3D(1, 1, 1); @@ -75,7 +90,10 @@ describe('Sun', () => { expect(result).toMatchSnapshot(); }); - // The 'eclipseAngles' method should handle cases where the satellite is directly above or below the earth. + /* + * The 'eclipseAngles' method should handle cases where the satellite is + * directly above or below the earth. + */ it('should handle cases where the satellite is directly above or below the earth', () => { const satPos = new Vector3D(0, 0, 0); const sunPos = new Vector3D(0, 0, 1); @@ -84,7 +102,10 @@ describe('Sun', () => { expect(result).toMatchSnapshot(); }); - // The 'eclipticLatitude' method should handle extreme values of solar latitude. + /* + * The 'eclipticLatitude' method should handle extreme values of solar + * latitude. + */ it('should handle extreme values of solar latitude', () => { const B = 90; const result = Sun.eclipticLatitude(B); @@ -92,7 +113,10 @@ describe('Sun', () => { expect(result).toMatchSnapshot(); }); - // The 'eclipticLongitude' method should handle extreme values of solar mean anomaly. + /* + * The 'eclipticLongitude' method should handle extreme values of solar mean + * anomaly. + */ it('should handle extreme values of solar mean anomaly', () => { const M = 360; const result = Sun.eclipticLongitude(M); @@ -100,19 +124,9 @@ describe('Sun', () => { expect(result).toMatchSnapshot(); }); - // The 'getSolarTime' method should return the solar time for a given date, UTC offset, and longitude. - it('should return the solar time for a given date, UTC offset, and longitude', () => { - const utcOffset = -5; - const lon = -75 as Degrees; - - const result = Sun.getSolarTime(exampleDate, utcOffset, lon); - - expect(result).toMatchSnapshot(); - }); - /* - * The 'getSetJulian' method should return the Julian date of the sunrise, sunset, or other solar event - * given the observer's position, date, and time. + * The 'getSetJulian' method should return the Julian date of the sunrise, + * sunset, or other solar event given the observer's position, date, and time. */ it('should return the Julian date of the sunrise when the observers position, date, and time are provided', () => { // Mock input values @@ -127,7 +141,10 @@ describe('Sun', () => { expect(result).toMatchSnapshot(); }); - // The 'getSunTimeByAz' method should return the date and time of the sun's position given a specific azimuth. + /* + * The 'getSunTimeByAz' method should return the date and time of the sun's + * position given a specific azimuth. + */ it('should return the date and time of the suns position given a specific azimuth', () => { const lat = 37.7749 as Degrees; const lon = -122.4194 as Degrees; @@ -138,8 +155,8 @@ describe('Sun', () => { }); /* - * The 'getTimes' method should return the sunrise, sunset, and other solar event times for a given - * date, latitude, and longitude. + * The 'getTimes' method should return the sunrise, sunset, and other solar + * event times for a given date, latitude, and longitude. */ it('should return the sunrise, sunset, and other event times when given a date, latitude, and longitude', () => { // Mock input values diff --git a/test/body/__snapshots__/Moon.test.ts.snap b/test/body/__snapshots__/Moon.test.ts.snap index bbbc13e..89204d7 100644 --- a/test/body/__snapshots__/Moon.test.ts.snap +++ b/test/body/__snapshots__/Moon.test.ts.snap @@ -81,9 +81,9 @@ exports[`Moon should return an object with 'rise', 'set', 'ye', 'alwaysUp', 'alw Object { "alwaysDown": false, "alwaysUp": false, - "highest": 2021-10-31T16:31:15.245Z, - "rise": 2021-10-31T09:42:19.184Z, - "set": 2021-10-31T23:20:11.307Z, + "highest": 2024-01-12T21:42:31.618Z, + "rise": 2024-01-12T16:43:59.167Z, + "set": 2024-01-13T02:41:04.069Z, "ye": null, } `; diff --git a/test/body/__snapshots__/Sun.test.ts.snap b/test/body/__snapshots__/Sun.test.ts.snap index f57771c..889f88d 100644 --- a/test/body/__snapshots__/Sun.test.ts.snap +++ b/test/body/__snapshots__/Sun.test.ts.snap @@ -59,8 +59,6 @@ exports[`Sun should return the same shadow result given the same time and positi exports[`Sun should return the same sunlight result given the same positions 1`] = `1`; -exports[`Sun should return the solar time for a given date, UTC offset, and longitude 1`] = `2024-01-13T01:20:30.888Z`; - exports[`Sun should return the sunrise, sunset, and other event times when given a date, latitude, and longitude 1`] = ` Object { "amateurDawn": 2024-01-12T14:08:48.295Z, diff --git a/test/objects/__snapshots__/sun-moon.test.ts.snap b/test/objects/__snapshots__/sun-moon.test.ts.snap index 84345ae..dce3ed8 100644 --- a/test/objects/__snapshots__/sun-moon.test.ts.snap +++ b/test/objects/__snapshots__/sun-moon.test.ts.snap @@ -132,5 +132,3 @@ Object { "el": 0.5021704545690489, } `; - -exports[`Tests from Hypnos3 getSolarTime returns the solar time 1`] = `"Mon, 04 Mar 2013 17:03:20 GMT"`; diff --git a/test/objects/sun-moon.test.ts b/test/objects/sun-moon.test.ts index d97887f..13a608f 100644 --- a/test/objects/sun-moon.test.ts +++ b/test/objects/sun-moon.test.ts @@ -18,16 +18,6 @@ describe('Sun and Moon', () => { Sun.azEl(dateObj, 0 as Degrees, 0 as Degrees); }); - test('Local Solar Time', () => { - /* - * Use number of milliseconds since epoch instead of local year, month, day, - * etc for consistency across machines - */ - const lst = Sun.getSolarTime(new Date(1658807880000), -5, -71 as Degrees); - - expect(lst.toUTCString()).toEqual('Tue, 26 Jul 2022 04:07:49 GMT'); - }); - test('Moon Unit Tests', () => { expect(Moon.getMoonIllumination(dateObj)).toMatchSnapshot(); @@ -218,10 +208,4 @@ describe('Tests from Hypnos3', () => { expect(times[i].toUTCString()).toEqual(new Date(testTimes[key]).toUTCString()); } }); - - test('getSolarTime returns the solar time', () => { - const solarTime = Sun.getSolarTime(date, -5, -71 as Degrees); - - expect(solarTime.toUTCString()).toMatchSnapshot(); - }); });