From 942f204784419bd78fd3a4e803040df4ab79bd8c Mon Sep 17 00:00:00 2001 From: Theodore Kruczek Date: Mon, 15 Jan 2024 22:42:39 -0500 Subject: [PATCH] refactor: :label: improve type support for radec observations --- src/observation/ObservationUtils.ts | 25 +++--- src/observation/RadecGeocentric.ts | 36 +++++---- src/observation/RadecTopocentric.ts | 77 +++++++++++-------- src/types/types.ts | 5 ++ .../RadecTopocentric.test.ts.snap | 4 +- 5 files changed, 82 insertions(+), 65 deletions(-) diff --git a/src/observation/ObservationUtils.ts b/src/observation/ObservationUtils.ts index 8896e04..30a284c 100644 --- a/src/observation/ObservationUtils.ts +++ b/src/observation/ObservationUtils.ts @@ -21,33 +21,34 @@ * SOFTWARE. */ +import { Kilometers, KilometersPerSecond, Radians, RadiansPerSecond } from '../main'; import { Vector3D } from '../operations/Vector3D'; -export const radecToPosition = (ra: number, dec: number, r: number): Vector3D => { +export const radecToPosition = (ra: Radians, dec: Radians, r: Kilometers): Vector3D => { const ca = Math.cos(ra); const sa = Math.sin(ra); const cd = Math.cos(dec); const sd = Math.sin(dec); - return new Vector3D(r * cd * ca, r * cd * sa, r * sd); + return new Vector3D(r * cd * ca as Kilometers, r * cd * sa as Kilometers, r * sd as Kilometers); }; export const radecToVelocity = ( - ra: number, - dec: number, - r: number, - raDot: number, - decDot: number, - rDot: number, -): Vector3D => { + ra: Radians, + dec: Radians, + r: Kilometers, + raDot: RadiansPerSecond, + decDot: RadiansPerSecond, + rDot: KilometersPerSecond, +): Vector3D => { const ca = Math.cos(ra); const sa = Math.sin(ra); const cd = Math.cos(dec); const sd = Math.sin(dec); return new Vector3D( - rDot * cd * ca - r * sd * ca * decDot - r * cd * sa * raDot, - rDot * cd * sa - r * sd * sa * decDot + r * cd * ca * raDot, - rDot * sd + r * cd * decDot, + rDot * cd * ca - r * sd * ca * decDot - r * cd * sa * raDot as KilometersPerSecond, + rDot * cd * sa - r * sd * sa * decDot + r * cd * ca * raDot as KilometersPerSecond, + rDot * sd + r * cd * decDot as KilometersPerSecond, ); }; diff --git a/src/observation/RadecGeocentric.ts b/src/observation/RadecGeocentric.ts index 5724e66..12e6cfd 100644 --- a/src/observation/RadecGeocentric.ts +++ b/src/observation/RadecGeocentric.ts @@ -22,7 +22,7 @@ */ /* eslint-disable no-undefined */ -import { Degrees, Kilometers, Radians } from 'src/main'; +import { Degrees, Kilometers, KilometersPerSecond, Radians, RadiansPerSecond } from 'src/main'; import { J2000 } from '../coordinate/J2000'; import { AngularDistanceMethod } from '../enums/AngularDistanceMethod'; import { Vector3D } from '../operations/Vector3D'; @@ -39,9 +39,9 @@ export class RadecGeocentric { public rightAscension: Radians, public declination: Radians, public range?: Kilometers, - public rightAscensionRate?: Radians, - public declinationRate?: Radians, - public rangeRate?: number, + public rightAscensionRate?: RadiansPerSecond, + public declinationRate?: RadiansPerSecond, + public rangeRate?: KilometersPerSecond, ) { // Nothing to do here. } @@ -65,18 +65,20 @@ export class RadecGeocentric { range?: Kilometers, rightAscensionRateDegrees?: Degrees, declinationRateDegrees?: Degrees, - rangeRate?: number, + rangeRate?: KilometersPerSecond, ): RadecGeocentric { - const rightAscensionRate = rightAscensionRateDegrees && rightAscensionRateDegrees * DEG2RAD; - const declinationRate = declinationRateDegrees && declinationRateDegrees * DEG2RAD; + const rightAscensionRate = rightAscensionRateDegrees + ? rightAscensionRateDegrees * DEG2RAD as RadiansPerSecond + : undefined; + const declinationRate = declinationRateDegrees ? declinationRateDegrees * DEG2RAD as RadiansPerSecond : undefined; return new RadecGeocentric( epoch, rightAscensionDegrees * DEG2RAD as Radians, declinationDegrees * DEG2RAD as Radians, range, - rightAscensionRate as Radians, - declinationRate as Radians, + rightAscensionRate, + declinationRate, rangeRate, ); } @@ -99,7 +101,7 @@ export class RadecGeocentric { } else { rightAscension = Math.atan2(vJ, vI); } - const rangeRate = state.position.dot(state.velocity) / rMag; + const rangeRate = state.position.dot(state.velocity) / rMag as KilometersPerSecond; const rightAscensionRate = (vI * rJ - vJ * rI) / (-(rJ * rJ) - rI * rI); const declinationRate = (vK - rangeRate * (rK / rMag)) / rIJMag; @@ -108,8 +110,8 @@ export class RadecGeocentric { rightAscension % TAU as Radians, declination as Radians, rMag, - rightAscensionRate as Radians, - declinationRate as Radians, + rightAscensionRate as RadiansPerSecond, + declinationRate as RadiansPerSecond, rangeRate, ); } @@ -142,8 +144,8 @@ export class RadecGeocentric { * @param range Range _(km)_. * @returns A [Vector3D] object. */ - position(range?: number): Vector3D { - const r = range ?? this.range ?? 1.0; + position(range?: Kilometers): Vector3D { + const r = range ?? this.range ?? 1.0 as Kilometers; return radecToPosition(this.rightAscension, this.declination, r); } @@ -157,12 +159,12 @@ export class RadecGeocentric { * @param rangeRate Range rate _(km/s)_. * @returns A [Vector3D] object. */ - velocity(range?: number, rangeRate?: number): Vector3D { + velocity(range?: Kilometers, rangeRate?: KilometersPerSecond): Vector3D { if (!this.rightAscensionRate || !this.declinationRate) { throw new Error('Velocity unsolvable, missing ra/dec rates.'); } - const r = range ?? this.range ?? 1.0; - const rd = rangeRate ?? this.rangeRate ?? 0.0; + const r = range ?? this.range ?? 1.0 as Kilometers; + const rd = rangeRate ?? this.rangeRate ?? 0.0 as KilometersPerSecond; return radecToVelocity(this.rightAscension, this.declination, r, this.rightAscensionRate, this.declinationRate, rd); } diff --git a/src/observation/RadecTopocentric.ts b/src/observation/RadecTopocentric.ts index 53b1804..50d66f5 100644 --- a/src/observation/RadecTopocentric.ts +++ b/src/observation/RadecTopocentric.ts @@ -22,6 +22,7 @@ */ /* eslint-disable no-undefined */ +import { Degrees, DegreesPerSecond, Kilometers, KilometersPerSecond, Radians, RadiansPerSecond } from 'src/main'; import { J2000 } from '../coordinate/J2000'; import { AngularDistanceMethod } from '../enums/AngularDistanceMethod'; import { Vector3D } from '../operations/Vector3D'; @@ -35,12 +36,12 @@ export class RadecTopocentric { // / Create a new [RadecTopocentric] object. constructor( public epoch: EpochUTC, - public rightAscension: number, - public declination: number, - public range?: number, - public rightAscensionRate?: number, - public declinationRate?: number, - public rangeRate?: number, + public rightAscension: Radians, + public declination: Radians, + public range?: Kilometers, + public rightAscensionRate?: RadiansPerSecond, + public declinationRate?: RadiansPerSecond, + public rangeRate?: KilometersPerSecond, ) { // Nothing to do here. } @@ -59,20 +60,24 @@ export class RadecTopocentric { */ static fromDegrees( epoch: EpochUTC, - rightAscensionDegrees: number, - declinationDegrees: number, - range?: number, - rightAscensionRateDegrees?: number, - declinationRateDegrees?: number, - rangeRate?: number, + rightAscensionDegrees: Degrees, + declinationDegrees: Degrees, + range?: Kilometers, + rightAscensionRateDegrees?: DegreesPerSecond, + declinationRateDegrees?: DegreesPerSecond, + rangeRate?: KilometersPerSecond, ): RadecTopocentric { - const rightAscensionRate = rightAscensionRateDegrees ? rightAscensionRateDegrees * DEG2RAD : undefined; - const declinationRate = declinationRateDegrees ? declinationRateDegrees * DEG2RAD : undefined; + const rightAscensionRate = rightAscensionRateDegrees + ? rightAscensionRateDegrees * DEG2RAD as RadiansPerSecond + : undefined; + const declinationRate = declinationRateDegrees + ? declinationRateDegrees * DEG2RAD as RadiansPerSecond + : undefined; return new RadecTopocentric( epoch, - rightAscensionDegrees * DEG2RAD, - declinationDegrees * DEG2RAD, + rightAscensionDegrees * DEG2RAD as Radians, + declinationDegrees * DEG2RAD as Radians, range, rightAscensionRate, declinationRate, @@ -112,33 +117,37 @@ export class RadecTopocentric { return new RadecTopocentric( state.epoch, - rightAscension % TAU, - declination, + rightAscension % TAU as Radians, + declination as Radians, pMag, - rightAscensionRate, - declinationRate, - rangeRate, + rightAscensionRate as RadiansPerSecond, + declinationRate as RadiansPerSecond, + rangeRate as KilometersPerSecond, ); } // / Right-ascension _(°)_. - get rightAscensionDegrees(): number { - return this.rightAscension * RAD2DEG; + get rightAscensionDegrees(): Degrees { + return this.rightAscension * RAD2DEG as Degrees; } // / Declination _(°)_. - get declinationDegrees(): number { - return this.declination * RAD2DEG; + get declinationDegrees(): Degrees { + return this.declination * RAD2DEG as Degrees; } // / Right-ascension rate _(°/s)_. - get rightAscensionRateDegrees(): number | undefined { - return this.rightAscensionRate ? this.rightAscensionRate * RAD2DEG : undefined; + get rightAscensionRateDegrees(): DegreesPerSecond | null { + return this.rightAscensionRate + ? this.rightAscensionRate * RAD2DEG as DegreesPerSecond + : null; } // / Declination rate _(°/s)_. - get declinationRateDegrees(): number | undefined { - return this.declinationRate ? this.declinationRate * RAD2DEG : undefined; + get declinationRateDegrees(): DegreesPerSecond | null { + return this.declinationRate + ? this.declinationRate * RAD2DEG as DegreesPerSecond + : null; } /** @@ -150,8 +159,8 @@ export class RadecTopocentric { * @param range Range _(km)_. * @returns A [Vector3D] object. */ - position(site: J2000, range?: number): Vector3D { - const r = range ?? this.range ?? 1.0; + position(site: J2000, range?: Kilometers): Vector3D { + const r = range ?? this.range ?? 1.0 as Kilometers; return radecToPosition(this.rightAscension, this.declination, r).add(site.position); } @@ -166,12 +175,12 @@ export class RadecTopocentric { * @param rangeRate Range rate _(km/s)_. * @returns A [Vector3D] object. */ - velocity(site: J2000, range?: number, rangeRate?: number): Vector3D { + velocity(site: J2000, range?: Kilometers, rangeRate?: KilometersPerSecond): Vector3D { if (!this.rightAscensionRate || !this.declinationRate) { throw new Error('Velocity unsolvable, missing ra/dec rates.'); } - const r = range ?? this.range ?? 1.0; - const rd = rangeRate ?? this.rangeRate ?? 0.0; + const r = range ?? this.range ?? 1.0 as Kilometers; + const rd = rangeRate ?? this.rangeRate ?? 0.0 as KilometersPerSecond; return radecToVelocity( this.rightAscension, diff --git a/src/types/types.ts b/src/types/types.ts index 070786a..9e05398 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -103,6 +103,11 @@ export type KilometersPerSecond = Distinct; */ export type RadiansPerSecond = Distinct; +/** + * Represents a value in degrees per second. + */ +export type DegreesPerSecond = Distinct; + /** * Represents a value in meters per second. */ diff --git a/test/observation/__snapshots__/RadecTopocentric.test.ts.snap b/test/observation/__snapshots__/RadecTopocentric.test.ts.snap index e48b58f..2d647f7 100644 --- a/test/observation/__snapshots__/RadecTopocentric.test.ts.snap +++ b/test/observation/__snapshots__/RadecTopocentric.test.ts.snap @@ -48,7 +48,7 @@ exports[`RadecTopocentric should return the angle in degrees 1`] = `0.9999999999 exports[`RadecTopocentric should return the declination in degrees 1`] = `0`; -exports[`RadecTopocentric should return the declination rate in degrees 1`] = `undefined`; +exports[`RadecTopocentric should return the declination rate in degrees 1`] = `null`; exports[`RadecTopocentric should return the position 1`] = ` Vector3D { @@ -60,7 +60,7 @@ Vector3D { exports[`RadecTopocentric should return the right ascension in degrees 1`] = `25`; -exports[`RadecTopocentric should return the right ascension rate in degrees 1`] = `undefined`; +exports[`RadecTopocentric should return the right ascension rate in degrees 1`] = `null`; exports[`RadecTopocentric should return the velocity 1`] = ` Vector3D {