From 96609b3e37364ca73a0ef879a5707d2e5cdbebc9 Mon Sep 17 00:00:00 2001 From: "Michael J. Roberts" <84131395+michealroberts@users.noreply.github.com> Date: Sun, 27 Aug 2023 14:17:19 +0100 Subject: [PATCH] feat: Added isBodyCircumpolar() to transit module in @observerly/astrometry. feat: Added isBodyCircumpolar() to transit module in @observerly/astrometry. Includes associated test suite and expected API output. --- src/transit.ts | 37 ++++++++++++- tests/transit.spec.ts | 120 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 tests/transit.spec.ts diff --git a/src/transit.ts b/src/transit.ts index 2cd04b4..008315b 100644 --- a/src/transit.ts +++ b/src/transit.ts @@ -1,11 +1,44 @@ /*****************************************************************************************************************/ // @author Michael Roberts -// @package @observerly/astrometry/transits +// @package @observerly/astrometry/transit // @license Copyright © 2021-2023 observerly /*****************************************************************************************************************/ -export {} +import { type EquatorialCoordinate, type GeographicCoordinate } from './common' + +/*****************************************************************************************************************/ + +/** + * + * isBodyCircumpolar() + * + * An object is considered circumpolar if it is always above the observer's horizon + * and never sets. This is true when the object's declination is greater than 90 + * degrees minus the observer's latitude. + * + * @param observer - The geographic coordinate of the observer. + * @param target - The equatorial coordinate of the observed object. + * @param horizon - The observer's horizon (in degrees). + * @returns a boolean indicating whether the target is circumpolar. + */ +export const isBodyCircumpolar = ( + observer: GeographicCoordinate, + target: EquatorialCoordinate, + horizon: number = 0 +): boolean => { + // We only need to consider the latitude of the observer: + const { latitude } = observer + + // We only need to consider the declination of the target object: + const { dec } = target + + const extrema = 90 - Math.abs(latitude) - horizon + + // If the object's declination is greater than 90 degrees minus the observer's latitude, + // then the object is circumpolar (always above the observer's horizon and never sets). + return latitude >= 0 ? dec > extrema : dec < extrema +} /*****************************************************************************************************************/ diff --git a/tests/transit.spec.ts b/tests/transit.spec.ts new file mode 100644 index 0000000..db3ca29 --- /dev/null +++ b/tests/transit.spec.ts @@ -0,0 +1,120 @@ +/*****************************************************************************************************************/ + +// @author Michael Roberts +// @package @observerly/astrometry/epoch +// @license Copyright © 2021-2023 observerly + +/*****************************************************************************************************************/ + +import { describe, expect, it } from 'vitest' + +/*****************************************************************************************************************/ + +import { type EquatorialCoordinate, isBodyCircumpolar } from '../src' + +/*****************************************************************************************************************/ + +// For testing we need to specify a date because most calculations are +// differential w.r.t a time component. We set it to the author's birthday: +export const datetime = new Date('2021-05-14T00:00:00.000+00:00') + +// For testing we will fix the latitude to be Manua Kea, Hawaii, US +export const latitude = 19.820611 + +// For testing we will fix the longitude to be Manua Kea, Hawaii, US: +export const longitude = -155.468094 + +// For testing +const polaris: EquatorialCoordinate = { ra: 37.95456, dec: 89.264108 } + +// For testing +const betelgeuse: EquatorialCoordinate = { ra: 5.919529, dec: 7.407064 } + +// For testings +const sigmaOctantis: EquatorialCoordinate = { ra: 21.07875, dec: -88.9569444 } + +/*****************************************************************************************************************/ + +describe('isBodyCircumpolar', () => { + it('should be defined', () => { + expect(isBodyCircumpolar).toBeDefined() + }) + + it('should return true for northerm hemisphere circumpolar objects', () => { + expect( + isBodyCircumpolar( + { + latitude, + longitude + }, + polaris, + 0 + ) + ).toBe(true) + }) + + it('should return false for northerm hemisphere non-circumpolar objects', () => { + expect( + isBodyCircumpolar( + { + latitude, + longitude + }, + sigmaOctantis, + 0 + ) + ).toBe(false) + }) + + it('should return true for southern hemisphere circumpolar objects', () => { + expect( + isBodyCircumpolar( + { + latitude: -latitude, + longitude + }, + sigmaOctantis, + 0 + ) + ).toBe(true) + }) + + it('should return false for southern hemisphere non-circumpolar objects', () => { + expect( + isBodyCircumpolar( + { + latitude: -latitude, + longitude + }, + polaris, + 0 + ) + ).toBe(false) + }) + + it('should return false for an object that does set below the horizon', () => { + expect( + isBodyCircumpolar( + { + latitude, + longitude + }, + betelgeuse, + 0 + ) + ).toBe(false) + }) + + it('should return true for an object that does not set below the horizon', () => { + expect( + isBodyCircumpolar( + { + latitude: -latitude, + longitude + }, + betelgeuse, + 0 + ) + ).toBe(true) + }) +})