astronomia
Version:
An astronomical library
243 lines (227 loc) • 8.22 kB
JavaScript
/**
* @copyright 2013 Sonia Keys
* @copyright 2016 commenthol
* @license MIT
* @module coord
*/
/**
* Coord: Chapter 13, Transformation of Coordinates.
*
* Transforms in this package are provided in two forms, function and method.
* The results of the two forms should be identical.
*
* The function forms pass all arguments and results as single values. These
* forms are best used when you are transforming a single pair of coordinates
* and wish to avoid memory allocation.
*
* The method forms take and return pointers to structs. These forms are best
* used when you are transforming multiple coordinates and can reuse one or
* more of the structs. In this case reuse of structs will minimize
* allocations, and the struct pointers will pass more efficiently on the
* stack. These methods transform their arguments, placing the result in
* the receiver. The receiver is then returned for convenience.
*
* A number of the functions take sine and cosine of the obliquity of the
* ecliptic. This becomes an advantage when you doing multiple transformations
* with the same obliquity. The efficiency of computing sine and cosine once
* and reuse these values far outweighs the overhead of passing one number as
* opposed to two.
*/
import base from './base.js'
import sexa from './sexagesimal.js'
import { Coord as GlobeCoord } from './globe.js' // eslint-disable-line no-unused-vars
/**
* @typedef {object} LonLat
* @property {Number} lon - Longitude (λ) in radians
* @property {Number} lat - Latitude (β) in radians
*/
/**
* Ecliptic coordinates are referenced to the plane of the ecliptic.
*/
export class Ecliptic {
/**
* IMPORTANT: Longitudes are measured *positively* westwards
* e.g. Washington D.C. +77°04; Vienna -16°23'
* @param {Number|LonLat} [lon] - Longitude (λ) in radians
* @param {Number} [lat] - Latitude (β) in radians
*/
constructor (lon, lat) {
if (typeof lon === 'object') {
lat = lon.lat
lon = lon.lon
}
this.lon = lon || 0
this.lat = lat || 0
}
/**
* converts ecliptic coordinates to equatorial coordinates.
* @param {Number} ε - Obliquity
* @returns {Equatorial}
*/
toEquatorial (ε) {
const [εsin, εcos] = base.sincos(ε)
const [sβ, cβ] = base.sincos(this.lat)
const [sλ, cλ] = base.sincos(this.lon)
let ra = Math.atan2(sλ * εcos - (sβ / cβ) * εsin, cλ) // (13.3) p. 93
if (ra < 0) {
ra += 2 * Math.PI
}
const dec = Math.asin(sβ * εcos + cβ * εsin * sλ) // (13.4) p. 93
return new Equatorial(ra, dec)
}
}
/**
* Equatorial coordinates are referenced to the Earth's rotational axis.
*/
export class Equatorial {
/**
* @param {Number} ra - (float) Right ascension (α) in radians
* @param {Number} dec - (float) Declination (δ) in radians
*/
constructor (ra = 0, dec = 0) {
this.ra = ra
this.dec = dec
}
/**
* EqToEcl converts equatorial coordinates to ecliptic coordinates.
* @param {Number} ε - Obliquity
* @returns {Ecliptic}
*/
toEcliptic (ε) {
const [εsin, εcos] = base.sincos(ε)
const [sα, cα] = base.sincos(this.ra)
const [sδ, cδ] = base.sincos(this.dec)
const lon = Math.atan2(sα * εcos + (sδ / cδ) * εsin, cα) // (13.1) p. 93
const lat = Math.asin(sδ * εcos - cδ * εsin * sα) // (13.2) p. 93
return new Ecliptic(lon, lat)
}
/**
* EqToHz computes Horizontal coordinates from equatorial coordinates.
*
* Argument g is the location of the observer on the Earth. Argument st
* is the sidereal time at Greenwich.
*
* Sidereal time must be consistent with the equatorial coordinates.
* If coordinates are apparent, sidereal time must be apparent as well.
*
* @param {GlobeCoord} g - coordinates of observer on Earth
* @param {Number} st - sidereal time at Greenwich at time of observation
* @returns {Horizontal}
*/
toHorizontal (g, st) {
const H = new sexa.Time(st).rad() - g.lon - this.ra
const [sH, cH] = base.sincos(H)
const [sφ, cφ] = base.sincos(g.lat)
const [sδ, cδ] = base.sincos(this.dec)
const azimuth = Math.atan2(sH, cH * sφ - (sδ / cδ) * cφ) // (13.5) p. 93
const altitude = Math.asin(sφ * sδ + cφ * cδ * cH) // (13.6) p. 93
return new Horizontal(azimuth, altitude)
}
/**
* EqToGal converts equatorial coordinates to galactic coordinates.
*
* Equatorial coordinates must be referred to the standard equinox of B1950.0.
* For conversion to B1950, see package precess and utility functions in
* package "common".
*
* @returns {Galactic}
*/
toGalactic () {
const [sdα, cdα] = base.sincos(galacticNorth1950.ra - this.ra)
const [sgδ, cgδ] = base.sincos(galacticNorth1950.dec)
const [sδ, cδ] = base.sincos(this.dec)
const x = Math.atan2(sdα, cdα * sgδ - (sδ / cδ) * cgδ) // (13.7) p. 94
// (galactic0Lon1950 + 1.5*math.Pi) = magic number of 303 deg
const lon = (galactic0Lon1950 + 1.5 * Math.PI - x) % (2 * Math.PI) // (13.8) p. 94
const lat = Math.asin(sδ * sgδ + cδ * cgδ * cdα)
return new Galactic(lon, lat)
}
}
/**
* Horizontal coordinates are referenced to the local horizon of an observer
* on the surface of the Earth.
* @param {Number} az - Azimuth (A) in radians
* @param {Number} alt - Altitude (h) in radians
*/
export class Horizontal {
constructor (az = 0, alt = 0) {
this.az = az
this.alt = alt
}
/**
* transforms horizontal coordinates to equatorial coordinates.
*
* Sidereal time must be consistent with the equatorial coordinates.
* If coordinates are apparent, sidereal time must be apparent as well.
* @param {GlobeCoord} g - coordinates of observer on Earth (lat, lon)
* @param {Number} st - sidereal time at Greenwich at time of observation.
* @returns {Equatorial} (right ascension, declination)
*/
toEquatorial (g, st) {
const [sA, cA] = base.sincos(this.az)
const [sh, ch] = base.sincos(this.alt)
const [sφ, cφ] = base.sincos(g.lat)
const H = Math.atan2(sA, cA * sφ + sh / ch * cφ)
const ra = base.pmod(new sexa.Time(st).rad() - g.lon - H, 2 * Math.PI)
const dec = Math.asin(sφ * sh - cφ * ch * cA)
return new Equatorial(ra, dec)
}
}
/**
* Galactic coordinates are referenced to the plane of the Milky Way.
* @param {Number} lon - Longitude (l) in radians
* @param {Number} lat - Latitude (b) in radians
*/
export class Galactic {
constructor (lon = 0, lat = 0) {
this.lon = lon
this.lat = lat
}
/**
* GalToEq converts galactic coordinates to equatorial coordinates.
*
* Resulting equatorial coordinates will be referred to the standard equinox of
* B1950.0. For subsequent conversion to other epochs, see package precess and
* utility functions in package meeus.
*
* @returns {Equatorial} (right ascension, declination)
*/
toEquatorial () {
// (-galactic0Lon1950 - math.Pi/2) = magic number of -123 deg
const [sdLon, cdLon] = base.sincos(this.lon - galactic0Lon1950 - Math.PI / 2)
const [sgδ, cgδ] = base.sincos(galacticNorth1950.dec)
const [sb, cb] = base.sincos(this.lat)
const y = Math.atan2(sdLon, cdLon * sgδ - (sb / cb) * cgδ)
// (galacticNorth1950.RA.Rad() - math.Pi) = magic number of 12.25 deg
const ra = base.pmod(y + galacticNorth1950.ra - Math.PI, 2 * Math.PI)
const dec = Math.asin(sb * sgδ + cb * cgδ * cdLon)
return new Equatorial(ra, dec)
}
}
/**
* equatorial coords for galactic north
* IAU B1950.0 coordinates of galactic North Pole
*/
export const galacticNorth = new Equatorial(
new sexa.RA(12, 49, 0).rad(),
27.4 * Math.PI / 180
)
export const galacticNorth1950 = galacticNorth
/**
* Galactic Longitude 0°
* Meeus gives 33 as the origin of galactic longitudes relative to the
* ascending node of of the galactic equator. 33 + 90 = 123, the IAU
* value for origin relative to the equatorial pole.
*/
export const galacticLon0 = 33 * Math.PI / 180
export const galactic0Lon1950 = galacticLon0
export default {
Ecliptic,
Equatorial,
Horizontal,
Galactic,
galacticNorth,
galacticNorth1950,
galacticLon0,
galactic0Lon1950
}