galactic
Version:
Celestial coordinate conversions and utilities
154 lines (129 loc) • 4.84 kB
text/coffeescript
import './dates' as Dates
# Utilities
atan = Math.atan2
acos = Math.acos
asin = Math.asin
tan = Math.tan
cos = Math.cos
sin = Math.sin
radians = (deg) ->
deg/180*Math.PI
# Constants
radsPerHour = radians(360/24)
Coord =
EARTH:
obliquity: radians(23.439)
utcToLocalSidereal: (observer) ->
# Note: + longitude (vs -) means longitude specified in IAU standard (http://en.wikipedia.org/wiki/Celestial_coordinate_system#Notes_on_conversion)
Dates.julianDateToGMST(Dates.unixDateToJulian(observer.utc)) * radsPerHour + observer.longitude
hourAngleToRightAscension: (hourAngle, localSidereal) ->
localSidereal - hourAngle
rightAscensionToHourAngle: (rightAscension, localSidereal) ->
localSidereal - rightAscension
#
# Coordinate System Transformations:
#
#
# Ecliptic to Equatorial
# In: longitude, latitude
# Out: declication, right ascension, (obliquity used in calculation is also given)
#
eclipticToEquatorial: (coord) ->
latitude = coord.latitude
longitude = coord.longitude
obliquity = coord.obliquity || Coord.EARTH.obliquity
{
declination: asin( sin(latitude)*cos(obliquity) + cos(latitude)*sin(obliquity)*sin(longitude) )
rightAscension: atan( sin(longitude)*cos(obliquity) - tan(latitude)*sin(obliquity), cos(longitude) )
}
#
# Equatorial to Ecliptic
# In:
# - declination
# - rightAscension or hour angle
#
# If hour angle is provided instead of right ascension, an observer with either of the following properties is required:
# - local sidereal time, or
# - longitude & utc time
#
# Out:
# - latitude
# - longitude
#
equatorialToEcliptic: (coord, observer={}) ->
declination = coord.declination
rightAscension = coord.rightAscension
obliquity = coord.obliquity || Coord.EARTH.obliquity
unless rightAscension?
# Calculate right ascension from hour angle + observer if necessary
observer.localSidereal ?= Coord.utcToLocalSidereal(observer)
rightAscension = Coord.hourAngleToRightAscension(coord.hourAngle, observer.localSidereal)
{
latitude: asin( sin(declination)*cos(obliquity) - cos(declination)*sin(obliquity)*sin(rightAscension) )
longitude: atan( sin(rightAscension)*cos(obliquity) + tan(declination)*sin(obliquity), cos(rightAscension) )
}
#
# Converts an equatorial coordinate to horizontal coordinate given an observer's location on the planet
# In:
# - Coordinate:
# - declination
# - rightAscension or hour angle
# - Observer:
# - latitude
# - longitude
# - utc time of observation or local sidereal time
#
# Observer's longitude and utc time can be subsituted by local sidereal time. Furthermore, if the coordinate's
# hour angle is provided instead of right ascension, only the observer's latitude is needed
#
equatorialToHorizontal: (coord, observer) ->
# Required
declination = coord.declination
# Either hourAngle
# or rightAscension plus localSidereal/longitude+time are needed
hourAngle = coord.hourAngle
rightAscension = coord.rightAscension
# Observer
latitude = observer.latitude
localSidereal = observer.localSidereal
unless hourAngle?
localSidereal ?= Coord.utcToLocalSidereal(observer)
hourAngle = Coord.rightAscensionToHourAngle(rightAscension, localSidereal)
# Rotate azimuth by 180 deg (equations return result measured from due south)
{
altitude: asin( sin(latitude)*sin(declination) + cos(latitude)*cos(declination)*cos(hourAngle) )
azimuth: Math.PI + atan( sin(hourAngle), cos(hourAngle)*sin(latitude) - tan(declination)*cos(latitude) )
}
#
# Converts horiztonal coordinates into equatorial given the location of the observer for which the horizontal
# coordinates apply
#
# In:
# - Coordinate:
# - Altitude
# - Azimuth
# - Observer
# - latitude
# - longitude
# - utc time of observation
#
# Observer's longitude and utc time can be subsituted by local sidereal time.
#
horizontalToEquatorial: (coord, observer) ->
# Required
altitude = coord.altitude
# Rotate azimuth by 180 deg (equations expect it measured from due south)
azimuth = coord.azimuth - Math.PI
# Observer
latitude = observer.latitude
# Local Sidereal or longitude+utc are required
localSidereal = observer.localSidereal
utc = observer.utc
localSidereal ?= Coord.utcToLocalSidereal(observer)
hourAngle = atan( sin(azimuth), cos(azimuth)*sin(latitude) + tan(altitude)*cos(latitude) )
{
declination: asin( sin(latitude)*sin(altitude) - cos(latitude)*cos(altitude)*cos(azimuth) )
hourAngle: hourAngle
rightAscension: hourAngleToRightAscension(hourAngle, localSidereal)
}
export = Coord